1 /* 2 * (C) Copyright 2012-2013 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 .base = 0x20201000, 33 .type = TYPE_PL011, 34 .clock = 3000000, 35 }; 36 37 U_BOOT_DEVICE(bcm2835_serials) = { 38 .name = "serial_pl01x", 39 .platdata = &serial_platdata, 40 }; 41 42 struct msg_get_arm_mem { 43 struct bcm2835_mbox_hdr hdr; 44 struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; 45 u32 end_tag; 46 }; 47 48 struct msg_get_board_rev { 49 struct bcm2835_mbox_hdr hdr; 50 struct bcm2835_mbox_tag_get_board_rev get_board_rev; 51 u32 end_tag; 52 }; 53 54 struct msg_get_mac_address { 55 struct bcm2835_mbox_hdr hdr; 56 struct bcm2835_mbox_tag_get_mac_address get_mac_address; 57 u32 end_tag; 58 }; 59 60 struct msg_set_power_state { 61 struct bcm2835_mbox_hdr hdr; 62 struct bcm2835_mbox_tag_set_power_state set_power_state; 63 u32 end_tag; 64 }; 65 66 struct msg_get_clock_rate { 67 struct bcm2835_mbox_hdr hdr; 68 struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; 69 u32 end_tag; 70 }; 71 72 /* See comments in mbox.h for data source */ 73 static const struct { 74 const char *name; 75 const char *fdtfile; 76 bool has_onboard_eth; 77 } models[] = { 78 [0] = { 79 "Unknown model", 80 "bcm2835-rpi-other.dtb", 81 false, 82 }, 83 [BCM2835_BOARD_REV_B_I2C0_2] = { 84 "Model B (no P5)", 85 "bcm2835-rpi-b-i2c0.dtb", 86 true, 87 }, 88 [BCM2835_BOARD_REV_B_I2C0_3] = { 89 "Model B (no P5)", 90 "bcm2835-rpi-b-i2c0.dtb", 91 true, 92 }, 93 [BCM2835_BOARD_REV_B_I2C1_4] = { 94 "Model B", 95 "bcm2835-rpi-b.dtb", 96 true, 97 }, 98 [BCM2835_BOARD_REV_B_I2C1_5] = { 99 "Model B", 100 "bcm2835-rpi-b.dtb", 101 true, 102 }, 103 [BCM2835_BOARD_REV_B_I2C1_6] = { 104 "Model B", 105 "bcm2835-rpi-b.dtb", 106 true, 107 }, 108 [BCM2835_BOARD_REV_A_7] = { 109 "Model A", 110 "bcm2835-rpi-a.dtb", 111 false, 112 }, 113 [BCM2835_BOARD_REV_A_8] = { 114 "Model A", 115 "bcm2835-rpi-a.dtb", 116 false, 117 }, 118 [BCM2835_BOARD_REV_A_9] = { 119 "Model A", 120 "bcm2835-rpi-a.dtb", 121 false, 122 }, 123 [BCM2835_BOARD_REV_B_REV2_d] = { 124 "Model B rev2", 125 "bcm2835-rpi-b-rev2.dtb", 126 true, 127 }, 128 [BCM2835_BOARD_REV_B_REV2_e] = { 129 "Model B rev2", 130 "bcm2835-rpi-b-rev2.dtb", 131 true, 132 }, 133 [BCM2835_BOARD_REV_B_REV2_f] = { 134 "Model B rev2", 135 "bcm2835-rpi-b-rev2.dtb", 136 true, 137 }, 138 [BCM2835_BOARD_REV_B_PLUS] = { 139 "Model B+", 140 "bcm2835-rpi-b-plus.dtb", 141 true, 142 }, 143 [BCM2835_BOARD_REV_CM] = { 144 "Compute Module", 145 "bcm2835-rpi-cm.dtb", 146 false, 147 }, 148 [BCM2835_BOARD_REV_A_PLUS] = { 149 "Model A+", 150 "bcm2835-rpi-a-plus.dtb", 151 false, 152 }, 153 }; 154 155 u32 rpi_board_rev = 0; 156 157 int dram_init(void) 158 { 159 ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16); 160 int ret; 161 162 BCM2835_MBOX_INIT_HDR(msg); 163 BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 164 165 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 166 if (ret) { 167 printf("bcm2835: Could not query ARM memory size\n"); 168 return -1; 169 } 170 171 gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 172 173 return 0; 174 } 175 176 static void set_fdtfile(void) 177 { 178 const char *fdtfile; 179 180 if (getenv("fdtfile")) 181 return; 182 183 fdtfile = models[rpi_board_rev].fdtfile; 184 setenv("fdtfile", fdtfile); 185 } 186 187 static void set_usbethaddr(void) 188 { 189 ALLOC_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1, 16); 190 int ret; 191 192 if (!models[rpi_board_rev].has_onboard_eth) 193 return; 194 195 if (getenv("usbethaddr")) 196 return; 197 198 BCM2835_MBOX_INIT_HDR(msg); 199 BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 200 201 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 202 if (ret) { 203 printf("bcm2835: Could not query MAC address\n"); 204 /* Ignore error; not critical */ 205 return; 206 } 207 208 eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 209 210 return; 211 } 212 213 int misc_init_r(void) 214 { 215 set_fdtfile(); 216 set_usbethaddr(); 217 return 0; 218 } 219 220 static int power_on_module(u32 module) 221 { 222 ALLOC_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1, 16); 223 int ret; 224 225 BCM2835_MBOX_INIT_HDR(msg_pwr); 226 BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state, 227 SET_POWER_STATE); 228 msg_pwr->set_power_state.body.req.device_id = module; 229 msg_pwr->set_power_state.body.req.state = 230 BCM2835_MBOX_SET_POWER_STATE_REQ_ON | 231 BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT; 232 233 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, 234 &msg_pwr->hdr); 235 if (ret) { 236 printf("bcm2835: Could not set module %u power state\n", 237 module); 238 return -1; 239 } 240 241 return 0; 242 } 243 244 static void get_board_rev(void) 245 { 246 ALLOC_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1, 16); 247 int ret; 248 const char *name; 249 250 BCM2835_MBOX_INIT_HDR(msg); 251 BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 252 253 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 254 if (ret) { 255 printf("bcm2835: Could not query board revision\n"); 256 /* Ignore error; not critical */ 257 return; 258 } 259 260 rpi_board_rev = msg->get_board_rev.body.resp.rev; 261 if (rpi_board_rev >= ARRAY_SIZE(models)) { 262 printf("RPI: Board rev %u outside known range\n", 263 rpi_board_rev); 264 rpi_board_rev = 0; 265 } 266 if (!models[rpi_board_rev].name) { 267 printf("RPI: Board rev %u unknown\n", rpi_board_rev); 268 rpi_board_rev = 0; 269 } 270 271 name = models[rpi_board_rev].name; 272 printf("RPI model: %s\n", name); 273 } 274 275 int board_init(void) 276 { 277 get_board_rev(); 278 279 gd->bd->bi_boot_params = 0x100; 280 281 return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 282 } 283 284 int board_mmc_init(bd_t *bis) 285 { 286 ALLOC_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1, 16); 287 int ret; 288 289 power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI); 290 291 BCM2835_MBOX_INIT_HDR(msg_clk); 292 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); 293 msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; 294 295 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); 296 if (ret) { 297 printf("bcm2835: Could not query eMMC clock rate\n"); 298 return -1; 299 } 300 301 return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, 302 msg_clk->get_clock_rate.body.resp.rate_hz); 303 } 304 305 int ft_board_setup(void *blob, bd_t *bd) 306 { 307 /* 308 * For now, we simply always add the simplefb DT node. Later, we 309 * should be more intelligent, and e.g. only do this if no enabled DT 310 * node exists for the "real" graphics driver. 311 */ 312 lcd_dt_simplefb_add_node(blob); 313 314 return 0; 315 } 316