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