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