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