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 }; 147 148 static const struct rpi_model rpi_models_old_scheme[] = { 149 [0x2] = { 150 "Model B", 151 DTB_DIR "bcm2835-rpi-b.dtb", 152 true, 153 }, 154 [0x3] = { 155 "Model B", 156 DTB_DIR "bcm2835-rpi-b.dtb", 157 true, 158 }, 159 [0x4] = { 160 "Model B rev2", 161 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 162 true, 163 }, 164 [0x5] = { 165 "Model B rev2", 166 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 167 true, 168 }, 169 [0x6] = { 170 "Model B rev2", 171 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 172 true, 173 }, 174 [0x7] = { 175 "Model A", 176 DTB_DIR "bcm2835-rpi-a.dtb", 177 false, 178 }, 179 [0x8] = { 180 "Model A", 181 DTB_DIR "bcm2835-rpi-a.dtb", 182 false, 183 }, 184 [0x9] = { 185 "Model A", 186 DTB_DIR "bcm2835-rpi-a.dtb", 187 false, 188 }, 189 [0xd] = { 190 "Model B rev2", 191 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 192 true, 193 }, 194 [0xe] = { 195 "Model B rev2", 196 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 197 true, 198 }, 199 [0xf] = { 200 "Model B rev2", 201 DTB_DIR "bcm2835-rpi-b-rev2.dtb", 202 true, 203 }, 204 [0x10] = { 205 "Model B+", 206 DTB_DIR "bcm2835-rpi-b-plus.dtb", 207 true, 208 }, 209 [0x11] = { 210 "Compute Module", 211 DTB_DIR "bcm2835-rpi-cm.dtb", 212 false, 213 }, 214 [0x12] = { 215 "Model A+", 216 DTB_DIR "bcm2835-rpi-a-plus.dtb", 217 false, 218 }, 219 [0x13] = { 220 "Model B+", 221 DTB_DIR "bcm2835-rpi-b-plus.dtb", 222 true, 223 }, 224 [0x14] = { 225 "Compute Module", 226 DTB_DIR "bcm2835-rpi-cm.dtb", 227 false, 228 }, 229 [0x15] = { 230 "Model A+", 231 DTB_DIR "bcm2835-rpi-a-plus.dtb", 232 false, 233 }, 234 }; 235 236 static uint32_t revision; 237 static uint32_t rev_scheme; 238 static uint32_t rev_type; 239 static const struct rpi_model *model; 240 241 #ifdef CONFIG_ARM64 242 static struct mm_region bcm2837_mem_map[] = { 243 { 244 .virt = 0x00000000UL, 245 .phys = 0x00000000UL, 246 .size = 0x3f000000UL, 247 .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 248 PTE_BLOCK_INNER_SHARE 249 }, { 250 .virt = 0x3f000000UL, 251 .phys = 0x3f000000UL, 252 .size = 0x01000000UL, 253 .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 254 PTE_BLOCK_NON_SHARE | 255 PTE_BLOCK_PXN | PTE_BLOCK_UXN 256 }, { 257 /* List terminator */ 258 0, 259 } 260 }; 261 262 struct mm_region *mem_map = bcm2837_mem_map; 263 #endif 264 265 int dram_init(void) 266 { 267 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1); 268 int ret; 269 270 BCM2835_MBOX_INIT_HDR(msg); 271 BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 272 273 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 274 if (ret) { 275 printf("bcm2835: Could not query ARM memory size\n"); 276 return -1; 277 } 278 279 gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 280 281 return 0; 282 } 283 284 static void set_fdtfile(void) 285 { 286 const char *fdtfile; 287 288 if (env_get("fdtfile")) 289 return; 290 291 fdtfile = model->fdtfile; 292 env_set("fdtfile", fdtfile); 293 } 294 295 /* 296 * If the firmware provided a valid FDT at boot time, let's expose it in 297 * ${fdt_addr} so it may be passed unmodified to the kernel. 298 */ 299 static void set_fdt_addr(void) 300 { 301 if (env_get("fdt_addr")) 302 return; 303 304 if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC) 305 return; 306 307 env_set_hex("fdt_addr", fw_dtb_pointer); 308 } 309 310 /* 311 * Prevent relocation from stomping on a firmware provided FDT blob. 312 */ 313 unsigned long board_get_usable_ram_top(unsigned long total_size) 314 { 315 if ((gd->ram_top - fw_dtb_pointer) > SZ_64M) 316 return gd->ram_top; 317 return fw_dtb_pointer & ~0xffff; 318 } 319 320 static void set_usbethaddr(void) 321 { 322 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1); 323 int ret; 324 325 if (!model->has_onboard_eth) 326 return; 327 328 if (env_get("usbethaddr")) 329 return; 330 331 BCM2835_MBOX_INIT_HDR(msg); 332 BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 333 334 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 335 if (ret) { 336 printf("bcm2835: Could not query MAC address\n"); 337 /* Ignore error; not critical */ 338 return; 339 } 340 341 eth_env_set_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 342 343 if (!env_get("ethaddr")) 344 env_set("ethaddr", env_get("usbethaddr")); 345 346 return; 347 } 348 349 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 350 static void set_board_info(void) 351 { 352 char s[11]; 353 354 snprintf(s, sizeof(s), "0x%X", revision); 355 env_set("board_revision", s); 356 snprintf(s, sizeof(s), "%d", rev_scheme); 357 env_set("board_rev_scheme", s); 358 /* Can't rename this to board_rev_type since it's an ABI for scripts */ 359 snprintf(s, sizeof(s), "0x%X", rev_type); 360 env_set("board_rev", s); 361 env_set("board_name", model->name); 362 } 363 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */ 364 365 static void set_serial_number(void) 366 { 367 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_serial, msg, 1); 368 int ret; 369 char serial_string[17] = { 0 }; 370 371 if (env_get("serial#")) 372 return; 373 374 BCM2835_MBOX_INIT_HDR(msg); 375 BCM2835_MBOX_INIT_TAG_NO_REQ(&msg->get_board_serial, GET_BOARD_SERIAL); 376 377 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 378 if (ret) { 379 printf("bcm2835: Could not query board serial\n"); 380 /* Ignore error; not critical */ 381 return; 382 } 383 384 snprintf(serial_string, sizeof(serial_string), "%016llx", 385 msg->get_board_serial.body.resp.serial); 386 env_set("serial#", serial_string); 387 } 388 389 int misc_init_r(void) 390 { 391 set_fdt_addr(); 392 set_fdtfile(); 393 set_usbethaddr(); 394 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 395 set_board_info(); 396 #endif 397 set_serial_number(); 398 399 return 0; 400 } 401 402 static void get_board_rev(void) 403 { 404 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1); 405 int ret; 406 const struct rpi_model *models; 407 uint32_t models_count; 408 409 BCM2835_MBOX_INIT_HDR(msg); 410 BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 411 412 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 413 if (ret) { 414 printf("bcm2835: Could not query board revision\n"); 415 /* Ignore error; not critical */ 416 return; 417 } 418 419 /* 420 * For details of old-vs-new scheme, see: 421 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py 422 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282 423 * (a few posts down) 424 * 425 * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the 426 * lower byte to use as the board rev: 427 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250 428 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594 429 */ 430 revision = msg->get_board_rev.body.resp.rev; 431 if (revision & 0x800000) { 432 rev_scheme = 1; 433 rev_type = (revision >> 4) & 0xff; 434 models = rpi_models_new_scheme; 435 models_count = ARRAY_SIZE(rpi_models_new_scheme); 436 } else { 437 rev_scheme = 0; 438 rev_type = revision & 0xff; 439 models = rpi_models_old_scheme; 440 models_count = ARRAY_SIZE(rpi_models_old_scheme); 441 } 442 if (rev_type >= models_count) { 443 printf("RPI: Board rev 0x%x outside known range\n", rev_type); 444 model = &rpi_model_unknown; 445 } else if (!models[rev_type].name) { 446 printf("RPI: Board rev 0x%x unknown\n", rev_type); 447 model = &rpi_model_unknown; 448 } else { 449 model = &models[rev_type]; 450 } 451 452 printf("RPI %s (0x%x)\n", model->name, revision); 453 } 454 455 int board_init(void) 456 { 457 #ifdef CONFIG_HW_WATCHDOG 458 hw_watchdog_init(); 459 #endif 460 461 get_board_rev(); 462 463 gd->bd->bi_boot_params = 0x100; 464 465 return bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 466 } 467 468 /* 469 * If the firmware passed a device tree use it for U-Boot. 470 */ 471 void *board_fdt_blob_setup(void) 472 { 473 if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC) 474 return NULL; 475 return (void *)fw_dtb_pointer; 476 } 477 478 int ft_board_setup(void *blob, bd_t *bd) 479 { 480 /* 481 * For now, we simply always add the simplefb DT node. Later, we 482 * should be more intelligent, and e.g. only do this if no enabled DT 483 * node exists for the "real" graphics driver. 484 */ 485 lcd_dt_simplefb_add_node(blob); 486 487 #ifdef CONFIG_EFI_LOADER 488 /* Reserve the spin table */ 489 efi_add_memory_map(0, 1, EFI_RESERVED_MEMORY_TYPE, 0); 490 #endif 491 492 return 0; 493 } 494