xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/uimage.c (revision 63f38f9d869677dbdf606e865c70068033ec6b4a)
1191c6877SJoseph Chen /*
2191c6877SJoseph Chen  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3191c6877SJoseph Chen  *
4191c6877SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5191c6877SJoseph Chen  */
6191c6877SJoseph Chen 
7191c6877SJoseph Chen #include <common.h>
8191c6877SJoseph Chen #include <boot_rkimg.h>
9191c6877SJoseph Chen #include <image.h>
10191c6877SJoseph Chen #include <malloc.h>
11191c6877SJoseph Chen #include <sysmem.h>
12191c6877SJoseph Chen #include <asm/arch/resource_img.h>
13191c6877SJoseph Chen #include <asm/arch/uimage.h>
14191c6877SJoseph Chen 
uimage_load_one(struct blk_desc * dev_desc,disk_partition_t * part,int pos_off,int size,void * dst)156ea28a6cSJoseph Chen int uimage_load_one(struct blk_desc *dev_desc, disk_partition_t *part,
16191c6877SJoseph Chen 		    int pos_off, int size, void *dst)
17191c6877SJoseph Chen {
18191c6877SJoseph Chen 	u32 blknum, blkoff;
19191c6877SJoseph Chen 	u32 unused;
20191c6877SJoseph Chen 	ulong blksz;
21191c6877SJoseph Chen 	void *buf;
22191c6877SJoseph Chen 
23191c6877SJoseph Chen 	blksz  = dev_desc->blksz;
24191c6877SJoseph Chen 	blkoff = pos_off / blksz;
25191c6877SJoseph Chen 	unused = pos_off - blkoff * blksz;
26191c6877SJoseph Chen 	blknum = DIV_ROUND_UP(size, blksz) + !!unused;
27191c6877SJoseph Chen 
28191c6877SJoseph Chen 	if (!size)
29191c6877SJoseph Chen 		return -EINVAL;
30191c6877SJoseph Chen 
31191c6877SJoseph Chen 	if (!IS_ALIGNED(unused, ARCH_DMA_MINALIGN)) {
32191c6877SJoseph Chen 		buf = memalign(ARCH_DMA_MINALIGN, blknum * blksz);
33191c6877SJoseph Chen 		if (!buf)
34191c6877SJoseph Chen 			return -ENOMEM;
35191c6877SJoseph Chen 
36191c6877SJoseph Chen 		if (blk_dread(dev_desc, part->start + blkoff,
37191c6877SJoseph Chen 			      blknum, buf) != blknum) {
38191c6877SJoseph Chen 			free(buf);
39191c6877SJoseph Chen 			return -EIO;
40191c6877SJoseph Chen 		}
41191c6877SJoseph Chen 
42191c6877SJoseph Chen 		memcpy(dst, buf + unused, size);
43191c6877SJoseph Chen 		free(buf);
44191c6877SJoseph Chen 	} else {
45191c6877SJoseph Chen 		if (blk_dread(dev_desc, part->start + blkoff,
46191c6877SJoseph Chen 		      blknum, (void *)((ulong)dst - unused)) != blknum)
47191c6877SJoseph Chen 			return -EIO;
48191c6877SJoseph Chen 	}
49191c6877SJoseph Chen 
50191c6877SJoseph Chen 	return 0;
51191c6877SJoseph Chen }
52191c6877SJoseph Chen 
uimage_get_hdr(struct blk_desc * dev_desc,disk_partition_t * part)53191c6877SJoseph Chen static image_header_t *uimage_get_hdr(struct blk_desc *dev_desc,
54191c6877SJoseph Chen 				      disk_partition_t *part)
55191c6877SJoseph Chen {
56191c6877SJoseph Chen 	image_header_t *hdr;
57191c6877SJoseph Chen 
58191c6877SJoseph Chen 	hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
59191c6877SJoseph Chen 	if (!hdr)
60191c6877SJoseph Chen 		return NULL;
61191c6877SJoseph Chen 
62191c6877SJoseph Chen 	if (blk_dread(dev_desc, part->start, 1, hdr) != 1)
63191c6877SJoseph Chen 		goto err;
64191c6877SJoseph Chen 
65191c6877SJoseph Chen 	if (!image_check_magic(hdr) || (image_get_type(hdr) != IH_TYPE_MULTI))
66191c6877SJoseph Chen 		goto err;
67191c6877SJoseph Chen 
68191c6877SJoseph Chen 	return hdr;
69191c6877SJoseph Chen err:
70191c6877SJoseph Chen 	free(hdr);
71191c6877SJoseph Chen 	return NULL;
72191c6877SJoseph Chen }
73191c6877SJoseph Chen 
uimage_load_bootables(void)74191c6877SJoseph Chen void *uimage_load_bootables(void)
75191c6877SJoseph Chen {
76191c6877SJoseph Chen 	struct blk_desc *dev_desc;
77191c6877SJoseph Chen 	disk_partition_t part;
78191c6877SJoseph Chen 	image_header_t *hdr;
79191c6877SJoseph Chen 	char *part_name;
80191c6877SJoseph Chen 	ulong raddr;
81191c6877SJoseph Chen 	ulong kaddr;
82191c6877SJoseph Chen 	ulong faddr;
83191c6877SJoseph Chen 	int blknum;
84191c6877SJoseph Chen 
85191c6877SJoseph Chen 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
86191c6877SJoseph Chen 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
87191c6877SJoseph Chen 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
88191c6877SJoseph Chen 
89191c6877SJoseph Chen 	if (!faddr || !kaddr || !raddr)
90191c6877SJoseph Chen 		return NULL;
91191c6877SJoseph Chen 
92191c6877SJoseph Chen 	dev_desc = rockchip_get_bootdev();
93191c6877SJoseph Chen 	if (!dev_desc) {
94191c6877SJoseph Chen 		UIMG_I("No dev_desc\n");
95191c6877SJoseph Chen 		return NULL;
96191c6877SJoseph Chen 	}
97191c6877SJoseph Chen 
98191c6877SJoseph Chen 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
99191c6877SJoseph Chen 		part_name = PART_RECOVERY;
100191c6877SJoseph Chen 	else
101191c6877SJoseph Chen 		part_name = PART_BOOT;
102191c6877SJoseph Chen 
103191c6877SJoseph Chen 	if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
104191c6877SJoseph Chen 		UIMG_I("No %s partition\n", part_name);
105191c6877SJoseph Chen 		return NULL;
106191c6877SJoseph Chen 	}
107191c6877SJoseph Chen 
108191c6877SJoseph Chen 	hdr = uimage_get_hdr(dev_desc, &part);
109191c6877SJoseph Chen 	if (!hdr)
110191c6877SJoseph Chen 		return NULL;
111191c6877SJoseph Chen 
112191c6877SJoseph Chen 	/* load */
113191c6877SJoseph Chen 	blknum = DIV_ROUND_UP(image_get_image_size(hdr), dev_desc->blksz);
114191c6877SJoseph Chen 	hdr = sysmem_alloc(MEM_UIMAGE, blknum * dev_desc->blksz);
115191c6877SJoseph Chen 	if (!hdr)
116191c6877SJoseph Chen 		return NULL;
117191c6877SJoseph Chen 
118191c6877SJoseph Chen 	if (blk_dread(dev_desc, part.start, blknum, (void *)hdr) != blknum) {
119191c6877SJoseph Chen 		UIMG_I("Failed to read %s data\n", part.name);
120191c6877SJoseph Chen 		return NULL;
121191c6877SJoseph Chen 	}
122191c6877SJoseph Chen 
123191c6877SJoseph Chen 	return hdr;
124191c6877SJoseph Chen }
125191c6877SJoseph Chen 
uimage_sysmem_reserve_each(image_header_t * hdr,u32 * ramdisk_sz)126a86a723eSJoseph Chen int uimage_sysmem_reserve_each(image_header_t *hdr, u32 *ramdisk_sz)
127191c6877SJoseph Chen {
128191c6877SJoseph Chen 	ulong raddr, kaddr, faddr;
129191c6877SJoseph Chen 	ulong data, size;
130191c6877SJoseph Chen 	int blknum;
131191c6877SJoseph Chen 	int blksz = RK_BLK_SIZE;
132191c6877SJoseph Chen 
133191c6877SJoseph Chen 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
134191c6877SJoseph Chen 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
135191c6877SJoseph Chen 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
136191c6877SJoseph Chen 
137191c6877SJoseph Chen 	if (!faddr || !kaddr || !raddr)
138191c6877SJoseph Chen 		return -EINVAL;
139191c6877SJoseph Chen 
140191c6877SJoseph Chen 	/* kernel */
141191c6877SJoseph Chen 	image_multi_getimg(hdr, 0, &data, &size);
142191c6877SJoseph Chen 	blknum = DIV_ROUND_UP(size, blksz);
143191c6877SJoseph Chen 	if (!sysmem_alloc_base(MEM_KERNEL, (phys_addr_t)kaddr,
144191c6877SJoseph Chen 			       blknum * blksz))
145191c6877SJoseph Chen 		return -ENOMEM;
146191c6877SJoseph Chen 
147191c6877SJoseph Chen 	/* ramdisk */
148191c6877SJoseph Chen 	image_multi_getimg(hdr, 1, &data, &size);
149a86a723eSJoseph Chen 	*ramdisk_sz = size;
150191c6877SJoseph Chen 	blknum = DIV_ROUND_UP(size, blksz);
151a86a723eSJoseph Chen 	if (size && !sysmem_alloc_base(MEM_RAMDISK, (phys_addr_t)raddr,
152191c6877SJoseph Chen 			       blknum * blksz))
153191c6877SJoseph Chen 		return -ENOMEM;
154191c6877SJoseph Chen 
155191c6877SJoseph Chen 	/* fdt */
156191c6877SJoseph Chen 	image_multi_getimg(hdr, 2, &data, &size);
157191c6877SJoseph Chen 	blknum = DIV_ROUND_UP(size, blksz);
158191c6877SJoseph Chen 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)faddr,
159191c6877SJoseph Chen 			       blknum * blksz))
160191c6877SJoseph Chen 		return -ENOMEM;
161191c6877SJoseph Chen 
162191c6877SJoseph Chen 	env_set_hex("fdt_high", faddr);
163191c6877SJoseph Chen 	env_set_hex("initrd_high", raddr);
164191c6877SJoseph Chen 	env_set("bootm-reloc-at", "y");
165191c6877SJoseph Chen 
166191c6877SJoseph Chen 	return 0;
167191c6877SJoseph Chen }
168191c6877SJoseph Chen 
uimage_sysmem_free_each(image_header_t * img,u32 ramdisk_sz)169a86a723eSJoseph Chen int uimage_sysmem_free_each(image_header_t *img, u32 ramdisk_sz)
170191c6877SJoseph Chen {
171191c6877SJoseph Chen 	ulong raddr, kaddr, faddr;
172191c6877SJoseph Chen 
173191c6877SJoseph Chen 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
174191c6877SJoseph Chen 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
175191c6877SJoseph Chen 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
176191c6877SJoseph Chen 
177191c6877SJoseph Chen 	sysmem_free((phys_addr_t)img);
178191c6877SJoseph Chen 	sysmem_free((phys_addr_t)kaddr);
179191c6877SJoseph Chen 	sysmem_free((phys_addr_t)faddr);
180a86a723eSJoseph Chen 	if (ramdisk_sz)
181a86a723eSJoseph Chen 		sysmem_free((phys_addr_t)raddr);
182191c6877SJoseph Chen 
183191c6877SJoseph Chen 	return 0;
184191c6877SJoseph Chen }
185191c6877SJoseph Chen 
1866ea28a6cSJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
uimage_init_resource(struct blk_desc * dev_desc)187*63f38f9dSJoseph Chen int uimage_init_resource(struct blk_desc *dev_desc)
188191c6877SJoseph Chen {
189191c6877SJoseph Chen 	disk_partition_t part;
190*63f38f9dSJoseph Chen 	ulong data, offset, size;
191191c6877SJoseph Chen 	image_header_t *hdr;
1926ea28a6cSJoseph Chen 	char *part_name = PART_BOOT;
193*63f38f9dSJoseph Chen 	int ret, idx = 3;
194*63f38f9dSJoseph Chen 	void *buf;
195191c6877SJoseph Chen 
1966ea28a6cSJoseph Chen 	if (!dev_desc)
197*63f38f9dSJoseph Chen 		return -ENODEV;
198191c6877SJoseph Chen 
1996ea28a6cSJoseph Chen #ifndef CONFIG_ANDROID_AB
200191c6877SJoseph Chen 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
201191c6877SJoseph Chen 		part_name = PART_RECOVERY;
2026ea28a6cSJoseph Chen #endif
203191c6877SJoseph Chen 	if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
204191c6877SJoseph Chen 		UIMG_I("No %s partition\n", part_name);
205191c6877SJoseph Chen 		return -ENODEV;
206191c6877SJoseph Chen 	}
207191c6877SJoseph Chen 
208191c6877SJoseph Chen 	hdr = uimage_get_hdr(dev_desc, &part);
209191c6877SJoseph Chen 	if (!hdr)
210*63f38f9dSJoseph Chen 		return -EAGAIN;
211191c6877SJoseph Chen 
212*63f38f9dSJoseph Chen 	image_multi_getimg(hdr, idx, &data, &size);
213*63f38f9dSJoseph Chen 	offset = data - (ulong)hdr;
214191c6877SJoseph Chen 	free(hdr);
215191c6877SJoseph Chen 
216*63f38f9dSJoseph Chen 	buf = memalign(ARCH_DMA_MINALIGN, ALIGN(size, dev_desc->blksz));
217*63f38f9dSJoseph Chen 	if (!buf)
218*63f38f9dSJoseph Chen 		return -ENOMEM;
219*63f38f9dSJoseph Chen 
220*63f38f9dSJoseph Chen 	printf("RESC: '%s', blk@0x%08lx\n", part.name,
221*63f38f9dSJoseph Chen 	       part.start + (offset / dev_desc->blksz));
222*63f38f9dSJoseph Chen 	ret = uimage_load_one(dev_desc, &part, offset, size, buf);
223*63f38f9dSJoseph Chen 	if (ret)
224*63f38f9dSJoseph Chen 		return ret;
225*63f38f9dSJoseph Chen 
226*63f38f9dSJoseph Chen 	ret = resource_setup_ram_list(dev_desc, buf);
227*63f38f9dSJoseph Chen 	if (ret) {
228*63f38f9dSJoseph Chen 		UIMG_I("Failed to setup resource ram list, ret=%d\n", ret);
229*63f38f9dSJoseph Chen 		return ret;
230*63f38f9dSJoseph Chen 	}
231191c6877SJoseph Chen 
232191c6877SJoseph Chen 	return 0;
233191c6877SJoseph Chen }
2346ea28a6cSJoseph Chen #endif
235