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