xref: /rk3399_rockchip-uboot/board/raspberrypi/rpi/rpi.c (revision a033171b2ece1f3575ab7277e7b862e7f611b3f6)
1 /*
2  * (C) Copyright 2012-2013 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 <mmc.h>
14 #include <asm/gpio.h>
15 #include <asm/arch/mbox.h>
16 #include <asm/arch/sdhci.h>
17 #include <asm/global_data.h>
18 #include <dm/platform_data/serial_pl01x.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 static const struct bcm2835_gpio_platdata gpio_platdata = {
23 	.base = BCM2835_GPIO_BASE,
24 };
25 
26 U_BOOT_DEVICE(bcm2835_gpios) = {
27 	.name = "gpio_bcm2835",
28 	.platdata = &gpio_platdata,
29 };
30 
31 static const struct pl01x_serial_platdata serial_platdata = {
32 	.base = 0x20201000,
33 	.type = TYPE_PL011,
34 	.clock = 3000000,
35 };
36 
37 U_BOOT_DEVICE(bcm2835_serials) = {
38 	.name = "serial_pl01x",
39 	.platdata = &serial_platdata,
40 };
41 
42 struct msg_get_arm_mem {
43 	struct bcm2835_mbox_hdr hdr;
44 	struct bcm2835_mbox_tag_get_arm_mem get_arm_mem;
45 	u32 end_tag;
46 };
47 
48 struct msg_get_board_rev {
49 	struct bcm2835_mbox_hdr hdr;
50 	struct bcm2835_mbox_tag_get_board_rev get_board_rev;
51 	u32 end_tag;
52 };
53 
54 struct msg_get_mac_address {
55 	struct bcm2835_mbox_hdr hdr;
56 	struct bcm2835_mbox_tag_get_mac_address get_mac_address;
57 	u32 end_tag;
58 };
59 
60 struct msg_set_power_state {
61 	struct bcm2835_mbox_hdr hdr;
62 	struct bcm2835_mbox_tag_set_power_state set_power_state;
63 	u32 end_tag;
64 };
65 
66 struct msg_get_clock_rate {
67 	struct bcm2835_mbox_hdr hdr;
68 	struct bcm2835_mbox_tag_get_clock_rate get_clock_rate;
69 	u32 end_tag;
70 };
71 
72 /* See comments in mbox.h for data source */
73 static const struct {
74 	const char *name;
75 	const char *fdtfile;
76 	bool has_onboard_eth;
77 } models[] = {
78 	[0] = {
79 		"Unknown model",
80 		"bcm2835-rpi-other.dtb",
81 		false,
82 	},
83 	[BCM2835_BOARD_REV_B_I2C0_2] = {
84 		"Model B (no P5)",
85 		"bcm2835-rpi-b-i2c0.dtb",
86 		true,
87 	},
88 	[BCM2835_BOARD_REV_B_I2C0_3] = {
89 		"Model B (no P5)",
90 		"bcm2835-rpi-b-i2c0.dtb",
91 		true,
92 	},
93 	[BCM2835_BOARD_REV_B_I2C1_4] = {
94 		"Model B",
95 		"bcm2835-rpi-b.dtb",
96 		true,
97 	},
98 	[BCM2835_BOARD_REV_B_I2C1_5] = {
99 		"Model B",
100 		"bcm2835-rpi-b.dtb",
101 		true,
102 	},
103 	[BCM2835_BOARD_REV_B_I2C1_6] = {
104 		"Model B",
105 		"bcm2835-rpi-b.dtb",
106 		true,
107 	},
108 	[BCM2835_BOARD_REV_A_7] = {
109 		"Model A",
110 		"bcm2835-rpi-a.dtb",
111 		false,
112 	},
113 	[BCM2835_BOARD_REV_A_8] = {
114 		"Model A",
115 		"bcm2835-rpi-a.dtb",
116 		false,
117 	},
118 	[BCM2835_BOARD_REV_A_9] = {
119 		"Model A",
120 		"bcm2835-rpi-a.dtb",
121 		false,
122 	},
123 	[BCM2835_BOARD_REV_B_REV2_d] = {
124 		"Model B rev2",
125 		"bcm2835-rpi-b-rev2.dtb",
126 		true,
127 	},
128 	[BCM2835_BOARD_REV_B_REV2_e] = {
129 		"Model B rev2",
130 		"bcm2835-rpi-b-rev2.dtb",
131 		true,
132 	},
133 	[BCM2835_BOARD_REV_B_REV2_f] = {
134 		"Model B rev2",
135 		"bcm2835-rpi-b-rev2.dtb",
136 		true,
137 	},
138 	[BCM2835_BOARD_REV_B_PLUS] = {
139 		"Model B+",
140 		"bcm2835-rpi-b-plus.dtb",
141 		true,
142 	},
143 	[BCM2835_BOARD_REV_CM] = {
144 		"Compute Module",
145 		"bcm2835-rpi-cm.dtb",
146 		false,
147 	},
148 	[BCM2835_BOARD_REV_A_PLUS] = {
149 		"Model A+",
150 		"bcm2835-rpi-a-plus.dtb",
151 		false,
152 	},
153 };
154 
155 u32 rpi_board_rev = 0;
156 
157 int dram_init(void)
158 {
159 	ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16);
160 	int ret;
161 
162 	BCM2835_MBOX_INIT_HDR(msg);
163 	BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY);
164 
165 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
166 	if (ret) {
167 		printf("bcm2835: Could not query ARM memory size\n");
168 		return -1;
169 	}
170 
171 	gd->ram_size = msg->get_arm_mem.body.resp.mem_size;
172 
173 	return 0;
174 }
175 
176 static void set_fdtfile(void)
177 {
178 	const char *fdtfile;
179 
180 	if (getenv("fdtfile"))
181 		return;
182 
183 	fdtfile = models[rpi_board_rev].fdtfile;
184 	setenv("fdtfile", fdtfile);
185 }
186 
187 static void set_usbethaddr(void)
188 {
189 	ALLOC_ALIGN_BUFFER(struct msg_get_mac_address, msg, 1, 16);
190 	int ret;
191 
192 	if (!models[rpi_board_rev].has_onboard_eth)
193 		return;
194 
195 	if (getenv("usbethaddr"))
196 		return;
197 
198 	BCM2835_MBOX_INIT_HDR(msg);
199 	BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS);
200 
201 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
202 	if (ret) {
203 		printf("bcm2835: Could not query MAC address\n");
204 		/* Ignore error; not critical */
205 		return;
206 	}
207 
208 	eth_setenv_enetaddr("usbethaddr", msg->get_mac_address.body.resp.mac);
209 
210 	return;
211 }
212 
213 int misc_init_r(void)
214 {
215 	set_fdtfile();
216 	set_usbethaddr();
217 	return 0;
218 }
219 
220 static int power_on_module(u32 module)
221 {
222 	ALLOC_ALIGN_BUFFER(struct msg_set_power_state, msg_pwr, 1, 16);
223 	int ret;
224 
225 	BCM2835_MBOX_INIT_HDR(msg_pwr);
226 	BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
227 			      SET_POWER_STATE);
228 	msg_pwr->set_power_state.body.req.device_id = module;
229 	msg_pwr->set_power_state.body.req.state =
230 		BCM2835_MBOX_SET_POWER_STATE_REQ_ON |
231 		BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
232 
233 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
234 				     &msg_pwr->hdr);
235 	if (ret) {
236 		printf("bcm2835: Could not set module %u power state\n",
237 		       module);
238 		return -1;
239 	}
240 
241 	return 0;
242 }
243 
244 static void get_board_rev(void)
245 {
246 	ALLOC_ALIGN_BUFFER(struct msg_get_board_rev, msg, 1, 16);
247 	int ret;
248 	const char *name;
249 
250 	BCM2835_MBOX_INIT_HDR(msg);
251 	BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV);
252 
253 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr);
254 	if (ret) {
255 		printf("bcm2835: Could not query board revision\n");
256 		/* Ignore error; not critical */
257 		return;
258 	}
259 
260 	rpi_board_rev = msg->get_board_rev.body.resp.rev;
261 	if (rpi_board_rev >= ARRAY_SIZE(models)) {
262 		printf("RPI: Board rev %u outside known range\n",
263 		       rpi_board_rev);
264 		rpi_board_rev = 0;
265 	}
266 	if (!models[rpi_board_rev].name) {
267 		printf("RPI: Board rev %u unknown\n", rpi_board_rev);
268 		rpi_board_rev = 0;
269 	}
270 
271 	name = models[rpi_board_rev].name;
272 	printf("RPI model: %s\n", name);
273 }
274 
275 int board_init(void)
276 {
277 	get_board_rev();
278 
279 	gd->bd->bi_boot_params = 0x100;
280 
281 	return power_on_module(BCM2835_MBOX_POWER_DEVID_USB_HCD);
282 }
283 
284 int board_mmc_init(bd_t *bis)
285 {
286 	ALLOC_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1, 16);
287 	int ret;
288 
289 	power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
290 
291 	BCM2835_MBOX_INIT_HDR(msg_clk);
292 	BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE);
293 	msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC;
294 
295 	ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
296 	if (ret) {
297 		printf("bcm2835: Could not query eMMC clock rate\n");
298 		return -1;
299 	}
300 
301 	return bcm2835_sdhci_init(BCM2835_SDHCI_BASE,
302 				  msg_clk->get_clock_rate.body.resp.rate_hz);
303 }
304 
305 int ft_board_setup(void *blob, bd_t *bd)
306 {
307 	/*
308 	 * For now, we simply always add the simplefb DT node. Later, we
309 	 * should be more intelligent, and e.g. only do this if no enabled DT
310 	 * node exists for the "real" graphics driver.
311 	 */
312 	lcd_dt_simplefb_add_node(blob);
313 
314 	return 0;
315 }
316