]> git.ipfire.org Git - people/ms/u-boot.git/blob - board/raspberrypi/rpi/rpi.c
rpi: BCM2837 and Raspberry Pi 3 32-bit support
[people/ms/u-boot.git] / board / raspberrypi / rpi / rpi.c
1 /*
2 * (C) Copyright 2012-2016 Stephen Warren
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 #include <common.h>
8 #include <inttypes.h>
9 #include <config.h>
10 #include <dm.h>
11 #include <fdt_support.h>
12 #include <fdt_simplefb.h>
13 #include <lcd.h>
14 #include <memalign.h>
15 #include <mmc.h>
16 #include <asm/gpio.h>
17 #include <asm/arch/mbox.h>
18 #include <asm/arch/sdhci.h>
19 #include <asm/global_data.h>
20 #include <dm/platform_data/serial_pl01x.h>
21 #include <dm/platform_data/serial_bcm283x_mu.h>
22
23 DECLARE_GLOBAL_DATA_PTR;
24
25 static const struct bcm2835_gpio_platdata gpio_platdata = {
26 .base = BCM2835_GPIO_BASE,
27 };
28
29 U_BOOT_DEVICE(bcm2835_gpios) = {
30 .name = "gpio_bcm2835",
31 .platdata = &gpio_platdata,
32 };
33
34 #ifdef CONFIG_PL01X_SERIAL
35 static const struct pl01x_serial_platdata serial_platdata = {
36 #ifndef CONFIG_BCM2835
37 .base = 0x3f201000,
38 #else
39 .base = 0x20201000,
40 #endif
41 .type = TYPE_PL011,
42 .skip_init = true,
43 };
44
45 U_BOOT_DEVICE(bcm2835_serials) = {
46 .name = "serial_pl01x",
47 .platdata = &serial_platdata,
48 };
49 #else
50 static const struct bcm283x_mu_serial_platdata serial_platdata = {
51 .base = 0x3f215040,
52 .clock = 250000000,
53 .skip_init = true,
54 };
55
56 U_BOOT_DEVICE(bcm2837_serials) = {
57 .name = "serial_bcm283x_mu",
58 .platdata = &serial_platdata,
59 };
60 #endif
61
62 struct msg_get_arm_mem {
63 struct bcm2835_mbox_hdr hdr;
64 struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
65 u32 end_tag;
66 };
67
68 struct msg_get_board_rev {
69 struct bcm2835_mbox_hdr hdr;
70 struct bcm2835_mbox_tag_get_board_rev get_board_rev;
71 u32 end_tag;
72 };
73
74 struct msg_get_board_serial {
75 struct bcm2835_mbox_hdr hdr;
76 struct bcm2835_mbox_tag_get_board_serial get_board_serial;
77 u32 end_tag;
78 };
79
80 struct msg_get_mac_address {
81 struct bcm2835_mbox_hdr hdr;
82 struct bcm2835_mbox_tag_get_mac_address get_mac_address;
83 u32 end_tag;
84 };
85
86 struct msg_set_power_state {
87 struct bcm2835_mbox_hdr hdr;
88 struct bcm2835_mbox_tag_set_power_state set_power_state;
89 u32 end_tag;
90 };
91
92 struct msg_get_clock_rate {
93 struct bcm2835_mbox_hdr hdr;
94 struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
95 u32 end_tag;
96 };
97
98 /*
99 * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/
100 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733
101 * http://git.drogon.net/?p=wiringPi;a=blob;f=wiringPi/wiringPi.c;h=503151f61014418b9c42f4476a6086f75cd4e64b;hb=refs/heads/master#l922
102 *
103 * In http://lists.denx.de/pipermail/u-boot/2016-January/243752.html
104 * ("[U-Boot] [PATCH] rpi: fix up Model B entries") Dom Cobley at the RPi
105 * Foundation stated that the following source was accurate:
106 * https://github.com/AndrewFromMelbourne/raspberry_pi_revision
107 */
108 struct rpi_model {
109 const char *name;
110 const char *fdtfile;
111 bool has_onboard_eth;
112 };
113
114 static const struct rpi_model rpi_model_unknown = {
115 "Unknown model",
116 "bcm283x-rpi-other.dtb",
117 false,
118 };
119
120 static const struct rpi_model rpi_models_new_scheme[] = {
121 [0x4] = {
122 "2 Model B",
123 "bcm2836-rpi-2-b.dtb",
124 true,
125 },
126 [0x8] = {
127 "3 Model B",
128 "bcm2837-rpi-3-b.dtb",
129 true,
130 },
131 [0x9] = {
132 "Zero",
133 "bcm2835-rpi-zero.dtb",
134 false,
135 },
136 };
137
138 static const struct rpi_model rpi_models_old_scheme[] = {
139 [0x2] = {
140 "Model B",
141 "bcm2835-rpi-b.dtb",
142 true,
143 },
144 [0x3] = {
145 "Model B",
146 "bcm2835-rpi-b.dtb",
147 true,
148 },
149 [0x4] = {
150 "Model B rev2",
151 "bcm2835-rpi-b-rev2.dtb",
152 true,
153 },
154 [0x5] = {
155 "Model B rev2",
156 "bcm2835-rpi-b-rev2.dtb",
157 true,
158 },
159 [0x6] = {
160 "Model B rev2",
161 "bcm2835-rpi-b-rev2.dtb",
162 true,
163 },
164 [0x7] = {
165 "Model A",
166 "bcm2835-rpi-a.dtb",
167 false,
168 },
169 [0x8] = {
170 "Model A",
171 "bcm2835-rpi-a.dtb",
172 false,
173 },
174 [0x9] = {
175 "Model A",
176 "bcm2835-rpi-a.dtb",
177 false,
178 },
179 [0xd] = {
180 "Model B rev2",
181 "bcm2835-rpi-b-rev2.dtb",
182 true,
183 },
184 [0xe] = {
185 "Model B rev2",
186 "bcm2835-rpi-b-rev2.dtb",
187 true,
188 },
189 [0xf] = {
190 "Model B rev2",
191 "bcm2835-rpi-b-rev2.dtb",
192 true,
193 },
194 [0x10] = {
195 "Model B+",
196 "bcm2835-rpi-b-plus.dtb",
197 true,
198 },
199 [0x11] = {
200 "Compute Module",
201 "bcm2835-rpi-cm.dtb",
202 false,
203 },
204 [0x12] = {
205 "Model A+",
206 "bcm2835-rpi-a-plus.dtb",
207 false,
208 },
209 [0x13] = {
210 "Model B+",
211 "bcm2835-rpi-b-plus.dtb",
212 true,
213 },
214 [0x14] = {
215 "Compute Module",
216 "bcm2835-rpi-cm.dtb",
217 false,
218 },
219 [0x15] = {
220 "Model A+",
221 "bcm2835-rpi-a-plus.dtb",
222 false,
223 },
224 };
225
226 static uint32_t revision;
227 static uint32_t rev_scheme;
228 static uint32_t rev_type;
229 static const struct rpi_model *model;
230
231 int dram_init(void)
232 {
233 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1);
234 int ret;
235
236 BCM2835_MBOX_INIT_HDR(msg);
237 BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
238
239 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
240 if (ret) {
241 printf("bcm2835: Could not query ARM memory size\n");
242 return -1;
243 }
244
245 gd->ram_size = msg->get_arm_mem.body.resp.mem_size;
246
247 return 0;
248 }
249
250 static void set_fdtfile(void)
251 {
252 const char *fdtfile;
253
254 if (getenv("fdtfile"))
255 return;
256
257 fdtfile = model->fdtfile;
258 setenv("fdtfile", fdtfile);
259 }
260
261 static void set_usbethaddr(void)
262 {
263 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1);
264 int ret;
265
266 if (!model->has_onboard_eth)
267 return;
268
269 if (getenv("usbethaddr"))
270 return;
271
272 BCM2835_MBOX_INIT_HDR(msg);
273 BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
274
275 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
276 if (ret) {
277 printf("bcm2835: Could not query MAC address\n");
278 /* Ignore error; not critical */
279 return;
280 }
281
282 eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac);
283
284 if (!getenv("ethaddr"))
285 setenv("ethaddr", getenv("usbethaddr"));
286
287 return;
288 }
289
290 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
291 static void set_board_info(void)
292 {
293 char s[11];
294
295 snprintf(s, sizeof(s), "0x%X", revision);
296 setenv("board_revision", s);
297 snprintf(s, sizeof(s), "%d", rev_scheme);
298 setenv("board_rev_scheme", s);
299 /* Can't rename this to board_rev_type since it's an ABI for scripts */
300 snprintf(s, sizeof(s), "0x%X", rev_type);
301 setenv("board_rev", s);
302 setenv("board_name", model->name);
303 }
304 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
305
306 static void set_serial_number(void)
307 {
308 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_serial, msg, 1);
309 int ret;
310 char serial_string[17] = { 0 };
311
312 if (getenv("serial#"))
313 return;
314
315 BCM2835_MBOX_INIT_HDR(msg);
316 BCM2835_MBOX_INIT_TAG_NO_REQ(&msg->get_board_serial, GET_BOARD_SERIAL);
317
318 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
319 if (ret) {
320 printf("bcm2835: Could not query board serial\n");
321 /* Ignore error; not critical */
322 return;
323 }
324
325 snprintf(serial_string, sizeof(serial_string), "%016" PRIx64,
326 msg->get_board_serial.body.resp.serial);
327 setenv("serial#", serial_string);
328 }
329
330 int misc_init_r(void)
331 {
332 set_fdtfile();
333 set_usbethaddr();
334 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
335 set_board_info();
336 #endif
337 set_serial_number();
338
339 return 0;
340 }
341
342 static int power_on_module(u32 module)
343 {
344 ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1);
345 int ret;
346
347 BCM2835_MBOX_INIT_HDR(msg_pwr);
348 BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
349 SET_POWER_STATE);
350 msg_pwr->set_power_state.body.req.device_id = module;
351 msg_pwr->set_power_state.body.req.state =
352 BCM2835_MBOX_SET_POWER_STATE_REQ_ON |
353 BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
354
355 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
356 &msg_pwr->hdr);
357 if (ret) {
358 printf("bcm2835: Could not set module %u power state\n",
359 module);
360 return -1;
361 }
362
363 return 0;
364 }
365
366 static void get_board_rev(void)
367 {
368 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1);
369 int ret;
370 const struct rpi_model *models;
371 uint32_t models_count;
372
373 BCM2835_MBOX_INIT_HDR(msg);
374 BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
375
376 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
377 if (ret) {
378 printf("bcm2835: Could not query board revision\n");
379 /* Ignore error; not critical */
380 return;
381 }
382
383 /*
384 * For details of old-vs-new scheme, see:
385 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py
386 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282
387 * (a few posts down)
388 *
389 * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the
390 * lower byte to use as the board rev:
391 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
392 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
393 */
394 revision = msg->get_board_rev.body.resp.rev;
395 if (revision & 0x800000) {
396 rev_scheme = 1;
397 rev_type = (revision >> 4) & 0xff;
398 models = rpi_models_new_scheme;
399 models_count = ARRAY_SIZE(rpi_models_new_scheme);
400 } else {
401 rev_scheme = 0;
402 rev_type = revision & 0xff;
403 models = rpi_models_old_scheme;
404 models_count = ARRAY_SIZE(rpi_models_old_scheme);
405 }
406 if (rev_type >= models_count) {
407 printf("RPI: Board rev 0x%x outside known range\n", rev_type);
408 model = &rpi_model_unknown;
409 } else if (!models[rev_type].name) {
410 printf("RPI: Board rev 0x%x unknown\n", rev_type);
411 model = &rpi_model_unknown;
412 } else {
413 model = &models[rev_type];
414 }
415
416 printf("RPI %s (0x%x)\n", model->name, revision);
417 }
418
419 int board_init(void)
420 {
421 get_board_rev();
422
423 gd->bd->bi_boot_params = 0x100;
424
425 return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD);
426 }
427
428 int board_mmc_init(bd_t *bis)
429 {
430 ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
431 int ret;
432
433 power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
434
435 BCM2835_MBOX_INIT_HDR(msg_clk);
436 BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE);
437 msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC;
438
439 ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
440 if (ret) {
441 printf("bcm2835: Could not query eMMC clock rate\n");
442 return -1;
443 }
444
445 return bcm2835_sdhci_init(BCM2835_SDHCI_BASE,
446 msg_clk->get_clock_rate.body.resp.rate_hz);
447 }
448
449 int ft_board_setup(void *blob, bd_t *bd)
450 {
451 /*
452 * For now, we simply always add the simplefb DT node. Later, we
453 * should be more intelligent, and e.g. only do this if no enabled DT
454 * node exists for the "real" graphics driver.
455 */
456 lcd_dt_simplefb_add_node(blob);
457
458 return 0;
459 }