xref: /rk3399_rockchip-uboot/board/raspberrypi/rpi/rpi.c (revision dbe6f1eb93e14c611865274c53b0be1aa59e7762)
1 /*
2  * (C) Copyright 2012-2013,2015 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 <memalign.h>
14 #include <mmc.h>
15 #include <asm/gpio.h>
16 #include <asm/arch/mbox.h>
17 #include <asm/arch/sdhci.h>
18 #include <asm/global_data.h>
19 #include <dm/platform_data/serial_pl01x.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 static const struct bcm2835_gpio_platdata gpio_platdata = {
24 	.base = BCM2835_GPIO_BASE,
25 };
26 
27 U_BOOT_DEVICE(bcm2835_gpios) = {
28 	.name = "gpio_bcm2835",
29 	.platdata = &gpio_platdata,
30 };
31 
32 static const struct pl01x_serial_platdata serial_platdata = {
33 #ifdef CONFIG_BCM2836
34 	.base = 0x3f201000,
35 #else
36 	.base = 0x20201000,
37 #endif
38 	.type = TYPE_PL011,
39 	.clock = 3000000,
40 };
41 
42 U_BOOT_DEVICE(bcm2835_serials) = {
43 	.name = "serial_pl01x",
44 	.platdata = &serial_platdata,
45 };
46 
47 struct msg_get_arm_mem {
48 	struct bcm2835_mbox_hdr hdr;
49 	struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
50 	u32 end_tag;
51 };
52 
53 struct msg_get_board_rev {
54 	struct bcm2835_mbox_hdr hdr;
55 	struct bcm2835_mbox_tag_get_board_rev get_board_rev;
56 	u32 end_tag;
57 };
58 
59 struct msg_get_mac_address {
60 	struct bcm2835_mbox_hdr hdr;
61 	struct bcm2835_mbox_tag_get_mac_address get_mac_address;
62 	u32 end_tag;
63 };
64 
65 struct msg_set_power_state {
66 	struct bcm2835_mbox_hdr hdr;
67 	struct bcm2835_mbox_tag_set_power_state set_power_state;
68 	u32 end_tag;
69 };
70 
71 struct msg_get_clock_rate {
72 	struct bcm2835_mbox_hdr hdr;
73 	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
74 	u32 end_tag;
75 };
76 
77 /*
78  * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/
79  * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733
80  * http://git.drogon.net/?p=wiringPi;a=blob_plain;f=wiringPi/wiringPi.c;hb=5edd177112c99416f68ba3e8c6c4db6ed942e796
81  */
82 static const struct {
83 	const char *name;
84 	const char *fdtfile;
85 	bool has_onboard_eth;
86 } models[] = {
87 	[0] = {
88 		"Unknown model",
89 #ifdef CONFIG_BCM2836
90 		"bcm2836-rpi-other.dtb",
91 #else
92 		"bcm2835-rpi-other.dtb",
93 #endif
94 		false,
95 	},
96 #ifdef CONFIG_BCM2836
97 	[0x4] = {
98 		"2 Model B",
99 		"bcm2836-rpi-2-b.dtb",
100 		true,
101 	},
102 #else
103 	[0x2] = {
104 		"Model B (no P5)",
105 		"bcm2835-rpi-b-i2c0.dtb",
106 		true,
107 	},
108 	[0x3] = {
109 		"Model B (no P5)",
110 		"bcm2835-rpi-b-i2c0.dtb",
111 		true,
112 	},
113 	[0x4] = {
114 		"Model B",
115 		"bcm2835-rpi-b.dtb",
116 		true,
117 	},
118 	[0x5] = {
119 		"Model B",
120 		"bcm2835-rpi-b.dtb",
121 		true,
122 	},
123 	[0x6] = {
124 		"Model B",
125 		"bcm2835-rpi-b.dtb",
126 		true,
127 	},
128 	[0x7] = {
129 		"Model A",
130 		"bcm2835-rpi-a.dtb",
131 		false,
132 	},
133 	[0x8] = {
134 		"Model A",
135 		"bcm2835-rpi-a.dtb",
136 		false,
137 	},
138 	[0x9] = {
139 		"Model A",
140 		"bcm2835-rpi-a.dtb",
141 		false,
142 	},
143 	[0xd] = {
144 		"Model B rev2",
145 		"bcm2835-rpi-b-rev2.dtb",
146 		true,
147 	},
148 	[0xe] = {
149 		"Model B rev2",
150 		"bcm2835-rpi-b-rev2.dtb",
151 		true,
152 	},
153 	[0xf] = {
154 		"Model B rev2",
155 		"bcm2835-rpi-b-rev2.dtb",
156 		true,
157 	},
158 	[0x10] = {
159 		"Model B+",
160 		"bcm2835-rpi-b-plus.dtb",
161 		true,
162 	},
163 	[0x11] = {
164 		"Compute Module",
165 		"bcm2835-rpi-cm.dtb",
166 		false,
167 	},
168 	[0x12] = {
169 		"Model A+",
170 		"bcm2835-rpi-a-plus.dtb",
171 		false,
172 	},
173 	[0x13] = {
174 		"Model B+",
175 		"bcm2835-rpi-b-plus.dtb",
176 		true,
177 	},
178 	[0x14] = {
179 		"Compute Module",
180 		"bcm2835-rpi-cm.dtb",
181 		false,
182 	},
183 	[0x15] = {
184 		"Model A+",
185 		"bcm2835-rpi-a-plus.dtb",
186 		false,
187 	},
188 #endif
189 };
190 
191 u32 rpi_board_rev = 0;
192 
193 int dram_init(void)
194 {
195 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1);
196 	int ret;
197 
198 	BCM2835_MBOX_INIT_HDR(msg);
199 	BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
200 
201 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
202 	if (ret) {
203 		printf("bcm2835: Could not query ARM memory size\n");
204 		return -1;
205 	}
206 
207 	gd->ram_size = msg->get_arm_mem.body.resp.mem_size;
208 
209 	return 0;
210 }
211 
212 static void set_fdtfile(void)
213 {
214 	const char *fdtfile;
215 
216 	if (getenv("fdtfile"))
217 		return;
218 
219 	fdtfile = models[rpi_board_rev].fdtfile;
220 	setenv("fdtfile", fdtfile);
221 }
222 
223 static void set_usbethaddr(void)
224 {
225 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1);
226 	int ret;
227 
228 	if (!models[rpi_board_rev].has_onboard_eth)
229 		return;
230 
231 	if (getenv("usbethaddr"))
232 		return;
233 
234 	BCM2835_MBOX_INIT_HDR(msg);
235 	BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
236 
237 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
238 	if (ret) {
239 		printf("bcm2835: Could not query MAC address\n");
240 		/* Ignore error; not critical */
241 		return;
242 	}
243 
244 	eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac);
245 
246 	return;
247 }
248 
249 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
250 static void set_board_info(void)
251 {
252 	char str_rev[11];
253 	sprintf(str_rev, "0x%X", rpi_board_rev);
254 	setenv("board_rev", str_rev);
255 	setenv("board_name", models[rpi_board_rev].name);
256 }
257 #endif /* CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG */
258 
259 int misc_init_r(void)
260 {
261 	set_fdtfile();
262 	set_usbethaddr();
263 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
264 	set_board_info();
265 #endif
266 	return 0;
267 }
268 
269 static int power_on_module(u32 module)
270 {
271 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1);
272 	int ret;
273 
274 	BCM2835_MBOX_INIT_HDR(msg_pwr);
275 	BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
276 			      SET_POWER_STATE);
277 	msg_pwr->set_power_state.body.req.device_id = module;
278 	msg_pwr->set_power_state.body.req.state =
279 		BCM2835_MBOX_SET_POWER_STATE_REQ_ON |
280 		BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
281 
282 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
283 				     &msg_pwr->hdr);
284 	if (ret) {
285 		printf("bcm2835: Could not set module %u power state\n",
286 		       module);
287 		return -1;
288 	}
289 
290 	return 0;
291 }
292 
293 static void get_board_rev(void)
294 {
295 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1);
296 	int ret;
297 	const char *name;
298 
299 	BCM2835_MBOX_INIT_HDR(msg);
300 	BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
301 
302 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
303 	if (ret) {
304 		printf("bcm2835: Could not query board revision\n");
305 		/* Ignore error; not critical */
306 		return;
307 	}
308 
309 	/*
310 	 * For details of old-vs-new scheme, see:
311 	 * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py
312 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282
313 	 * (a few posts down)
314 	 *
315 	 * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the
316 	 * lower byte to use as the board rev:
317 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250
318 	 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594
319 	 */
320 	rpi_board_rev = msg->get_board_rev.body.resp.rev;
321 	if (rpi_board_rev & 0x800000)
322 		rpi_board_rev = (rpi_board_rev >> 4) & 0xff;
323 	else
324 		rpi_board_rev &= 0xff;
325 	if (rpi_board_rev >= ARRAY_SIZE(models)) {
326 		printf("RPI: Board rev %u outside known range\n",
327 		       rpi_board_rev);
328 		rpi_board_rev = 0;
329 	}
330 	if (!models[rpi_board_rev].name) {
331 		printf("RPI: Board rev %u unknown\n", rpi_board_rev);
332 		rpi_board_rev = 0;
333 	}
334 
335 	name = models[rpi_board_rev].name;
336 	printf("RPI %s\n", name);
337 }
338 
339 int board_init(void)
340 {
341 	get_board_rev();
342 
343 	gd->bd->bi_boot_params = 0x100;
344 
345 	return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD);
346 }
347 
348 int board_mmc_init(bd_t *bis)
349 {
350 	ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
351 	int ret;
352 
353 	power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
354 
355 	BCM2835_MBOX_INIT_HDR(msg_clk);
356 	BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE);
357 	msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC;
358 
359 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
360 	if (ret) {
361 		printf("bcm2835: Could not query eMMC clock rate\n");
362 		return -1;
363 	}
364 
365 	return bcm2835_sdhci_init(BCM2835_SDHCI_BASE,
366 				  msg_clk->get_clock_rate.body.resp.rate_hz);
367 }
368 
369 int ft_board_setup(void *blob, bd_t *bd)
370 {
371 	/*
372 	 * For now, we simply always add the simplefb DT node. Later, we
373 	 * should be more intelligent, and e.g. only do this if no enabled DT
374 	 * node exists for the "real" graphics driver.
375 	 */
376 	lcd_dt_simplefb_add_node(blob);
377 
378 	return 0;
379 }
380