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 #endif 169 }; 170 171 u32 rpi_board_rev = 0; 172 173 int dram_init(void) 174 { 175 ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16); 176 int ret; 177 178 BCM2835_MBOX_INIT_HDR(msg); 179 BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 180 181 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 182 if (ret) { 183 printf("bcm2835: Could not query ARM memory size\n"); 184 return -1; 185 } 186 187 gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 188 189 return 0; 190 } 191 192 static void set_fdtfile(void) 193 { 194 const char *fdtfile; 195 196 if (getenv("fdtfile")) 197 return; 198 199 fdtfile = models[rpi_board_rev].fdtfile; 200 setenv("fdtfile", fdtfile); 201 } 202 203 static void set_usbethaddr(void) 204 { 205 ALLOC_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1, 16); 206 int ret; 207 208 if (!models[rpi_board_rev].has_onboard_eth) 209 return; 210 211 if (getenv("usbethaddr")) 212 return; 213 214 BCM2835_MBOX_INIT_HDR(msg); 215 BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 216 217 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 218 if (ret) { 219 printf("bcm2835: Could not query MAC address\n"); 220 /* Ignore error; not critical */ 221 return; 222 } 223 224 eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 225 226 return; 227 } 228 229 int misc_init_r(void) 230 { 231 set_fdtfile(); 232 set_usbethaddr(); 233 return 0; 234 } 235 236 static int power_on_module(u32 module) 237 { 238 ALLOC_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1, 16); 239 int ret; 240 241 BCM2835_MBOX_INIT_HDR(msg_pwr); 242 BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state, 243 SET_POWER_STATE); 244 msg_pwr->set_power_state.body.req.device_id = module; 245 msg_pwr->set_power_state.body.req.state = 246 BCM2835_MBOX_SET_POWER_STATE_REQ_ON | 247 BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT; 248 249 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, 250 &msg_pwr->hdr); 251 if (ret) { 252 printf("bcm2835: Could not set module %u power state\n", 253 module); 254 return -1; 255 } 256 257 return 0; 258 } 259 260 static void get_board_rev(void) 261 { 262 ALLOC_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1, 16); 263 int ret; 264 const char *name; 265 266 BCM2835_MBOX_INIT_HDR(msg); 267 BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 268 269 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 270 if (ret) { 271 printf("bcm2835: Could not query board revision\n"); 272 /* Ignore error; not critical */ 273 return; 274 } 275 276 /* 277 * For details of old-vs-new scheme, see: 278 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py 279 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282 280 * (a few posts down) 281 */ 282 rpi_board_rev = msg->get_board_rev.body.resp.rev; 283 if (rpi_board_rev & 0x800000) 284 rpi_board_rev = (rpi_board_rev >> 4) & 0xff; 285 if (rpi_board_rev >= ARRAY_SIZE(models)) { 286 printf("RPI: Board rev %u outside known range\n", 287 rpi_board_rev); 288 rpi_board_rev = 0; 289 } 290 if (!models[rpi_board_rev].name) { 291 printf("RPI: Board rev %u unknown\n", rpi_board_rev); 292 rpi_board_rev = 0; 293 } 294 295 name = models[rpi_board_rev].name; 296 printf("RPI %s\n", name); 297 } 298 299 int board_init(void) 300 { 301 get_board_rev(); 302 303 gd->bd->bi_boot_params = 0x100; 304 305 return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 306 } 307 308 int board_mmc_init(bd_t *bis) 309 { 310 ALLOC_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1, 16); 311 int ret; 312 313 power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI); 314 315 BCM2835_MBOX_INIT_HDR(msg_clk); 316 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); 317 msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; 318 319 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); 320 if (ret) { 321 printf("bcm2835: Could not query eMMC clock rate\n"); 322 return -1; 323 } 324 325 return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, 326 msg_clk->get_clock_rate.body.resp.rate_hz); 327 } 328 329 int ft_board_setup(void *blob, bd_t *bd) 330 { 331 /* 332 * For now, we simply always add the simplefb DT node. Later, we 333 * should be more intelligent, and e.g. only do this if no enabled DT 334 * node exists for the "real" graphics driver. 335 */ 336 lcd_dt_simplefb_add_node(blob); 337 338 return 0; 339 } 340