1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 #include <common.h> 6 #include <amp.h> 7 #include <boot_rkimg.h> 8 #include <bidram.h> 9 #include <dm.h> 10 #include <sysmem.h> 11 #include <asm/arch/rockchip_smccc.h> 12 13 #define AMP_I(fmt, args...) printf("AMP: "fmt, ##args) 14 #define AMP_E(fmt, args...) printf("AMP Error: "fmt, ##args) 15 16 /* 17 * non-OTA packaged kernel.img & boot.img return the image size on success, 18 * and a negative value on error. 19 */ 20 static int read_rockchip_image(struct blk_desc *dev_desc, 21 disk_partition_t *part, void *dst) 22 { 23 struct rockchip_image *img; 24 int header_len = 8; 25 int cnt, ret; 26 #ifdef CONFIG_ROCKCHIP_CRC 27 u32 crc32; 28 #endif 29 30 img = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 31 if (!img) 32 return -ENOMEM; 33 34 /* read first block with header imformation */ 35 ret = blk_dread(dev_desc, part->start, 1, img); 36 if (ret != 1) { 37 ret = -EIO; 38 goto err; 39 } 40 41 if (img->tag != TAG_KERNEL) { 42 printf("Invalid %s image tag(0x%x)\n", part->name, img->tag); 43 ret = -EINVAL; 44 goto err; 45 } 46 47 /* 48 * read the rest blks 49 * total size = image size + 8 bytes header + 4 bytes crc32 50 */ 51 cnt = DIV_ROUND_UP(img->size + 8 + 4, RK_BLK_SIZE); 52 if (!sysmem_alloc_base_by_name((const char *)part->name, 53 (phys_addr_t)dst, 54 cnt * dev_desc->blksz)) { 55 ret = -ENXIO; 56 goto err; 57 } 58 59 memcpy(dst, img->image, RK_BLK_SIZE - header_len); 60 ret = blk_dread(dev_desc, part->start + 1, cnt - 1, 61 dst + RK_BLK_SIZE - header_len); 62 if (ret != (cnt - 1)) { 63 printf("Failed to read %s part, ret=%d\n", part->name, ret); 64 ret = -EIO; 65 } else { 66 ret = img->size; 67 } 68 69 #ifdef CONFIG_ROCKCHIP_CRC 70 printf("%s image rk crc32 verify... ", part->name); 71 crc32 = crc32_verify((uchar *)(ulong)dst, img->size + 4); 72 if (!crc32) { 73 printf("fail!\n"); 74 ret = -EINVAL; 75 } else { 76 printf("okay.\n"); 77 } 78 #endif 79 80 err: 81 free(img); 82 return ret; 83 } 84 85 /* 86 * An example for amps dts node configure: 87 * 88 * amps { 89 * compatible = "uboot,rockchip-amp"; 90 * status = "okay"; 91 * 92 * amp@0 { 93 * description = "mcu-os1"; 94 * partition = "mcu1"; 95 * cpu = <0x1>; // this is mpidr! 96 * aarch64 = <1>; // 0: aarch32, 1: aarch64 97 * thumb = <0>; // 0: arm, 1: thumb 98 * hyp = <1>; // 0: el1/svc, 1: el2/hyp 99 * secure = <0>; // 0: non-secure, 1: secure 100 * load = <0x800000>; 101 * entry = <0x800000>; 102 * memory = <0x800000 0x400000>; 103 * }; 104 * 105 * amp@1 { 106 * ...... 107 * }; 108 * 109 * ...... 110 * }; 111 * 112 * U-Boot load "mcu-os1" firmware to "0x800000" address from partiton 113 * "mcu1" for cpu[1] with ARM, aarch64, hyp(el2) and non-secure state, 114 * running on 0x800000. 115 * 116 * U-Boot reserve memory from 0x800000 with 0x400000 size in order 117 * to make it invisible for kernel. 118 * 119 * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: 120 * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img 121 */ 122 123 static int rockchip_amp_cpu_on(struct udevice *dev) 124 { 125 struct dm_amp_uclass_platdata *uc_pdata; 126 struct blk_desc *dev_desc; 127 disk_partition_t part_info; 128 int ret, size; 129 u32 pe_state; 130 131 uc_pdata = dev_get_uclass_platdata(dev); 132 if (!uc_pdata) 133 return -ENXIO; 134 135 dev_desc = rockchip_get_bootdev(); 136 if (!dev_desc) 137 return -EEXIST; 138 139 ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); 140 if (ret < 0) { 141 AMP_E("\"%s\" find partition \"%s\" failed\n", 142 uc_pdata->desc, uc_pdata->partition); 143 return ret; 144 } 145 146 if (uc_pdata->reserved_mem[1]) { 147 ret = bidram_reserve_by_name(uc_pdata->partition, 148 uc_pdata->reserved_mem[0], 149 uc_pdata->reserved_mem[1]); 150 if (ret) { 151 AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 152 uc_pdata->desc, uc_pdata->reserved_mem[0], 153 uc_pdata->reserved_mem[0] + 154 uc_pdata->reserved_mem[1], ret); 155 return -ENOMEM; 156 } 157 } 158 159 size = read_rockchip_image(dev_desc, &part_info, 160 (void *)(ulong)uc_pdata->load); 161 if (size < 0) { 162 AMP_E("\"%s\" load at 0x%08x failed\n", 163 uc_pdata->desc, uc_pdata->load); 164 return size; 165 } 166 167 flush_dcache_range(uc_pdata->load, 168 uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); 169 170 pe_state = PE_STATE(uc_pdata->aarch64, uc_pdata->hyp, 171 uc_pdata->thumb, uc_pdata->secure); 172 173 AMP_I("Brought up cpu[%x] with state(%x) from \"%s\" entry 0x%08x ...", 174 uc_pdata->cpu, pe_state, uc_pdata->desc, uc_pdata->entry); 175 176 sip_smc_amp_cfg(AMP_PE_STATE, uc_pdata->cpu, pe_state); 177 ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); 178 if (ret) { 179 printf("failed\n"); 180 return ret; 181 } 182 printf("OK\n"); 183 184 return 0; 185 } 186 187 static const struct dm_amp_ops rockchip_amp_ops = { 188 .cpu_on = rockchip_amp_cpu_on, 189 }; 190 191 U_BOOT_DRIVER(rockchip_amp) = { 192 .name = "rockchip_amp", 193 .id = UCLASS_AMP, 194 .ops = &rockchip_amp_ops, 195 }; 196 197 /* AMP bus driver as all amp parent */ 198 static int rockchip_amp_bus_bind(struct udevice *dev) 199 { 200 return amp_bind_children(dev, "rockchip_amp"); 201 } 202 203 static const struct udevice_id rockchip_amp_bus_match[] = { 204 { .compatible = "uboot,rockchip-amp", }, 205 {}, 206 }; 207 208 U_BOOT_DRIVER(rockchip_amp_bus) = { 209 .name = "rockchip_amp_bus", 210 .id = UCLASS_SIMPLE_BUS, 211 .of_match = rockchip_amp_bus_match, 212 .bind = rockchip_amp_bus_bind, 213 }; 214