xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-rockchip/kernel_dtb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 #include <common.h>
7 #include <boot_rkimg.h>
8 #include <dm.h>
9 #include <malloc.h>
10 #include <of_live.h>
11 #include <dm/device-internal.h>
12 #include <dm/root.h>
13 #include <dm/uclass-internal.h>
14 #include <asm/arch/hotkey.h>
15 #include <asm/arch/resource_img.h>
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 #ifdef CONFIG_USING_KERNEL_DTB_V2
dm_rm_kernel_dev(void)20 static int dm_rm_kernel_dev(void)
21 {
22 	struct udevice *dev, *rec[10];
23 	u32 uclass[] = { UCLASS_CRYPTO };
24 	int i, j, k;
25 
26 	for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) {
27 		for (uclass_find_first_device(uclass[i], &dev); dev;
28 		     uclass_find_next_device(&dev)) {
29 			if (dev->flags & DM_FLAG_KNRL_DTB)
30 				rec[j++] = dev;
31 		}
32 
33 		for (k = 0; k < j; k++) {
34 			device_remove(rec[k], DM_REMOVE_NORMAL);
35 			device_unbind(rec[k]);
36 		}
37 	}
38 
39 	return 0;
40 }
41 
dm_rm_u_boot_dev(void)42 static int dm_rm_u_boot_dev(void)
43 {
44 	struct udevice *dev, *rec[10];
45 	u32 uclass[] = { UCLASS_ETH };
46 	int del = 0;
47 	int i, j, k;
48 
49 	for (i = 0, j = 0; i < ARRAY_SIZE(uclass); i++) {
50 		for (uclass_find_first_device(uclass[i], &dev); dev;
51 		     uclass_find_next_device(&dev)) {
52 			if (dev->flags & DM_FLAG_KNRL_DTB)
53 				del = 1;
54 			else
55 				rec[j++] = dev;
56 		}
57 
58 		/* remove u-boot dev if there is someone from kernel */
59 		if (del) {
60 			for (k = 0; k < j; k++) {
61 				device_remove(rec[k], DM_REMOVE_NORMAL);
62 				device_unbind(rec[k]);
63 			}
64 		}
65 	}
66 
67 	return 0;
68 }
69 
70 #else
71 /* Here, only fixup cru phandle, pmucru is not included */
phandles_fixup_cru(const void * fdt)72 static int phandles_fixup_cru(const void *fdt)
73 {
74 	const char *props[] = { "clocks", "assigned-clocks", "resets"};
75 	struct udevice *dev;
76 	struct uclass *uc;
77 	const char *comp;
78 	u32 id, nclocks;
79 	u32 *clocks;
80 	int phandle, ncells;
81 	int off, offset;
82 	int ret, length;
83 	int i, j;
84 	int first_phandle = -1;
85 
86 	phandle = -ENODATA;
87 	ncells = -ENODATA;
88 
89 	/* fdt points to kernel dtb, getting cru phandle and "#clock-cells" */
90 	for (offset = fdt_next_node(fdt, 0, NULL);
91 	     offset >= 0;
92 	     offset = fdt_next_node(fdt, offset, NULL)) {
93 		comp = fdt_getprop(fdt, offset, "compatible", NULL);
94 		if (!comp)
95 			continue;
96 
97 		/* Actually, this is not a good method to get cru node */
98 		off = strlen(comp) - strlen("-cru");
99 		if (off > 0 && !strncmp(comp + off, "-cru", 4)) {
100 			phandle = fdt_get_phandle(fdt, offset);
101 			ncells = fdtdec_get_int(fdt, offset,
102 						"#clock-cells", -ENODATA);
103 			break;
104 		}
105 	}
106 
107 	if (phandle == -ENODATA || ncells == -ENODATA)
108 		return 0;
109 
110 	debug("%s: target cru: clock-cells:%d, phandle:0x%x\n",
111 	      __func__, ncells, fdt32_to_cpu(phandle));
112 
113 	/* Try to fixup all cru phandle from U-Boot dtb nodes */
114 	for (id = 0; id < UCLASS_COUNT; id++) {
115 		ret = uclass_get(id, &uc);
116 		if (ret)
117 			continue;
118 
119 		if (list_empty(&uc->dev_head))
120 			continue;
121 
122 		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
123 			/* Only U-Boot node go further */
124 			if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") &&
125 			    !dev_read_bool(dev, "u-boot,dm-spl"))
126 				continue;
127 
128 			for (i = 0; i < ARRAY_SIZE(props); i++) {
129 				if (!dev_read_prop(dev, props[i], &length))
130 					continue;
131 
132 				clocks = malloc(length);
133 				if (!clocks)
134 					return -ENOMEM;
135 
136 				/* Read "props[]" which contains cru phandle */
137 				nclocks = length / sizeof(u32);
138 				if (dev_read_u32_array(dev, props[i],
139 						       clocks, nclocks)) {
140 					free(clocks);
141 					continue;
142 				}
143 
144 				/* Fixup with kernel cru phandle */
145 				for (j = 0; j < nclocks; j += (ncells + 1)) {
146 					/*
147 					 * Check: update pmucru phandle with cru
148 					 * phandle by mistake.
149 					 */
150 					if (first_phandle == -1)
151 						first_phandle = clocks[j];
152 
153 					if (clocks[j] != first_phandle) {
154 						debug("WARN: %s: first cru phandle=%d, this=%d\n",
155 						      dev_read_name(dev),
156 						      first_phandle, clocks[j]);
157 						continue;
158 					}
159 
160 					clocks[j] = phandle;
161 				}
162 
163 				/*
164 				 * Override live dt nodes but not fdt nodes,
165 				 * because all U-Boot nodes has been imported
166 				 * to live dt nodes, should use "dev_xxx()".
167 				 */
168 				dev_write_u32_array(dev, props[i],
169 						    clocks, nclocks);
170 				free(clocks);
171 			}
172 		}
173 	}
174 
175 	return 0;
176 }
177 
phandles_fixup_gpio(const void * fdt,void * ufdt)178 static int phandles_fixup_gpio(const void *fdt, void *ufdt)
179 {
180 	struct udevice *dev;
181 	struct uclass *uc;
182 	const char *prop = "gpios";
183 	const char *comp;
184 	char *gpio_name[10];
185 	int gpio_off[10];
186 	int pinctrl;
187 	int offset;
188 	int i = 0;
189 	int n = 0;
190 
191 	pinctrl = fdt_path_offset(fdt, "/pinctrl");
192 	if (pinctrl < 0)
193 		return 0;
194 
195 	memset(gpio_name, 0, sizeof(gpio_name));
196 	for (offset = fdt_first_subnode(fdt, pinctrl);
197 	     offset >= 0;
198 	     offset = fdt_next_subnode(fdt, offset)) {
199 		/* assume the font nodes are gpio node */
200 		if (++i >= ARRAY_SIZE(gpio_name))
201 			break;
202 
203 		comp = fdt_getprop(fdt, offset, "compatible", NULL);
204 		if (!comp)
205 			continue;
206 
207 		if (!strcmp(comp, "rockchip,gpio-bank")) {
208 			gpio_name[n] = (char *)fdt_get_name(fdt, offset, NULL);
209 			gpio_off[n]  = offset;
210 			n++;
211 		}
212 	}
213 
214 	if (!gpio_name[0])
215 		return 0;
216 
217 	if (uclass_get(UCLASS_KEY, &uc) || list_empty(&uc->dev_head))
218 		return 0;
219 
220 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
221 		u32 new_phd, phd_old;
222 		char *name;
223 		ofnode ofn;
224 
225 		if (!dev_read_bool(dev, "u-boot,dm-pre-reloc") &&
226 		    !dev_read_bool(dev, "u-boot,dm-spl"))
227 			continue;
228 
229 		if (dev_read_u32_array(dev, prop, &phd_old, 1))
230 			continue;
231 
232 		ofn = ofnode_get_by_phandle(phd_old);
233 		if (!ofnode_valid(ofn))
234 			continue;
235 
236 		name = (char *)ofnode_get_name(ofn);
237 		if (!name)
238 			continue;
239 
240 		for (i = 0; i < ARRAY_SIZE(gpio_name); i++) {
241 			if (gpio_name[i] && !strcmp(name, gpio_name[i])) {
242 				new_phd = fdt_get_phandle(fdt, gpio_off[i]);
243 				dev_write_u32_array(dev, prop, &new_phd, 1);
244 				break;
245 			}
246 		}
247 	}
248 
249 	return 0;
250 }
251 #endif
252 
board_mmc_dm_reinit(struct udevice * dev)253 __weak int board_mmc_dm_reinit(struct udevice *dev)
254 {
255 	return 0;
256 }
257 
mmc_dm_reinit(void)258 static int mmc_dm_reinit(void)
259 {
260 	struct udevice *dev;
261 	struct uclass *uc;
262 	int ret;
263 
264 	if (uclass_get(UCLASS_MMC, &uc) || list_empty(&uc->dev_head))
265 		return 0;
266 
267 	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
268 		ret = board_mmc_dm_reinit(dev);
269 		if (ret)
270 			return ret;
271 	}
272 
273 	return 0;
274 }
275 
276 /* Check by property: "/compatible" */
dtb_check_ok(void * kfdt,void * ufdt)277 static int dtb_check_ok(void *kfdt, void *ufdt)
278 {
279 	const char *compat;
280 	int index;
281 
282 	/* TODO */
283 	return 1;
284 
285 	for (index = 0;
286 	     compat = fdt_stringlist_get(ufdt, 0, "compatible",
287 					 index, NULL), compat;
288 	     index++) {
289 		debug("u-compat: %s\n", compat);
290 		if (!fdt_node_check_compatible(kfdt, 0, compat))
291 			return 1;
292 	}
293 
294 	return 0;
295 }
296 
init_kernel_dtb(void)297 int init_kernel_dtb(void)
298 {
299 #ifndef CONFIG_USING_KERNEL_DTB_V2
300 	void *ufdt_blob = (void *)gd->fdt_blob;
301 #endif
302 	ulong fdt_addr = 0;
303 	int ret = -ENODEV;
304 
305 	printf("DM: v%d\n", IS_ENABLED(CONFIG_USING_KERNEL_DTB_V2) ? 2 : 1);
306 
307 	/*
308 	 * If memory size <= 128MB, we firstly try to get "fdt_addr1_r".
309 	 */
310 	if (gd->ram_size <= SZ_128M)
311 		fdt_addr = env_get_ulong("fdt_addr1_r", 16, 0);
312 
313 	if (!fdt_addr)
314 		fdt_addr = env_get_ulong("fdt_addr_r", 16, 0);
315 	if (!fdt_addr) {
316 		printf("No Found FDT Load Address.\n");
317 		return -ENODEV;
318 	}
319 
320 #ifdef CONFIG_EMBED_KERNEL_DTB_ALWAYS
321 	printf("Always embed kernel dtb\n");
322 	goto dtb_embed;
323 #endif
324 	ret = rockchip_read_dtb_file((void *)fdt_addr);
325 	if (!ret) {
326 		if (!dtb_check_ok((void *)fdt_addr, (void *)gd->fdt_blob)) {
327 			ret = -EINVAL;
328 			printf("Kernel dtb mismatch this platform!\n");
329 		} else {
330 			goto dtb_okay;
331 		}
332 	}
333 
334 #ifdef CONFIG_EMBED_KERNEL_DTB
335 #ifdef CONFIG_EMBED_KERNEL_DTB_ALWAYS
336 dtb_embed:
337 #endif
338 	if (gd->fdt_blob_kern) {
339 		if (!dtb_check_ok((void *)gd->fdt_blob_kern, (void *)gd->fdt_blob)) {
340 			printf("Embedded kernel dtb mismatch this platform!\n");
341 			return -EINVAL;
342 		}
343 
344 		fdt_addr = (ulong)memalign(ARCH_DMA_MINALIGN,
345 				fdt_totalsize(gd->fdt_blob_kern));
346 		if (!fdt_addr)
347 			return -ENOMEM;
348 
349 		/*
350 		 * Alloc another space for this embed kernel dtb.
351 		 * Because "fdt_addr_r" *MUST* be the fdt passed to kernel.
352 		 */
353 		memcpy((void *)fdt_addr, gd->fdt_blob_kern,
354 		       fdt_totalsize(gd->fdt_blob_kern));
355 		printf("DTB: %s\n", CONFIG_EMBED_KERNEL_DTB_PATH);
356 	} else
357 #endif
358 	{
359 		printf("Failed to get kernel dtb, ret=%d\n", ret);
360 		return -ENOENT;
361 	}
362 
363 dtb_okay:
364 	gd->fdt_blob = (void *)fdt_addr;
365 	hotkey_run(HK_FDT);
366 
367 #ifndef CONFIG_USING_KERNEL_DTB_V2
368 	/*
369 	 * There is a phandle miss match between U-Boot and kernel dtb node,
370 	 * we fixup it in U-Boot live dt nodes.
371 	 *
372 	 * CRU:	 all nodes.
373 	 * GPIO: key nodes.
374 	 */
375 	phandles_fixup_cru((void *)gd->fdt_blob);
376 	phandles_fixup_gpio((void *)gd->fdt_blob, (void *)ufdt_blob);
377 #endif
378 
379 	gd->flags |= GD_FLG_KDTB_READY;
380 	gd->of_root_f = gd->of_root;
381 	of_live_build((void *)gd->fdt_blob, (struct device_node **)&gd->of_root);
382 	dm_scan_fdt((void *)gd->fdt_blob, false);
383 
384 #ifdef CONFIG_USING_KERNEL_DTB_V2
385 	dm_rm_kernel_dev();
386 	dm_rm_u_boot_dev();
387 #endif
388 	/*
389 	 * There maybe something for the mmc devices to do after kernel dtb
390 	 * dm setup, eg: regain the clock device binding from kernel dtb.
391 	 */
392 	mmc_dm_reinit();
393 
394 	/* Reserve 'reserved-memory' */
395 	ret = boot_fdt_add_sysmem_rsv_regions((void *)gd->fdt_blob);
396 	if (ret)
397 		return ret;
398 
399 	return 0;
400 }
401 
402