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