xref: /openbmc/u-boot/board/raspberrypi/rpi/rpi.c (revision ad5b5801)
1 /*
2  * (C) Copyright 2012-2016 Stephen Warren
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <inttypes.h>
9 #include <config.h>
10 #include <dm.h>
11 #include <fdt_support.h>
12 #include <fdt_simplefb.h>
13 #include <lcd.h>
14 #include <memalign.h>
15 #include <mmc.h>
16 #include <asm/gpio.h>
17 #include <asm/arch/mbox.h>
18 #include <asm/arch/sdhci.h>
19 #include <asm/global_data.h>
20 #include <dm/platform_data/serial_pl01x.h>
21 #include <dm/platform_data/serial_bcm283x_mu.h>
22 #ifdef CONFIG_ARM64
23 #include <asm/armv8/mmu.h>
24 #endif
25 
26 DECLARE_GLOBAL_DATA_PTR;
27 
28 static const struct bcm2835_gpio_platdata gpio_platdata = {
29 	.base = BCM2835_GPIO_BASE,
30 };
31 
32 U_BOOT_DEVICE(bcm2835_gpios) = {
33 	.name = "gpio_bcm2835",
34 	.platdata = &gpio_platdata,
35 };
36 
37 #ifdef CONFIG_PL01X_SERIAL
38 static const struct pl01x_serial_platdata serial_platdata = {
39 #ifndef CONFIG_BCM2835
40 	.base = 0x3f201000,
41 #else
42 	.base = 0x20201000,
43 #endif
44 	.type = TYPE_PL011,
45 	.skip_init = true,
46 };
47 
48 U_BOOT_DEVICE(bcm2835_serials) = {
49 	.name = "serial_pl01x",
50 	.platdata = &serial_platdata,
51 };
52 #else
53 static const struct bcm283x_mu_serial_platdata serial_platdata = {
54 	.base = 0x3f215040,
55 	.clock = 250000000,
56 	.skip_init = true,
57 };
58 
59 U_BOOT_DEVICE(bcm2837_serials) = {
60 	.name = "serial_bcm283x_mu",
61 	.platdata = &serial_platdata,
62 };
63 #endif
64 
65 struct msg_get_arm_mem {
66 	struct bcm2835_mbox_hdr hdr;
67 	struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
68 	u32 end_tag;
69 };
70 
71 struct msg_get_board_rev {
72 	struct bcm2835_mbox_hdr hdr;
73 	struct bcm2835_mbox_tag_get_board_rev get_board_rev;
74 	u32 end_tag;
75 };
76 
77 struct msg_get_board_serial {
78 	struct bcm2835_mbox_hdr hdr;
79 	struct bcm2835_mbox_tag_get_board_serial get_board_serial;
80 	u32 end_tag;
81 };
82 
83 struct msg_get_mac_address {
84 	struct bcm2835_mbox_hdr hdr;
85 	struct bcm2835_mbox_tag_get_mac_address get_mac_address;
86 	u32 end_tag;
87 };
88 
89 struct msg_set_power_state {
90 	struct bcm2835_mbox_hdr hdr;
91 	struct bcm2835_mbox_tag_set_power_state set_power_state;
92 	u32 end_tag;
93 };
94 
95 struct msg_get_clock_rate {
96 	struct bcm2835_mbox_hdr hdr;
97 	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
98 	u32 end_tag;
99 };
100 
101 /*
102  * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/
103  * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733
104  * http://git.drogon.net/?p=wiringPi;a=blob;f=wiringPi/wiringPi.c;h=503151f61014418b9c42f4476a6086f75cd4e64b;hb=refs/heads/master#l922
105  *
106  * In http://lists.denx.de/pipermail/u-boot/2016-January/243752.html
107  * ("[U-Boot] [PATCH] rpi: fix up Model B entries") Dom Cobley at the RPi
108  * Foundation stated that the following source was accurate:
109  * https://github.com/AndrewFromMelbourne/raspberry_pi_revision
110  */
111 struct rpi_model {
112 	const char *name;
113 	const char *fdtfile;
114 	bool has_onboard_eth;
115 };
116 
117 static const struct rpi_model rpi_model_unknown = {
118 	"Unknown model",
119 	"bcm283x-rpi-other.dtb",
120 	false,
121 };
122 
123 static const struct rpi_model rpi_models_new_scheme[] = {
124 	[0x4] = {
125 		"2 Model B",
126 		"bcm2836-rpi-2-b.dtb",
127 		true,
128 	},
129 	[0x8] = {
130 		"3 Model B",
131 		"bcm2837-rpi-3-b.dtb",
132 		true,
133 	},
134 	[0x9] = {
135 		"Zero",
136 		"bcm2835-rpi-zero.dtb",
137 		false,
138 	},
139 };
140 
141 static const struct rpi_model rpi_models_old_scheme[] = {
142 	[0x2] = {
143 		"Model B",
144 		"bcm2835-rpi-b.dtb",
145 		true,
146 	},
147 	[0x3] = {
148 		"Model B",
149 		"bcm2835-rpi-b.dtb",
150 		true,
151 	},
152 	[0x4] = {
153 		"Model B rev2",
154 		"bcm2835-rpi-b-rev2.dtb",
155 		true,
156 	},
157 	[0x5] = {
158 		"Model B rev2",
159 		"bcm2835-rpi-b-rev2.dtb",
160 		true,
161 	},
162 	[0x6] = {
163 		"Model B rev2",
164 		"bcm2835-rpi-b-rev2.dtb",
165 		true,
166 	},
167 	[0x7] = {
168 		"Model A",
169 		"bcm2835-rpi-a.dtb",
170 		false,
171 	},
172 	[0x8] = {
173 		"Model A",
174 		"bcm2835-rpi-a.dtb",
175 		false,
176 	},
177 	[0x9] = {
178 		"Model A",
179 		"bcm2835-rpi-a.dtb",
180 		false,
181 	},
182 	[0xd] = {
183 		"Model B rev2",
184 		"bcm2835-rpi-b-rev2.dtb",
185 		true,
186 	},
187 	[0xe] = {
188 		"Model B rev2",
189 		"bcm2835-rpi-b-rev2.dtb",
190 		true,
191 	},
192 	[0xf] = {
193 		"Model B rev2",
194 		"bcm2835-rpi-b-rev2.dtb",
195 		true,
196 	},
197 	[0x10] = {
198 		"Model B+",
199 		"bcm2835-rpi-b-plus.dtb",
200 		true,
201 	},
202 	[0x11] = {
203 		"Compute Module",
204 		"bcm2835-rpi-cm.dtb",
205 		false,
206 	},
207 	[0x12] = {
208 		"Model A+",
209 		"bcm2835-rpi-a-plus.dtb",
210 		false,
211 	},
212 	[0x13] = {
213 		"Model B+",
214 		"bcm2835-rpi-b-plus.dtb",
215 		true,
216 	},
217 	[0x14] = {
218 		"Compute Module",
219 		"bcm2835-rpi-cm.dtb",
220 		false,
221 	},
222 	[0x15] = {
223 		"Model A+",
224 		"bcm2835-rpi-a-plus.dtb",
225 		false,
226 	},
227 };
228 
229 static uint32_t revision;
230 static uint32_t rev_scheme;
231 static uint32_t rev_type;
232 static const struct rpi_model *model;
233 
234 #ifdef CONFIG_ARM64
235 static struct mm_region bcm2837_mem_map[] = {
236 	{
237 		.base = 0x00000000UL,
238 		.size = 0x3f000000UL,
239 		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
240 			 PTE_BLOCK_INNER_SHARE
241 	}, {
242 		.base = 0x3f000000UL,
243 		.size = 0x01000000UL,
244 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
245 			 PTE_BLOCK_NON_SHARE |
246 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
247 	}, {
248 		/* List terminator */
249 		0,
250 	}
251 };
252 
253 struct mm_region *mem_map = bcm2837_mem_map;
254 #endif
255 
256 int dram_init(void)
257 {
258 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1);
259 	int ret;
260 
261 	BCM2835_MBOX_INIT_HDR(msg);
262 	BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
263 
264 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
265 	if (ret) {
266 		printf("bcm2835: Could not query ARM memory size\n");
267 		return -1;
268 	}
269 
270 	gd->ram_size = msg->get_arm_mem.body.resp.mem_size;
271 
272 	return 0;
273 }
274 
275 static void set_fdtfile(void)
276 {
277 	const char *fdtfile;
278 
279 	if (getenv("fdtfile"))
280 		return;
281 
282 	fdtfile = model->fdtfile;
283 	setenv("fdtfile", fdtfile);
284 }
285 
286 static void set_usbethaddr(void)
287 {
288 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1);
289 	int ret;
290 
291 	if (!model->has_onboard_eth)
292 		return;
293 
294 	if (getenv("usbethaddr"))
295 		return;
296 
297 	BCM2835_MBOX_INIT_HDR(msg);
298 	BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
299 
300 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
301 	if (ret) {
302 		printf("bcm2835: Could not query MAC address\n");
303 		/* Ignore error; not critical */
304 		return;
305 	}
306 
307 	eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac);
308 
309 	if (!getenv("ethaddr"))
310 		setenv("ethaddr", getenv("usbethaddr"));
311 
312 	return;
313 }
314 
315 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
316 static void set_board_info(void)
317 {
318 	char s[11];
319 
320 	snprintf(s, sizeof(s), "0x%X", revision);
321 	setenv("board_revision", s);
322 	snprintf(s, sizeof(s), "%d", rev_scheme);
323 	setenv("board_rev_scheme", s);
324 	/* Can't rename this to board_rev_type since it's an ABI for scripts */
325 	snprintf(s, sizeof(s), "0x%X", rev_type);
326 	setenv("board_rev", s);
327 	setenv("board_name", model->name);
328 }
329 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
330 
331 static void set_serial_number(void)
332 {
333 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_serial, msg, 1);
334 	int ret;
335 	char serial_string[17] = { 0 };
336 
337 	if (getenv("serial#"))
338 		return;
339 
340 	BCM2835_MBOX_INIT_HDR(msg);
341 	BCM2835_MBOX_INIT_TAG_NO_REQ(&msg->get_board_serial, GET_BOARD_SERIAL);
342 
343 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
344 	if (ret) {
345 		printf("bcm2835: Could not query board serial\n");
346 		/* Ignore error; not critical */
347 		return;
348 	}
349 
350 	snprintf(serial_string, sizeof(serial_string), "%016" PRIx64,
351 		 msg->get_board_serial.body.resp.serial);
352 	setenv("serial#", serial_string);
353 }
354 
355 int misc_init_r(void)
356 {
357 	set_fdtfile();
358 	set_usbethaddr();
359 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
360 	set_board_info();
361 #endif
362 	set_serial_number();
363 
364 	return 0;
365 }
366 
367 static int power_on_module(u32 module)
368 {
369 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1);
370 	int ret;
371 
372 	BCM2835_MBOX_INIT_HDR(msg_pwr);
373 	BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
374 			      SET_POWER_STATE);
375 	msg_pwr->set_power_state.body.req.device_id = module;
376 	msg_pwr->set_power_state.body.req.state =
377 		BCM2835_MBOX_SET_POWER_STATE_REQ_ON |
378 		BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
379 
380 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
381 				     &msg_pwr->hdr);
382 	if (ret) {
383 		printf("bcm2835: Could not set module %u power state\n",
384 		       module);
385 		return -1;
386 	}
387 
388 	return 0;
389 }
390 
391 static void get_board_rev(void)
392 {
393 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1);
394 	int ret;
395 	const struct rpi_model *models;
396 	uint32_t models_count;
397 
398 	BCM2835_MBOX_INIT_HDR(msg);
399 	BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
400 
401 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
402 	if (ret) {
403 		printf("bcm2835: Could not query board revision\n");
404 		/* Ignore error; not critical */
405 		return;
406 	}
407 
408 	/*
409 	 * For details of old-vs-new scheme, see:
410 	 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py
411 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282
412 	 * (a few posts down)
413 	 *
414 	 * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the
415 	 * lower byte to use as the board rev:
416 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
417 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
418 	 */
419 	revision = msg->get_board_rev.body.resp.rev;
420 	if (revision & 0x800000) {
421 		rev_scheme = 1;
422 		rev_type = (revision >> 4) & 0xff;
423 		models = rpi_models_new_scheme;
424 		models_count = ARRAY_SIZE(rpi_models_new_scheme);
425 	} else {
426 		rev_scheme = 0;
427 		rev_type = revision & 0xff;
428 		models = rpi_models_old_scheme;
429 		models_count = ARRAY_SIZE(rpi_models_old_scheme);
430 	}
431 	if (rev_type >= models_count) {
432 		printf("RPI: Board rev 0x%x outside known range\n", rev_type);
433 		model = &rpi_model_unknown;
434 	} else if (!models[rev_type].name) {
435 		printf("RPI: Board rev 0x%x unknown\n", rev_type);
436 		model = &rpi_model_unknown;
437 	} else {
438 		model = &models[rev_type];
439 	}
440 
441 	printf("RPI %s (0x%x)\n", model->name, revision);
442 }
443 
444 int board_init(void)
445 {
446 	get_board_rev();
447 
448 	gd->bd->bi_boot_params = 0x100;
449 
450 	return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD);
451 }
452 
453 int board_mmc_init(bd_t *bis)
454 {
455 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
456 	int ret;
457 
458 	power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
459 
460 	BCM2835_MBOX_INIT_HDR(msg_clk);
461 	BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE);
462 	msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC;
463 
464 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
465 	if (ret) {
466 		printf("bcm2835: Could not query eMMC clock rate\n");
467 		return -1;
468 	}
469 
470 	return bcm2835_sdhci_init(BCM2835_SDHCI_BASE,
471 				  msg_clk->get_clock_rate.body.resp.rate_hz);
472 }
473 
474 int ft_board_setup(void *blob, bd_t *bd)
475 {
476 	/*
477 	 * For now, we simply always add the simplefb DT node. Later, we
478 	 * should be more intelligent, and e.g. only do this if no enabled DT
479 	 * node exists for the "real" graphics driver.
480 	 */
481 	lcd_dt_simplefb_add_node(blob);
482 
483 	return 0;
484 }
485