xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/rk_atags.c (revision dfe45d3e7e8abc8fcabff66135bf69b9671c19a4)
1 // SPDX-License-Identifier:     GPL-2.0+
2 /*
3  * (C) Copyright 2018 Rockchip Electronics Co., Ltd.
4  *
5  */
6 
7 #include <common.h>
8 #include <asm/io.h>
9 #include <asm/arch/bootrom.h>
10 #include <asm/arch/rk_atags.h>
11 #if CONFIG_IS_ENABLED(TINY_FRAMEWORK)
12 #include <debug_uart.h>
13 #endif
14 
15 #define HASH_LEN	sizeof(u32)
16 
17 #if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD)
18 /*
19  * The array is used to transform rom bootsource type to rk atags boot type.
20  */
21 static int bootdev_map[] = {
22 	BOOT_TYPE_UNKNOWN,
23 	BOOT_TYPE_NAND,
24 	BOOT_TYPE_EMMC,
25 	BOOT_TYPE_SPI_NOR,
26 	BOOT_TYPE_SPI_NAND,
27 	BOOT_TYPE_SD0,
28 	BOOT_TYPE_UNKNOWN,
29 	BOOT_TYPE_UFS,
30 	BOOT_TYPE_UNKNOWN,
31 	BOOT_TYPE_UNKNOWN,
32 	BOOT_TYPE_UNKNOWN
33 };
34 
35 static int spl_bootdev_map[] = {
36 	BOOT_TYPE_RAM,
37 	BOOT_TYPE_EMMC,
38 	BOOT_TYPE_SD0,
39 	BOOT_TYPE_UNKNOWN,
40 	BOOT_TYPE_NAND,
41 	BOOT_TYPE_UNKNOWN,
42 	BOOT_TYPE_UNKNOWN,
43 	BOOT_TYPE_UNKNOWN,
44 	BOOT_TYPE_UNKNOWN,
45 	BOOT_TYPE_UNKNOWN,
46 	BOOT_TYPE_UNKNOWN,
47 	BOOT_TYPE_UNKNOWN,
48 	BOOT_TYPE_UNKNOWN,
49 	BOOT_TYPE_UNKNOWN,
50 	BOOT_TYPE_UNKNOWN,
51 	BOOT_TYPE_UNKNOWN,
52 	BOOT_TYPE_MTD_BLK_NAND,
53 	BOOT_TYPE_MTD_BLK_SPI_NAND,
54 	BOOT_TYPE_MTD_BLK_SPI_NOR,
55 	BOOT_TYPE_UNKNOWN,
56 	BOOT_TYPE_UFS
57 };
58 #endif
59 
60 #if CONFIG_IS_ENABLED(TINY_FRAMEWORK) &&		\
61 	!CONFIG_IS_ENABLED(LIBGENERIC_SUPPORT) &&	\
62 	!CONFIG_IS_ENABLED(USE_ARCH_MEMSET)
63 /**
64  * memset - Fill a region of memory with the given value
65  * @s: Pointer to the start of the area.
66  * @c: The byte to fill the area with
67  * @count: The size of the area.
68  *
69  * Do not use memset() to access IO space, use memset_io() instead.
70  */
memset(void * s,int c,size_t count)71 void *memset(void *s, int c, size_t count)
72 {
73 	unsigned long *sl = (unsigned long *)s;
74 	char *s8;
75 
76 	s8 = (char *)sl;
77 	while (count--)
78 		*s8++ = c;
79 
80 	return s;
81 }
82 #endif
83 
84 #if CONFIG_IS_ENABLED(TINY_FRAMEWORK) &&		\
85 	!CONFIG_IS_ENABLED(LIBGENERIC_SUPPORT) &&	\
86 	!CONFIG_IS_ENABLED(USE_ARCH_MEMCPY)
87 /**
88  * memcpy - Copy one area of memory to another
89  * @dest: Where to copy to
90  * @src: Where to copy from
91  * @count: The size of the area.
92  *
93  * You should not use this function to access IO space, use memcpy_toio()
94  * or memcpy_fromio() instead.
95  */
memcpy(void * dest,const void * src,size_t count)96 void *memcpy(void *dest, const void *src, size_t count)
97 {
98 	unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src;
99 	char *d8, *s8;
100 
101 	if (src == dest)
102 		return dest;
103 
104 	/* while all data is aligned (common case), copy a word at a time */
105 	if ((((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) == 0) {
106 		while (count >= sizeof(*dl)) {
107 			*dl++ = *sl++;
108 			count -= sizeof(*dl);
109 		}
110 	}
111 	/* copy the reset one byte at a time */
112 	d8 = (char *)dl;
113 	s8 = (char *)sl;
114 	while (count--)
115 		*d8++ = *s8++;
116 
117 	return dest;
118 }
119 #endif
120 
js_hash(void * buf,u32 len)121 static u32 js_hash(void *buf, u32 len)
122 {
123 	u32 i, hash = 0x47C6A7E6;
124 	char *data = buf;
125 
126 	if (!buf || !len)
127 		return hash;
128 
129 	for (i = 0; i < len; i++)
130 		hash ^= ((hash << 5) + data[i] + (hash >> 2));
131 
132 	return hash;
133 }
134 
atags_bad_magic(u32 magic)135 int atags_bad_magic(u32 magic)
136 {
137 	bool bad;
138 
139 	bad = ((magic != ATAG_CORE) &&
140 	       (magic != ATAG_NONE) &&
141 	       (magic < ATAG_SERIAL || magic > ATAG_MAX));
142 	if (bad) {
143 #if !CONFIG_IS_ENABLED(TINY_FRAMEWORK)
144 		printf("Magic(%x) is not support\n", magic);
145 #else
146 		printascii("Magic is not support\n");
147 #endif
148 	}
149 
150 	return bad;
151 }
152 
atags_size_overflow(struct tag * t,u32 tag_size)153 static int inline atags_size_overflow(struct tag *t, u32 tag_size)
154 {
155 	return (unsigned long)t + (tag_size << 2) - ATAGS_PHYS_BASE > ATAGS_SIZE;
156 }
157 
atags_overflow(struct tag * t)158 int atags_overflow(struct tag *t)
159 {
160 	bool overflow;
161 
162 	overflow = atags_size_overflow(t, 0) ||
163 		   atags_size_overflow(t, t->hdr.size);
164 	if (overflow) {
165 #if !CONFIG_IS_ENABLED(TINY_FRAMEWORK)
166 		printf("Tag is overflow\n");
167 #else
168 		printascii("Tag is overflow\n");
169 #endif
170 	}
171 
172 	return overflow;
173 }
174 
atags_is_available(void)175 int atags_is_available(void)
176 {
177 	struct tag *t = (struct tag *)ATAGS_PHYS_BASE;
178 
179 	return (t->hdr.magic == ATAG_CORE);
180 }
181 
atags_set_tag(u32 magic,void * tagdata)182 int atags_set_tag(u32 magic, void *tagdata)
183 {
184 	struct tag *t = (struct tag *)ATAGS_PHYS_BASE;
185 	u32 length, size = 0, hash;
186 	int append = 1; /* 0: override */
187 
188 #if !defined(CONFIG_TPL_BUILD) && !CONFIG_IS_ENABLED(FPGA_ROCKCHIP)
189 	if (!atags_is_available())
190 		return -EPERM;
191 #endif
192 
193 	if (!tagdata)
194 		return -ENODATA;
195 
196 	if (atags_bad_magic(magic))
197 		return -EINVAL;
198 
199 	/* Not allowed to be set by user directly, so do nothing */
200 	if ((magic == ATAG_CORE) || (magic == ATAG_NONE))
201 		return -EPERM;
202 
203 	/* If not initialized, setup now! */
204 	if (t->hdr.magic != ATAG_CORE) {
205 		t->hdr.magic = ATAG_CORE;
206 		t->hdr.size = tag_size(tag_core);
207 		t->u.core.flags = 0;
208 		t->u.core.pagesize = 0;
209 		t->u.core.rootdev = 0;
210 
211 		t = tag_next(t);
212 	} else {
213 		/* Find the end, and use it as a new tag */
214 		for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) {
215 			if (atags_overflow(t))
216 				return -EINVAL;
217 
218 			if (atags_bad_magic(t->hdr.magic))
219 				return -EINVAL;
220 
221 			/* This is an old tag, override it */
222 			if (t->hdr.magic == magic) {
223 				append = 0;
224 				break;
225 			}
226 
227 			if (t->hdr.magic == ATAG_NONE)
228 				break;
229 		}
230 	}
231 
232 	/* Initialize new tag */
233 	switch (magic) {
234 	case ATAG_SERIAL:
235 		size = tag_size(tag_serial);
236 		break;
237 	case ATAG_BOOTDEV:
238 		size = tag_size(tag_bootdev);
239 		break;
240 	case ATAG_TOS_MEM:
241 		size = tag_size(tag_tos_mem);
242 		break;
243 	case ATAG_DDR_MEM:
244 		size = tag_size(tag_ddr_mem);
245 		break;
246 	case ATAG_RAM_PARTITION:
247 		size = tag_size(tag_ram_partition);
248 		break;
249 	case ATAG_ATF_MEM:
250 		size = tag_size(tag_atf_mem);
251 		break;
252 	case ATAG_PUB_KEY:
253 		size = tag_size(tag_pub_key);
254 		break;
255 	case ATAG_SOC_INFO:
256 		size = tag_size(tag_soc_info);
257 		break;
258 	case ATAG_BOOT1_PARAM:
259 		size = tag_size(tag_boot1p);
260 		break;
261 	case ATAG_PSTORE:
262 		size = tag_size(tag_pstore);
263 		break;
264 	case ATAG_FWVER:
265 		size = tag_size(tag_fwver);
266 		break;
267 	};
268 
269 	if (!size)
270 		return -EINVAL;
271 
272 	if (atags_size_overflow(t, size))
273 		return -ENOMEM;
274 
275 	/* It's okay to setup a new tag or override tag */
276 	t->hdr.magic = magic;
277 	t->hdr.size = size;
278 	length = (t->hdr.size << 2) - sizeof(struct tag_header) - HASH_LEN;
279 	memcpy(&t->u, (char *)tagdata, length);
280 	hash = js_hash(t, (size << 2) - HASH_LEN);
281 	memcpy((char *)&t->u + length, &hash, HASH_LEN);
282 
283 	if (append) {
284 		/* Next tag */
285 		t = tag_next(t);
286 
287 		/* Setup done */
288 		t->hdr.magic = ATAG_NONE;
289 		t->hdr.size = 0;
290 	}
291 
292 	return 0;
293 }
294 
295 #ifndef CONFIG_TPL_BUILD
atags_set_shared_fwver(u32 fwid,char * ver)296 int atags_set_shared_fwver(u32 fwid, char *ver)
297 {
298 	struct tag_fwver fw = {}, *pfw;
299 	struct tag *t;
300 
301 	if (!ver || (strlen(ver) >= FWVER_LEN) || fwid >= FW_MAX)
302 		return -EINVAL;
303 
304 	t = atags_get_tag(ATAG_FWVER);
305 	if (!t) {
306 		pfw = &fw;
307 		pfw->version = 0;
308 	} else {
309 		pfw = &t->u.fwver;
310 	}
311 
312 	strcpy(pfw->ver[fwid], ver);
313 	atags_set_tag(ATAG_FWVER, pfw);
314 
315 	return 0;
316 }
317 
atags_get_tag(u32 magic)318 struct tag *atags_get_tag(u32 magic)
319 {
320 	u32 *hash, calc_hash, size;
321 	struct tag *t;
322 
323 	if (!atags_is_available())
324 		return NULL;
325 
326 	for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) {
327 		if (atags_overflow(t))
328 			return NULL;
329 
330 		if (atags_bad_magic(t->hdr.magic))
331 			return NULL;
332 
333 		if (t->hdr.magic != magic)
334 			continue;
335 
336 		size = t->hdr.size;
337 		hash = (u32 *)((ulong)t + (size << 2) - HASH_LEN);
338 		if (!*hash) {
339 			debug("No hash, magic(%x)\n", magic);
340 			return t;
341 		} else {
342 			calc_hash = js_hash(t, (size << 2) - HASH_LEN);
343 			if (calc_hash == *hash) {
344 				debug("Hash okay, magic(%x)\n", magic);
345 				return t;
346 			} else {
347 				debug("Hash bad, magic(%x), orgHash=%x, nowHash=%x\n",
348 				      magic, *hash, calc_hash);
349 				return NULL;
350 			}
351 		}
352 	}
353 
354 	return NULL;
355 }
356 #else
atags_get_tag(u32 magic)357 struct tag *atags_get_tag(u32 magic) { return NULL; }
358 #endif
359 
360 #if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD)
get_bootdev_by_brom_bootsource(void)361 int get_bootdev_by_brom_bootsource(void)
362 {
363 	int bootsource = 0;
364 
365 	bootsource = readl(BROM_BOOTSOURCE_ID_ADDR);
366 	if (bootsource > ARRAY_SIZE(bootdev_map) - 1 || bootsource < 0)
367 		return 0;
368 	else
369 		return bootdev_map[bootsource];
370 }
371 
atags_set_bootdev_by_brom_bootsource(void)372 int atags_set_bootdev_by_brom_bootsource(void)
373 {
374 	struct tag_bootdev boot_dev;
375 
376 	memset(&boot_dev, 0, sizeof(struct tag_bootdev));
377 	boot_dev.devtype = get_bootdev_by_brom_bootsource();
378 
379 	return atags_set_tag(ATAG_BOOTDEV, &boot_dev);
380 }
381 
get_bootdev_by_spl_bootdevice(int bootdevice)382 int get_bootdev_by_spl_bootdevice(int bootdevice)
383 {
384 	if (bootdevice > ARRAY_SIZE(spl_bootdev_map) - 1)
385 		return -ENODEV;
386 
387 	return spl_bootdev_map[bootdevice];
388 }
389 
atags_set_bootdev_by_spl_bootdevice(int bootdevice)390 int atags_set_bootdev_by_spl_bootdevice(int bootdevice)
391 {
392 	struct tag_bootdev boot_dev;
393 
394 	memset(&boot_dev, 0, sizeof(struct tag_bootdev));
395 	boot_dev.devtype = get_bootdev_by_spl_bootdevice(bootdevice);
396 	if (boot_dev.devtype < 0)
397 		boot_dev.devtype = BOOT_TYPE_UNKNOWN;
398 
399 	return atags_set_tag(ATAG_BOOTDEV, &boot_dev);
400 }
401 
atags_set_pub_key(void * data,int len,int flag)402 int atags_set_pub_key(void *data, int len, int flag)
403 {
404 	struct tag_pub_key pub_key;
405 
406 	if (!data)
407 		return -ENOMEM;
408 
409 	memset(&pub_key, 0, sizeof(struct tag_pub_key));
410 	pub_key.len = len;
411 	pub_key.flag = flag;
412 	memcpy(pub_key.data, data, len);
413 
414 	return atags_set_tag(ATAG_PUB_KEY, &pub_key);
415 }
416 #endif
417 
atags_destroy(void)418 void atags_destroy(void)
419 {
420 	if (atags_is_available())
421 		memset((char *)ATAGS_PHYS_BASE, 0, sizeof(struct tag));
422 }
423 
424