19316e144SStephen Warren /* 2f031f501SStephen Warren * (C) Copyright 2012-2016 Stephen Warren 39316e144SStephen Warren * 4a033171bSStephen Warren * SPDX-License-Identifier: GPL-2.0 59316e144SStephen Warren */ 69316e144SStephen Warren 79316e144SStephen Warren #include <common.h> 8757cd149SLubomir Rintel #include <inttypes.h> 99316e144SStephen Warren #include <config.h> 109316e144SStephen Warren #include <dm.h> 111bcf7a30SAlexander Graf #include <efi_loader.h> 129316e144SStephen Warren #include <fdt_support.h> 13033167c4SNikita Kiryanov #include <fdt_simplefb.h> 149316e144SStephen Warren #include <lcd.h> 15cf92e05cSSimon Glass #include <memalign.h> 169316e144SStephen Warren #include <mmc.h> 179316e144SStephen Warren #include <asm/gpio.h> 189316e144SStephen Warren #include <asm/arch/mbox.h> 19*70997d88SSimon Glass #include <asm/arch/msg.h> 209316e144SStephen Warren #include <asm/arch/sdhci.h> 219316e144SStephen Warren #include <asm/global_data.h> 22f031f501SStephen Warren #include <dm/platform_data/serial_bcm283x_mu.h> 23d22a7657SStephen Warren #ifdef CONFIG_ARM64 24d22a7657SStephen Warren #include <asm/armv8/mmu.h> 25d22a7657SStephen Warren #endif 269316e144SStephen Warren 279316e144SStephen Warren DECLARE_GLOBAL_DATA_PTR; 289316e144SStephen Warren 29ade243a2SCédric Schieli /* From lowlevel_init.S */ 30ade243a2SCédric Schieli extern unsigned long fw_dtb_pointer; 31ade243a2SCédric Schieli 3211506666SSimon Glass 339316e144SStephen Warren struct msg_get_arm_mem { 349316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 359316e144SStephen Warren struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; 369316e144SStephen Warren u32 end_tag; 379316e144SStephen Warren }; 389316e144SStephen Warren 399316e144SStephen Warren struct msg_get_board_rev { 409316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 419316e144SStephen Warren struct bcm2835_mbox_tag_get_board_rev get_board_rev; 429316e144SStephen Warren u32 end_tag; 439316e144SStephen Warren }; 449316e144SStephen Warren 45757cd149SLubomir Rintel struct msg_get_board_serial { 46757cd149SLubomir Rintel struct bcm2835_mbox_hdr hdr; 47757cd149SLubomir Rintel struct bcm2835_mbox_tag_get_board_serial get_board_serial; 48757cd149SLubomir Rintel u32 end_tag; 49757cd149SLubomir Rintel }; 50757cd149SLubomir Rintel 519316e144SStephen Warren struct msg_get_mac_address { 529316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 539316e144SStephen Warren struct bcm2835_mbox_tag_get_mac_address get_mac_address; 549316e144SStephen Warren u32 end_tag; 559316e144SStephen Warren }; 569316e144SStephen Warren 579316e144SStephen Warren struct msg_get_clock_rate { 589316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 599316e144SStephen Warren struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; 609316e144SStephen Warren u32 end_tag; 619316e144SStephen Warren }; 629316e144SStephen Warren 635d3c4ba1STuomas Tynkkynen #ifdef CONFIG_ARM64 645d3c4ba1STuomas Tynkkynen #define DTB_DIR "broadcom/" 655d3c4ba1STuomas Tynkkynen #else 665d3c4ba1STuomas Tynkkynen #define DTB_DIR "" 675d3c4ba1STuomas Tynkkynen #endif 685d3c4ba1STuomas Tynkkynen 69dbe6f1ebSStephen Warren /* 70dbe6f1ebSStephen Warren * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/ 71dbe6f1ebSStephen Warren * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733 72c4ea1edbSStephen Warren * http://git.drogon.net/?p=wiringPi;a=blob;f=wiringPi/wiringPi.c;h=503151f61014418b9c42f4476a6086f75cd4e64b;hb=refs/heads/master#l922 73dba060ceSStephen Warren * 74dba060ceSStephen Warren * In http://lists.denx.de/pipermail/u-boot/2016-January/243752.html 75dba060ceSStephen Warren * ("[U-Boot] [PATCH] rpi: fix up Model B entries") Dom Cobley at the RPi 76dba060ceSStephen Warren * Foundation stated that the following source was accurate: 77dba060ceSStephen Warren * https://github.com/AndrewFromMelbourne/raspberry_pi_revision 78dbe6f1ebSStephen Warren */ 79c4ea1edbSStephen Warren struct rpi_model { 809316e144SStephen Warren const char *name; 819316e144SStephen Warren const char *fdtfile; 823207d8fcSStephen Warren bool has_onboard_eth; 83c4ea1edbSStephen Warren }; 84c4ea1edbSStephen Warren 85c4ea1edbSStephen Warren static const struct rpi_model rpi_model_unknown = { 86914627feSStephen Warren "Unknown model", 875d3c4ba1STuomas Tynkkynen DTB_DIR "bcm283x-rpi-other.dtb", 88914627feSStephen Warren false, 89c4ea1edbSStephen Warren }; 90c4ea1edbSStephen Warren 91c4ea1edbSStephen Warren static const struct rpi_model rpi_models_new_scheme[] = { 92dbe6f1ebSStephen Warren [0x4] = { 9346414296SStephen Warren "2 Model B", 945d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2836-rpi-2-b.dtb", 9546414296SStephen Warren true, 9646414296SStephen Warren }, 977233fb31SStephen Warren [0x8] = { 987233fb31SStephen Warren "3 Model B", 995d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2837-rpi-3-b.dtb", 1007233fb31SStephen Warren true, 1017233fb31SStephen Warren }, 102af7c03eaSStephen Warren [0x9] = { 103af7c03eaSStephen Warren "Zero", 1045d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-zero.dtb", 105af7c03eaSStephen Warren false, 106af7c03eaSStephen Warren }, 107c4ea1edbSStephen Warren }; 108c4ea1edbSStephen Warren 109c4ea1edbSStephen Warren static const struct rpi_model rpi_models_old_scheme[] = { 110dbe6f1ebSStephen Warren [0x2] = { 1117443a9c4SLubomir Rintel "Model B", 1125d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b.dtb", 1133207d8fcSStephen Warren true, 1149316e144SStephen Warren }, 115dbe6f1ebSStephen Warren [0x3] = { 1167443a9c4SLubomir Rintel "Model B", 1175d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b.dtb", 1183207d8fcSStephen Warren true, 1199316e144SStephen Warren }, 120dbe6f1ebSStephen Warren [0x4] = { 1217443a9c4SLubomir Rintel "Model B rev2", 1225d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1233207d8fcSStephen Warren true, 1249316e144SStephen Warren }, 125dbe6f1ebSStephen Warren [0x5] = { 1267443a9c4SLubomir Rintel "Model B rev2", 1275d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1283207d8fcSStephen Warren true, 1299316e144SStephen Warren }, 130dbe6f1ebSStephen Warren [0x6] = { 1317443a9c4SLubomir Rintel "Model B rev2", 1325d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1333207d8fcSStephen Warren true, 1349316e144SStephen Warren }, 135dbe6f1ebSStephen Warren [0x7] = { 1369316e144SStephen Warren "Model A", 1375d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-a.dtb", 1383207d8fcSStephen Warren false, 1399316e144SStephen Warren }, 140dbe6f1ebSStephen Warren [0x8] = { 1419316e144SStephen Warren "Model A", 1425d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-a.dtb", 1433207d8fcSStephen Warren false, 1449316e144SStephen Warren }, 145dbe6f1ebSStephen Warren [0x9] = { 1469316e144SStephen Warren "Model A", 1475d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-a.dtb", 1483207d8fcSStephen Warren false, 1499316e144SStephen Warren }, 150dbe6f1ebSStephen Warren [0xd] = { 1519316e144SStephen Warren "Model B rev2", 1525d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1533207d8fcSStephen Warren true, 1549316e144SStephen Warren }, 155dbe6f1ebSStephen Warren [0xe] = { 1569316e144SStephen Warren "Model B rev2", 1575d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1583207d8fcSStephen Warren true, 1599316e144SStephen Warren }, 160dbe6f1ebSStephen Warren [0xf] = { 1619316e144SStephen Warren "Model B rev2", 1625d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-rev2.dtb", 1633207d8fcSStephen Warren true, 1649316e144SStephen Warren }, 165dbe6f1ebSStephen Warren [0x10] = { 1669316e144SStephen Warren "Model B+", 1675d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-plus.dtb", 1683207d8fcSStephen Warren true, 1699316e144SStephen Warren }, 170dbe6f1ebSStephen Warren [0x11] = { 1719316e144SStephen Warren "Compute Module", 1725d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-cm.dtb", 1733207d8fcSStephen Warren false, 1749316e144SStephen Warren }, 175dbe6f1ebSStephen Warren [0x12] = { 17647705effSStephen Warren "Model A+", 1775d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-a-plus.dtb", 17847705effSStephen Warren false, 17947705effSStephen Warren }, 180dbe6f1ebSStephen Warren [0x13] = { 181787affb4SStephen Warren "Model B+", 1825d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-b-plus.dtb", 183787affb4SStephen Warren true, 184787affb4SStephen Warren }, 185dbe6f1ebSStephen Warren [0x14] = { 186787affb4SStephen Warren "Compute Module", 1875d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-cm.dtb", 188787affb4SStephen Warren false, 189787affb4SStephen Warren }, 190dbe6f1ebSStephen Warren [0x15] = { 19179ad5cefSLubomir Rintel "Model A+", 1925d3c4ba1STuomas Tynkkynen DTB_DIR "bcm2835-rpi-a-plus.dtb", 19379ad5cefSLubomir Rintel false, 19479ad5cefSLubomir Rintel }, 1959316e144SStephen Warren }; 1969316e144SStephen Warren 197c4ea1edbSStephen Warren static uint32_t revision; 198c4ea1edbSStephen Warren static uint32_t rev_scheme; 199c4ea1edbSStephen Warren static uint32_t rev_type; 200c4ea1edbSStephen Warren static const struct rpi_model *model; 2019316e144SStephen Warren 202d22a7657SStephen Warren #ifdef CONFIG_ARM64 203d22a7657SStephen Warren static struct mm_region bcm2837_mem_map[] = { 204d22a7657SStephen Warren { 205cd4b0c5fSYork Sun .virt = 0x00000000UL, 206cd4b0c5fSYork Sun .phys = 0x00000000UL, 207d22a7657SStephen Warren .size = 0x3f000000UL, 208d22a7657SStephen Warren .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | 209d22a7657SStephen Warren PTE_BLOCK_INNER_SHARE 210d22a7657SStephen Warren }, { 211cd4b0c5fSYork Sun .virt = 0x3f000000UL, 212cd4b0c5fSYork Sun .phys = 0x3f000000UL, 213d22a7657SStephen Warren .size = 0x01000000UL, 214d22a7657SStephen Warren .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | 215d22a7657SStephen Warren PTE_BLOCK_NON_SHARE | 216d22a7657SStephen Warren PTE_BLOCK_PXN | PTE_BLOCK_UXN 217d22a7657SStephen Warren }, { 218d22a7657SStephen Warren /* List terminator */ 219d22a7657SStephen Warren 0, 220d22a7657SStephen Warren } 221d22a7657SStephen Warren }; 222d22a7657SStephen Warren 223d22a7657SStephen Warren struct mm_region *mem_map = bcm2837_mem_map; 224d22a7657SStephen Warren #endif 225d22a7657SStephen Warren 2269316e144SStephen Warren int dram_init(void) 2279316e144SStephen Warren { 228927753aeSAlexander Stein ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1); 2299316e144SStephen Warren int ret; 2309316e144SStephen Warren 2319316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 2329316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 2339316e144SStephen Warren 2349316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 2359316e144SStephen Warren if (ret) { 2369316e144SStephen Warren printf("bcm2835: Could not query ARM memory size\n"); 2379316e144SStephen Warren return -1; 2389316e144SStephen Warren } 2399316e144SStephen Warren 2409316e144SStephen Warren gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 2419316e144SStephen Warren 2429316e144SStephen Warren return 0; 2439316e144SStephen Warren } 2449316e144SStephen Warren 2459316e144SStephen Warren static void set_fdtfile(void) 2469316e144SStephen Warren { 2479316e144SStephen Warren const char *fdtfile; 2489316e144SStephen Warren 2499316e144SStephen Warren if (getenv("fdtfile")) 2509316e144SStephen Warren return; 2519316e144SStephen Warren 252c4ea1edbSStephen Warren fdtfile = model->fdtfile; 2539316e144SStephen Warren setenv("fdtfile", fdtfile); 2549316e144SStephen Warren } 2559316e144SStephen Warren 256ade243a2SCédric Schieli /* 257ade243a2SCédric Schieli * If the firmware provided a valid FDT at boot time, let's expose it in 258ade243a2SCédric Schieli * ${fdt_addr} so it may be passed unmodified to the kernel. 259ade243a2SCédric Schieli */ 260ade243a2SCédric Schieli static void set_fdt_addr(void) 261ade243a2SCédric Schieli { 262ade243a2SCédric Schieli if (getenv("fdt_addr")) 263ade243a2SCédric Schieli return; 264ade243a2SCédric Schieli 265ade243a2SCédric Schieli if (fdt_magic(fw_dtb_pointer) != FDT_MAGIC) 266ade243a2SCédric Schieli return; 267ade243a2SCédric Schieli 268ade243a2SCédric Schieli setenv_hex("fdt_addr", fw_dtb_pointer); 269ade243a2SCédric Schieli } 270ade243a2SCédric Schieli 271ade243a2SCédric Schieli /* 272ade243a2SCédric Schieli * Prevent relocation from stomping on a firmware provided FDT blob. 273ade243a2SCédric Schieli */ 274ade243a2SCédric Schieli unsigned long board_get_usable_ram_top(unsigned long total_size) 275ade243a2SCédric Schieli { 276ade243a2SCédric Schieli if ((gd->ram_top - fw_dtb_pointer) > SZ_64M) 277ade243a2SCédric Schieli return gd->ram_top; 278ade243a2SCédric Schieli return fw_dtb_pointer & ~0xffff; 279ade243a2SCédric Schieli } 280ade243a2SCédric Schieli 2819316e144SStephen Warren static void set_usbethaddr(void) 2829316e144SStephen Warren { 283927753aeSAlexander Stein ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1); 2849316e144SStephen Warren int ret; 2859316e144SStephen Warren 286c4ea1edbSStephen Warren if (!model->has_onboard_eth) 2873207d8fcSStephen Warren return; 2883207d8fcSStephen Warren 2899316e144SStephen Warren if (getenv("usbethaddr")) 2909316e144SStephen Warren return; 2919316e144SStephen Warren 2929316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 2939316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 2949316e144SStephen Warren 2959316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 2969316e144SStephen Warren if (ret) { 2979316e144SStephen Warren printf("bcm2835: Could not query MAC address\n"); 2989316e144SStephen Warren /* Ignore error; not critical */ 2999316e144SStephen Warren return; 3009316e144SStephen Warren } 3019316e144SStephen Warren 3029316e144SStephen Warren eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 3039316e144SStephen Warren 304859f1437SLubomir Rintel if (!getenv("ethaddr")) 305859f1437SLubomir Rintel setenv("ethaddr", getenv("usbethaddr")); 306859f1437SLubomir Rintel 3079316e144SStephen Warren return; 3089316e144SStephen Warren } 3099316e144SStephen Warren 310bff78567SGuillaume GARDET #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 311bff78567SGuillaume GARDET static void set_board_info(void) 312bff78567SGuillaume GARDET { 313c4ea1edbSStephen Warren char s[11]; 314c4ea1edbSStephen Warren 315c4ea1edbSStephen Warren snprintf(s, sizeof(s), "0x%X", revision); 316c4ea1edbSStephen Warren setenv("board_revision", s); 317c4ea1edbSStephen Warren snprintf(s, sizeof(s), "%d", rev_scheme); 318c4ea1edbSStephen Warren setenv("board_rev_scheme", s); 319c4ea1edbSStephen Warren /* Can't rename this to board_rev_type since it's an ABI for scripts */ 320c4ea1edbSStephen Warren snprintf(s, sizeof(s), "0x%X", rev_type); 321c4ea1edbSStephen Warren setenv("board_rev", s); 322c4ea1edbSStephen Warren setenv("board_name", model->name); 323bff78567SGuillaume GARDET } 324bff78567SGuillaume GARDET #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */ 325bff78567SGuillaume GARDET 326757cd149SLubomir Rintel static void set_serial_number(void) 327757cd149SLubomir Rintel { 328757cd149SLubomir Rintel ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_serial, msg, 1); 329757cd149SLubomir Rintel int ret; 330757cd149SLubomir Rintel char serial_string[17] = { 0 }; 331757cd149SLubomir Rintel 332757cd149SLubomir Rintel if (getenv("serial#")) 333757cd149SLubomir Rintel return; 334757cd149SLubomir Rintel 335757cd149SLubomir Rintel BCM2835_MBOX_INIT_HDR(msg); 336757cd149SLubomir Rintel BCM2835_MBOX_INIT_TAG_NO_REQ(&msg->get_board_serial, GET_BOARD_SERIAL); 337757cd149SLubomir Rintel 338757cd149SLubomir Rintel ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 339757cd149SLubomir Rintel if (ret) { 340757cd149SLubomir Rintel printf("bcm2835: Could not query board serial\n"); 341757cd149SLubomir Rintel /* Ignore error; not critical */ 342757cd149SLubomir Rintel return; 343757cd149SLubomir Rintel } 344757cd149SLubomir Rintel 345757cd149SLubomir Rintel snprintf(serial_string, sizeof(serial_string), "%016" PRIx64, 346757cd149SLubomir Rintel msg->get_board_serial.body.resp.serial); 347757cd149SLubomir Rintel setenv("serial#", serial_string); 348757cd149SLubomir Rintel } 349757cd149SLubomir Rintel 3509316e144SStephen Warren int misc_init_r(void) 3519316e144SStephen Warren { 352ade243a2SCédric Schieli set_fdt_addr(); 3539316e144SStephen Warren set_fdtfile(); 3549316e144SStephen Warren set_usbethaddr(); 355bff78567SGuillaume GARDET #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 356bff78567SGuillaume GARDET set_board_info(); 357bff78567SGuillaume GARDET #endif 358757cd149SLubomir Rintel set_serial_number(); 359757cd149SLubomir Rintel 3609316e144SStephen Warren return 0; 3619316e144SStephen Warren } 3629316e144SStephen Warren 3639316e144SStephen Warren static void get_board_rev(void) 3649316e144SStephen Warren { 365927753aeSAlexander Stein ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1); 3669316e144SStephen Warren int ret; 367c4ea1edbSStephen Warren const struct rpi_model *models; 368c4ea1edbSStephen Warren uint32_t models_count; 3699316e144SStephen Warren 3709316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 3719316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 3729316e144SStephen Warren 3739316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 3749316e144SStephen Warren if (ret) { 3759316e144SStephen Warren printf("bcm2835: Could not query board revision\n"); 3769316e144SStephen Warren /* Ignore error; not critical */ 3779316e144SStephen Warren return; 3789316e144SStephen Warren } 3799316e144SStephen Warren 38046414296SStephen Warren /* 38146414296SStephen Warren * For details of old-vs-new scheme, see: 38246414296SStephen Warren * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py 38346414296SStephen Warren * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282 38446414296SStephen Warren * (a few posts down) 38595b4f112SStephen Warren * 38695b4f112SStephen Warren * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the 38795b4f112SStephen Warren * lower byte to use as the board rev: 38895b4f112SStephen Warren * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250 38995b4f112SStephen Warren * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594 39046414296SStephen Warren */ 391c4ea1edbSStephen Warren revision = msg->get_board_rev.body.resp.rev; 392c4ea1edbSStephen Warren if (revision & 0x800000) { 393c4ea1edbSStephen Warren rev_scheme = 1; 394c4ea1edbSStephen Warren rev_type = (revision >> 4) & 0xff; 395c4ea1edbSStephen Warren models = rpi_models_new_scheme; 396c4ea1edbSStephen Warren models_count = ARRAY_SIZE(rpi_models_new_scheme); 397c4ea1edbSStephen Warren } else { 398c4ea1edbSStephen Warren rev_scheme = 0; 399c4ea1edbSStephen Warren rev_type = revision & 0xff; 400c4ea1edbSStephen Warren models = rpi_models_old_scheme; 401c4ea1edbSStephen Warren models_count = ARRAY_SIZE(rpi_models_old_scheme); 40247705effSStephen Warren } 403c4ea1edbSStephen Warren if (rev_type >= models_count) { 404c4ea1edbSStephen Warren printf("RPI: Board rev 0x%x outside known range\n", rev_type); 405c4ea1edbSStephen Warren model = &rpi_model_unknown; 406c4ea1edbSStephen Warren } else if (!models[rev_type].name) { 407c4ea1edbSStephen Warren printf("RPI: Board rev 0x%x unknown\n", rev_type); 408c4ea1edbSStephen Warren model = &rpi_model_unknown; 409c4ea1edbSStephen Warren } else { 410c4ea1edbSStephen Warren model = &models[rev_type]; 411914627feSStephen Warren } 4129316e144SStephen Warren 413c4ea1edbSStephen Warren printf("RPI %s (0x%x)\n", model->name, revision); 4149316e144SStephen Warren } 4159316e144SStephen Warren 416601147b0SAlexander Graf #ifndef CONFIG_PL01X_SERIAL 417601147b0SAlexander Graf static bool rpi_is_serial_active(void) 418601147b0SAlexander Graf { 419601147b0SAlexander Graf int serial_gpio = 15; 420601147b0SAlexander Graf struct udevice *dev; 421601147b0SAlexander Graf 422601147b0SAlexander Graf /* 423601147b0SAlexander Graf * The RPi3 disables the mini uart by default. The easiest way to find 424601147b0SAlexander Graf * out whether it is available is to check if the RX pin is muxed. 425601147b0SAlexander Graf */ 426601147b0SAlexander Graf 427601147b0SAlexander Graf if (uclass_first_device(UCLASS_GPIO, &dev) || !dev) 428601147b0SAlexander Graf return true; 429601147b0SAlexander Graf 430601147b0SAlexander Graf if (bcm2835_gpio_get_func_id(dev, serial_gpio) != BCM2835_GPIO_ALT5) 431601147b0SAlexander Graf return false; 432601147b0SAlexander Graf 433601147b0SAlexander Graf return true; 434601147b0SAlexander Graf } 435d8396a32SFabian Vogt 436d8396a32SFabian Vogt /* Disable mini-UART I/O if it's not pinmuxed to our pins. 437d8396a32SFabian Vogt * The firmware only enables it if explicitly done in config.txt: enable_uart=1 438d8396a32SFabian Vogt */ 439d8396a32SFabian Vogt static void rpi_disable_inactive_uart(void) 440d8396a32SFabian Vogt { 441d8396a32SFabian Vogt struct udevice *dev; 442d8396a32SFabian Vogt struct bcm283x_mu_serial_platdata *plat; 443d8396a32SFabian Vogt 444d8396a32SFabian Vogt if (uclass_get_device_by_driver(UCLASS_SERIAL, 445d8396a32SFabian Vogt DM_GET_DRIVER(serial_bcm283x_mu), 446d8396a32SFabian Vogt &dev) || !dev) 447d8396a32SFabian Vogt return; 448d8396a32SFabian Vogt 449d8396a32SFabian Vogt if (!rpi_is_serial_active()) { 450d8396a32SFabian Vogt plat = dev_get_platdata(dev); 451d8396a32SFabian Vogt plat->disabled = true; 452d8396a32SFabian Vogt } 453d8396a32SFabian Vogt } 454601147b0SAlexander Graf #endif 455601147b0SAlexander Graf 456d8396a32SFabian Vogt int board_init(void) 457601147b0SAlexander Graf { 458601147b0SAlexander Graf #ifndef CONFIG_PL01X_SERIAL 459d8396a32SFabian Vogt rpi_disable_inactive_uart(); 460601147b0SAlexander Graf #endif 461601147b0SAlexander Graf 462d8396a32SFabian Vogt get_board_rev(); 463d8396a32SFabian Vogt 464d8396a32SFabian Vogt gd->bd->bi_boot_params = 0x100; 465d8396a32SFabian Vogt 466*70997d88SSimon Glass return bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 467601147b0SAlexander Graf } 468601147b0SAlexander Graf 4699316e144SStephen Warren int board_mmc_init(bd_t *bis) 4709316e144SStephen Warren { 471927753aeSAlexander Stein ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1); 4729316e144SStephen Warren int ret; 4739316e144SStephen Warren 474*70997d88SSimon Glass bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI); 4759316e144SStephen Warren 4769316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg_clk); 4779316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); 4789316e144SStephen Warren msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; 4799316e144SStephen Warren 4809316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); 4819316e144SStephen Warren if (ret) { 4829316e144SStephen Warren printf("bcm2835: Could not query eMMC clock rate\n"); 4839316e144SStephen Warren return -1; 4849316e144SStephen Warren } 4859316e144SStephen Warren 4869316e144SStephen Warren return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, 4879316e144SStephen Warren msg_clk->get_clock_rate.body.resp.rate_hz); 4889316e144SStephen Warren } 4899316e144SStephen Warren 4909316e144SStephen Warren int ft_board_setup(void *blob, bd_t *bd) 4919316e144SStephen Warren { 4929316e144SStephen Warren /* 4939316e144SStephen Warren * For now, we simply always add the simplefb DT node. Later, we 4949316e144SStephen Warren * should be more intelligent, and e.g. only do this if no enabled DT 4959316e144SStephen Warren * node exists for the "real" graphics driver. 4969316e144SStephen Warren */ 4979316e144SStephen Warren lcd_dt_simplefb_add_node(blob); 4989316e144SStephen Warren 4991bcf7a30SAlexander Graf #ifdef CONFIG_EFI_LOADER 5001bcf7a30SAlexander Graf /* Reserve the spin table */ 5011bcf7a30SAlexander Graf efi_add_memory_map(0, 1, EFI_RESERVED_MEMORY_TYPE, 0); 5021bcf7a30SAlexander Graf #endif 5031bcf7a30SAlexander Graf 5049316e144SStephen Warren return 0; 5059316e144SStephen Warren } 506