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