1*9316e144SStephen Warren /* 2*9316e144SStephen Warren * (C) Copyright 2012-2013 Stephen Warren 3*9316e144SStephen Warren * 4*9316e144SStephen Warren * See file CREDITS for list of people who contributed to this 5*9316e144SStephen Warren * project. 6*9316e144SStephen Warren * 7*9316e144SStephen Warren * This program is free software; you can redistribute it and/or 8*9316e144SStephen Warren * modify it under the terms of the GNU General Public License 9*9316e144SStephen Warren * version 2 as published by the Free Software Foundation. 10*9316e144SStephen Warren * 11*9316e144SStephen Warren * This program is distributed in the hope that it will be useful, but 12*9316e144SStephen Warren * WITHOUT ANY WARRANTY; without even the implied warranty of 13*9316e144SStephen Warren * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*9316e144SStephen Warren * GNU General Public License for more details. 15*9316e144SStephen Warren */ 16*9316e144SStephen Warren 17*9316e144SStephen Warren #include <common.h> 18*9316e144SStephen Warren #include <config.h> 19*9316e144SStephen Warren #include <dm.h> 20*9316e144SStephen Warren #include <fdt_support.h> 21*9316e144SStephen Warren #include <lcd.h> 22*9316e144SStephen Warren #include <mmc.h> 23*9316e144SStephen Warren #include <asm/gpio.h> 24*9316e144SStephen Warren #include <asm/arch/mbox.h> 25*9316e144SStephen Warren #include <asm/arch/sdhci.h> 26*9316e144SStephen Warren #include <asm/global_data.h> 27*9316e144SStephen Warren 28*9316e144SStephen Warren DECLARE_GLOBAL_DATA_PTR; 29*9316e144SStephen Warren 30*9316e144SStephen Warren static const struct bcm2835_gpio_platdata gpio_platdata = { 31*9316e144SStephen Warren .base = BCM2835_GPIO_BASE, 32*9316e144SStephen Warren }; 33*9316e144SStephen Warren 34*9316e144SStephen Warren U_BOOT_DEVICE(bcm2835_gpios) = { 35*9316e144SStephen Warren .name = "gpio_bcm2835", 36*9316e144SStephen Warren .platdata = &gpio_platdata, 37*9316e144SStephen Warren }; 38*9316e144SStephen Warren 39*9316e144SStephen Warren struct msg_get_arm_mem { 40*9316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 41*9316e144SStephen Warren struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; 42*9316e144SStephen Warren u32 end_tag; 43*9316e144SStephen Warren }; 44*9316e144SStephen Warren 45*9316e144SStephen Warren struct msg_get_board_rev { 46*9316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 47*9316e144SStephen Warren struct bcm2835_mbox_tag_get_board_rev get_board_rev; 48*9316e144SStephen Warren u32 end_tag; 49*9316e144SStephen Warren }; 50*9316e144SStephen Warren 51*9316e144SStephen Warren struct msg_get_mac_address { 52*9316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 53*9316e144SStephen Warren struct bcm2835_mbox_tag_get_mac_address get_mac_address; 54*9316e144SStephen Warren u32 end_tag; 55*9316e144SStephen Warren }; 56*9316e144SStephen Warren 57*9316e144SStephen Warren struct msg_set_power_state { 58*9316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 59*9316e144SStephen Warren struct bcm2835_mbox_tag_set_power_state set_power_state; 60*9316e144SStephen Warren u32 end_tag; 61*9316e144SStephen Warren }; 62*9316e144SStephen Warren 63*9316e144SStephen Warren struct msg_get_clock_rate { 64*9316e144SStephen Warren struct bcm2835_mbox_hdr hdr; 65*9316e144SStephen Warren struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; 66*9316e144SStephen Warren u32 end_tag; 67*9316e144SStephen Warren }; 68*9316e144SStephen Warren 69*9316e144SStephen Warren /* See comments in mbox.h for data source */ 70*9316e144SStephen Warren static const struct { 71*9316e144SStephen Warren const char *name; 72*9316e144SStephen Warren const char *fdtfile; 73*9316e144SStephen Warren } models[] = { 74*9316e144SStephen Warren [BCM2835_BOARD_REV_B_I2C0_2] = { 75*9316e144SStephen Warren "Model B (no P5)", 76*9316e144SStephen Warren "bcm2835-rpi-b-i2c0.dtb", 77*9316e144SStephen Warren }, 78*9316e144SStephen Warren [BCM2835_BOARD_REV_B_I2C0_3] = { 79*9316e144SStephen Warren "Model B (no P5)", 80*9316e144SStephen Warren "bcm2835-rpi-b-i2c0.dtb", 81*9316e144SStephen Warren }, 82*9316e144SStephen Warren [BCM2835_BOARD_REV_B_I2C1_4] = { 83*9316e144SStephen Warren "Model B", 84*9316e144SStephen Warren "bcm2835-rpi-b.dtb", 85*9316e144SStephen Warren }, 86*9316e144SStephen Warren [BCM2835_BOARD_REV_B_I2C1_5] = { 87*9316e144SStephen Warren "Model B", 88*9316e144SStephen Warren "bcm2835-rpi-b.dtb", 89*9316e144SStephen Warren }, 90*9316e144SStephen Warren [BCM2835_BOARD_REV_B_I2C1_6] = { 91*9316e144SStephen Warren "Model B", 92*9316e144SStephen Warren "bcm2835-rpi-b.dtb", 93*9316e144SStephen Warren }, 94*9316e144SStephen Warren [BCM2835_BOARD_REV_A_7] = { 95*9316e144SStephen Warren "Model A", 96*9316e144SStephen Warren "bcm2835-rpi-a.dtb", 97*9316e144SStephen Warren }, 98*9316e144SStephen Warren [BCM2835_BOARD_REV_A_8] = { 99*9316e144SStephen Warren "Model A", 100*9316e144SStephen Warren "bcm2835-rpi-a.dtb", 101*9316e144SStephen Warren }, 102*9316e144SStephen Warren [BCM2835_BOARD_REV_A_9] = { 103*9316e144SStephen Warren "Model A", 104*9316e144SStephen Warren "bcm2835-rpi-a.dtb", 105*9316e144SStephen Warren }, 106*9316e144SStephen Warren [BCM2835_BOARD_REV_B_REV2_d] = { 107*9316e144SStephen Warren "Model B rev2", 108*9316e144SStephen Warren "bcm2835-rpi-b-rev2.dtb", 109*9316e144SStephen Warren }, 110*9316e144SStephen Warren [BCM2835_BOARD_REV_B_REV2_e] = { 111*9316e144SStephen Warren "Model B rev2", 112*9316e144SStephen Warren "bcm2835-rpi-b-rev2.dtb", 113*9316e144SStephen Warren }, 114*9316e144SStephen Warren [BCM2835_BOARD_REV_B_REV2_f] = { 115*9316e144SStephen Warren "Model B rev2", 116*9316e144SStephen Warren "bcm2835-rpi-b-rev2.dtb", 117*9316e144SStephen Warren }, 118*9316e144SStephen Warren [BCM2835_BOARD_REV_B_PLUS] = { 119*9316e144SStephen Warren "Model B+", 120*9316e144SStephen Warren "bcm2835-rpi-b-plus.dtb", 121*9316e144SStephen Warren }, 122*9316e144SStephen Warren [BCM2835_BOARD_REV_CM] = { 123*9316e144SStephen Warren "Compute Module", 124*9316e144SStephen Warren "bcm2835-rpi-cm.dtb", 125*9316e144SStephen Warren }, 126*9316e144SStephen Warren }; 127*9316e144SStephen Warren 128*9316e144SStephen Warren u32 rpi_board_rev = 0; 129*9316e144SStephen Warren 130*9316e144SStephen Warren int dram_init(void) 131*9316e144SStephen Warren { 132*9316e144SStephen Warren ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16); 133*9316e144SStephen Warren int ret; 134*9316e144SStephen Warren 135*9316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 136*9316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); 137*9316e144SStephen Warren 138*9316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 139*9316e144SStephen Warren if (ret) { 140*9316e144SStephen Warren printf("bcm2835: Could not query ARM memory size\n"); 141*9316e144SStephen Warren return -1; 142*9316e144SStephen Warren } 143*9316e144SStephen Warren 144*9316e144SStephen Warren gd->ram_size = msg->get_arm_mem.body.resp.mem_size; 145*9316e144SStephen Warren 146*9316e144SStephen Warren return 0; 147*9316e144SStephen Warren } 148*9316e144SStephen Warren 149*9316e144SStephen Warren static void set_fdtfile(void) 150*9316e144SStephen Warren { 151*9316e144SStephen Warren const char *fdtfile; 152*9316e144SStephen Warren 153*9316e144SStephen Warren if (getenv("fdtfile")) 154*9316e144SStephen Warren return; 155*9316e144SStephen Warren 156*9316e144SStephen Warren fdtfile = models[rpi_board_rev].fdtfile; 157*9316e144SStephen Warren if (!fdtfile) 158*9316e144SStephen Warren fdtfile = "bcm2835-rpi-other.dtb"; 159*9316e144SStephen Warren 160*9316e144SStephen Warren setenv("fdtfile", fdtfile); 161*9316e144SStephen Warren } 162*9316e144SStephen Warren 163*9316e144SStephen Warren static void set_usbethaddr(void) 164*9316e144SStephen Warren { 165*9316e144SStephen Warren ALLOC_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1, 16); 166*9316e144SStephen Warren int ret; 167*9316e144SStephen Warren 168*9316e144SStephen Warren if (getenv("usbethaddr")) 169*9316e144SStephen Warren return; 170*9316e144SStephen Warren 171*9316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 172*9316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); 173*9316e144SStephen Warren 174*9316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 175*9316e144SStephen Warren if (ret) { 176*9316e144SStephen Warren printf("bcm2835: Could not query MAC address\n"); 177*9316e144SStephen Warren /* Ignore error; not critical */ 178*9316e144SStephen Warren return; 179*9316e144SStephen Warren } 180*9316e144SStephen Warren 181*9316e144SStephen Warren eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac); 182*9316e144SStephen Warren 183*9316e144SStephen Warren return; 184*9316e144SStephen Warren } 185*9316e144SStephen Warren 186*9316e144SStephen Warren int misc_init_r(void) 187*9316e144SStephen Warren { 188*9316e144SStephen Warren set_fdtfile(); 189*9316e144SStephen Warren set_usbethaddr(); 190*9316e144SStephen Warren return 0; 191*9316e144SStephen Warren } 192*9316e144SStephen Warren 193*9316e144SStephen Warren static int power_on_module(u32 module) 194*9316e144SStephen Warren { 195*9316e144SStephen Warren ALLOC_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1, 16); 196*9316e144SStephen Warren int ret; 197*9316e144SStephen Warren 198*9316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg_pwr); 199*9316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state, 200*9316e144SStephen Warren SET_POWER_STATE); 201*9316e144SStephen Warren msg_pwr->set_power_state.body.req.device_id = module; 202*9316e144SStephen Warren msg_pwr->set_power_state.body.req.state = 203*9316e144SStephen Warren BCM2835_MBOX_SET_POWER_STATE_REQ_ON | 204*9316e144SStephen Warren BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT; 205*9316e144SStephen Warren 206*9316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, 207*9316e144SStephen Warren &msg_pwr->hdr); 208*9316e144SStephen Warren if (ret) { 209*9316e144SStephen Warren printf("bcm2835: Could not set module %u power state\n", 210*9316e144SStephen Warren module); 211*9316e144SStephen Warren return -1; 212*9316e144SStephen Warren } 213*9316e144SStephen Warren 214*9316e144SStephen Warren return 0; 215*9316e144SStephen Warren } 216*9316e144SStephen Warren 217*9316e144SStephen Warren static void get_board_rev(void) 218*9316e144SStephen Warren { 219*9316e144SStephen Warren ALLOC_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1, 16); 220*9316e144SStephen Warren int ret; 221*9316e144SStephen Warren const char *name; 222*9316e144SStephen Warren 223*9316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg); 224*9316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); 225*9316e144SStephen Warren 226*9316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); 227*9316e144SStephen Warren if (ret) { 228*9316e144SStephen Warren printf("bcm2835: Could not query board revision\n"); 229*9316e144SStephen Warren /* Ignore error; not critical */ 230*9316e144SStephen Warren return; 231*9316e144SStephen Warren } 232*9316e144SStephen Warren 233*9316e144SStephen Warren rpi_board_rev = msg->get_board_rev.body.resp.rev; 234*9316e144SStephen Warren if (rpi_board_rev >= ARRAY_SIZE(models)) 235*9316e144SStephen Warren rpi_board_rev = 0; 236*9316e144SStephen Warren 237*9316e144SStephen Warren name = models[rpi_board_rev].name; 238*9316e144SStephen Warren if (!name) 239*9316e144SStephen Warren name = "Unknown model"; 240*9316e144SStephen Warren printf("RPI model: %s\n", name); 241*9316e144SStephen Warren } 242*9316e144SStephen Warren 243*9316e144SStephen Warren int board_init(void) 244*9316e144SStephen Warren { 245*9316e144SStephen Warren get_board_rev(); 246*9316e144SStephen Warren 247*9316e144SStephen Warren gd->bd->bi_boot_params = 0x100; 248*9316e144SStephen Warren 249*9316e144SStephen Warren return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD); 250*9316e144SStephen Warren } 251*9316e144SStephen Warren 252*9316e144SStephen Warren int board_mmc_init(bd_t *bis) 253*9316e144SStephen Warren { 254*9316e144SStephen Warren ALLOC_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1, 16); 255*9316e144SStephen Warren int ret; 256*9316e144SStephen Warren 257*9316e144SStephen Warren power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI); 258*9316e144SStephen Warren 259*9316e144SStephen Warren BCM2835_MBOX_INIT_HDR(msg_clk); 260*9316e144SStephen Warren BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); 261*9316e144SStephen Warren msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; 262*9316e144SStephen Warren 263*9316e144SStephen Warren ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); 264*9316e144SStephen Warren if (ret) { 265*9316e144SStephen Warren printf("bcm2835: Could not query eMMC clock rate\n"); 266*9316e144SStephen Warren return -1; 267*9316e144SStephen Warren } 268*9316e144SStephen Warren 269*9316e144SStephen Warren return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, 270*9316e144SStephen Warren msg_clk->get_clock_rate.body.resp.rate_hz); 271*9316e144SStephen Warren } 272*9316e144SStephen Warren 273*9316e144SStephen Warren int ft_board_setup(void *blob, bd_t *bd) 274*9316e144SStephen Warren { 275*9316e144SStephen Warren /* 276*9316e144SStephen Warren * For now, we simply always add the simplefb DT node. Later, we 277*9316e144SStephen Warren * should be more intelligent, and e.g. only do this if no enabled DT 278*9316e144SStephen Warren * node exists for the "real" graphics driver. 279*9316e144SStephen Warren */ 280*9316e144SStephen Warren lcd_dt_simplefb_add_node(blob); 281*9316e144SStephen Warren 282*9316e144SStephen Warren return 0; 283*9316e144SStephen Warren } 284