1 /* 2 * (C) Copyright 2012-2013,2015 Stephen Warren 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <common.h> 8 #include <config.h> 9 #include <dm.h> 10 #include <fdt_support.h> 11 #include <fdt_simplefb.h> 12 #include <lcd.h> 13 #include <memalign.h> 14 #include <mmc.h> 15 #include <asm/gpio.h> 16 #include <asm/arch/mbox.h> 17 #include <asm/arch/sdhci.h> 18 #include <asm/global_data.h> 19 #include <dm/platform_data/serial_pl01x.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 static const struct bcm2835_gpio_platdata gpio_platdata = { 24 .base = BCM2835_GPIO_BASE, 25 }; 26 27 U_BOOT_DEVICE(bcm2835_gpios) = { 28 .name = "gpio_bcm2835", 29 .platdata = &gpio_platdata, 30 }; 31 32 static const struct pl01x_serial_platdata serial_platdata = { 33 #ifdef CONFIG_BCM2836 34 .base = 0x3f201000, 35 #else 36 .base = 0x20201000, 37 #endif 38 .type = TYPE_PL011, 39 .clock = 3000000, 40 }; 41 42 U_BOOT_DEVICE(bcm2835_serials) = { 43 .name = "serial_pl01x", 44 .platdata = &serial_platdata, 45 }; 46 47 struct msg_get_arm_mem { 48 struct bcm2835_mbox_hdr hdr; 49 struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; 50 u32 end_tag; 51 }; 52 53 struct msg_get_board_rev { 54 struct bcm2835_mbox_hdr hdr; 55 struct bcm2835_mbox_tag_get_board_rev get_board_rev; 56 u32 end_tag; 57 }; 58 59 struct msg_get_mac_address { 60 struct bcm2835_mbox_hdr hdr; 61 struct bcm2835_mbox_tag_get_mac_address get_mac_address; 62 u32 end_tag; 63 }; 64 65 struct msg_set_power_state { 66 struct bcm2835_mbox_hdr hdr; 67 struct bcm2835_mbox_tag_set_power_state set_power_state; 68 u32 end_tag; 69 }; 70 71 struct msg_get_clock_rate { 72 struct bcm2835_mbox_hdr hdr; 73 struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; 74 u32 end_tag; 75 }; 76 77 /* 78 * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/ 79 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733 80 * http://git.drogon.net/?p=wiringPi;a=blob_plain;f=wiringPi/wiringPi.c;hb=5edd177112c99416f68ba3e8c6c4db6ed942e796 81 */ 82 static const struct { 83 const char *name; 84 const char *fdtfile; 85 bool has_onboard_eth; 86 } models[] = { 87 [0] = { 88 "Unknown model", 89 #ifdef CONFIG_BCM2836 90 "bcm2836-rpi-other.dtb", 91 #else 92 "bcm2835-rpi-other.dtb", 93 #endif 94 false, 95 }, 96 #ifdef CONFIG_BCM2836 97 [0x4] = { 98 "2 Model B", 99 "bcm2836-rpi-2-b.dtb", 100 true, 101 }, 102 #else 103 [0x2] = { 104 "Model B (no P5)", 105 "bcm2835-rpi-b-i2c0.dtb", 106 true, 107 }, 108 [0x3] = { 109 "Model B (no P5)", 110 "bcm2835-rpi-b-i2c0.dtb", 111 true, 112 }, 113 [0x4] = { 114 "Model B", 115 "bcm2835-rpi-b.dtb", 116 true, 117 }, 118 [0x5] = { 119 "Model B", 120 "bcm2835-rpi-b.dtb", 121 true, 122 }, 123 [0x6] = { 124 "Model B", 125 "bcm2835-rpi-b.dtb", 126 true, 127 }, 128 [0x7] = { 129 "Model A", 130 "bcm2835-rpi-a.dtb", 131 false, 132 }, 133 [0x8] = { 134 "Model A", 135 "bcm2835-rpi-a.dtb", 136 false, 137 }, 138 [0x9] = { 139 "Model A", 140 "bcm2835-rpi-a.dtb", 141 false, 142 }, 143 [0xd] = { 144 "Model B rev2", 145 "bcm2835-rpi-b-rev2.dtb", 146 true, 147 }, 148 [0xe] = { 149 "Model B rev2", 150 "bcm2835-rpi-b-rev2.dtb", 151 true, 152 }, 153 [0xf] = { 154 "Model B rev2", 155 "bcm2835-rpi-b-rev2.dtb", 156 true, 157 }, 158 [0x10] = { 159 "Model B+", 160 "bcm2835-rpi-b-plus.dtb", 161 true, 162 }, 163 [0x11] = { 164 "Compute Module", 165 "bcm2835-rpi-cm.dtb", 166 false, 167 }, 168 [0x12] = { 169 "Model A+", 170 "bcm2835-rpi-a-plus.dtb", 171 false, 172 }, 173 [0x13] = { 174 "Model B+", 175 "bcm2835-rpi-b-plus.dtb", 176 true, 177 }, 178 [0x14] = { 179 "Compute Module", 180 "bcm2835-rpi-cm.dtb", 181 false, 182 }, 183 [0x15] = { 184 "Model A+", 185 "bcm2835-rpi-a-plus.dtb", 186 false, 187 }, 188 #endif 189 }; 190 191 u32 rpi_board_rev = 0; 192 193 int dram_init(void) 194 { 195 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1); 196 int ret; 197 198 BCM2835_MBOX_INIT_HDR(msg); 199 BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 200 201 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 202 if (ret) { 203 printf("bcm2835: Could not query ARM memory size\n"); 204 return -1; 205 } 206 207 gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 208 209 return 0; 210 } 211 212 static void set_fdtfile(void) 213 { 214 const char *fdtfile; 215 216 if (getenv("fdtfile")) 217 return; 218 219 fdtfile = models[rpi_board_rev].fdtfile; 220 setenv("fdtfile", fdtfile); 221 } 222 223 static void set_usbethaddr(void) 224 { 225 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1); 226 int ret; 227 228 if (!models[rpi_board_rev].has_onboard_eth) 229 return; 230 231 if (getenv("usbethaddr")) 232 return; 233 234 BCM2835_MBOX_INIT_HDR(msg); 235 BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 236 237 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 238 if (ret) { 239 printf("bcm2835: Could not query MAC address\n"); 240 /* Ignore error; not critical */ 241 return; 242 } 243 244 eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 245 246 return; 247 } 248 249 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 250 static void set_board_info(void) 251 { 252 char str_rev[11]; 253 sprintf(str_rev, "0x%X", rpi_board_rev); 254 setenv("board_rev", str_rev); 255 setenv("board_name", models[rpi_board_rev].name); 256 } 257 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */ 258 259 int misc_init_r(void) 260 { 261 set_fdtfile(); 262 set_usbethaddr(); 263 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 264 set_board_info(); 265 #endif 266 return 0; 267 } 268 269 static int power_on_module(u32 module) 270 { 271 ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1); 272 int ret; 273 274 BCM2835_MBOX_INIT_HDR(msg_pwr); 275 BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state, 276 SET_POWER_STATE); 277 msg_pwr->set_power_state.body.req.device_id = module; 278 msg_pwr->set_power_state.body.req.state = 279 BCM2835_MBOX_SET_POWER_STATE_REQ_ON | 280 BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT; 281 282 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, 283 &msg_pwr->hdr); 284 if (ret) { 285 printf("bcm2835: Could not set module %u power state\n", 286 module); 287 return -1; 288 } 289 290 return 0; 291 } 292 293 static void get_board_rev(void) 294 { 295 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1); 296 int ret; 297 const char *name; 298 299 BCM2835_MBOX_INIT_HDR(msg); 300 BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 301 302 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 303 if (ret) { 304 printf("bcm2835: Could not query board revision\n"); 305 /* Ignore error; not critical */ 306 return; 307 } 308 309 /* 310 * For details of old-vs-new scheme, see: 311 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py 312 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282 313 * (a few posts down) 314 * 315 * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the 316 * lower byte to use as the board rev: 317 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250 318 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594 319 */ 320 rpi_board_rev = msg->get_board_rev.body.resp.rev; 321 if (rpi_board_rev & 0x800000) 322 rpi_board_rev = (rpi_board_rev >> 4) & 0xff; 323 else 324 rpi_board_rev &= 0xff; 325 if (rpi_board_rev >= ARRAY_SIZE(models)) { 326 printf("RPI: Board rev %u outside known range\n", 327 rpi_board_rev); 328 rpi_board_rev = 0; 329 } 330 if (!models[rpi_board_rev].name) { 331 printf("RPI: Board rev %u unknown\n", rpi_board_rev); 332 rpi_board_rev = 0; 333 } 334 335 name = models[rpi_board_rev].name; 336 printf("RPI %s\n", name); 337 } 338 339 int board_init(void) 340 { 341 get_board_rev(); 342 343 gd->bd->bi_boot_params = 0x100; 344 345 return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 346 } 347 348 int board_mmc_init(bd_t *bis) 349 { 350 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1); 351 int ret; 352 353 power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI); 354 355 BCM2835_MBOX_INIT_HDR(msg_clk); 356 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); 357 msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; 358 359 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); 360 if (ret) { 361 printf("bcm2835: Could not query eMMC clock rate\n"); 362 return -1; 363 } 364 365 return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, 366 msg_clk->get_clock_rate.body.resp.rate_hz); 367 } 368 369 int ft_board_setup(void *blob, bd_t *bd) 370 { 371 /* 372 * For now, we simply always add the simplefb DT node. Later, we 373 * should be more intelligent, and e.g. only do this if no enabled DT 374 * node exists for the "real" graphics driver. 375 */ 376 lcd_dt_simplefb_add_node(blob); 377 378 return 0; 379 } 380