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