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