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