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 * load = <0x800000>; 97 * entry = <0x800000>; 98 * memory = <0x800000 0x400000>; 99 * }; 100 * 101 * amp@1 { 102 * ...... 103 * }; 104 * 105 * ...... 106 * }; 107 * 108 * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton 109 * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And 110 * U-Boot reserve memory from 0x800000 with 0x400000 size in order 111 * to make it invisible for kernel. 112 * 113 * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: 114 * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img 115 */ 116 117 static int rockchip_amp_cpu_on(struct udevice *dev) 118 { 119 struct dm_amp_uclass_platdata *uc_pdata; 120 struct blk_desc *dev_desc; 121 disk_partition_t part_info; 122 int ret, size; 123 124 uc_pdata = dev_get_uclass_platdata(dev); 125 if (!uc_pdata) 126 return -ENXIO; 127 128 dev_desc = rockchip_get_bootdev(); 129 if (!dev_desc) 130 return -EEXIST; 131 132 ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); 133 if (ret < 0) { 134 AMP_E("\"%s\" find partition \"%s\" failed\n", 135 uc_pdata->desc, uc_pdata->partition); 136 return ret; 137 } 138 139 ret = bidram_reserve_by_name(uc_pdata->partition, 140 uc_pdata->reserved_mem[0], 141 uc_pdata->reserved_mem[1]); 142 if (ret) { 143 AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 144 uc_pdata->desc, uc_pdata->reserved_mem[0], 145 uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret); 146 return -ENOMEM; 147 } 148 149 size = read_rockchip_image(dev_desc, &part_info, 150 (void *)(ulong)uc_pdata->load); 151 if (size < 0) { 152 AMP_E("\"%s\" load at 0x%08x failed\n", 153 uc_pdata->desc, uc_pdata->load); 154 return size; 155 } 156 157 flush_dcache_range(uc_pdata->load, 158 uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); 159 160 AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...", 161 uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry); 162 163 ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); 164 if (ret) { 165 printf("failed\n"); 166 return ret; 167 } 168 printf("OK\n"); 169 170 return 0; 171 } 172 173 static const struct dm_amp_ops rockchip_amp_ops = { 174 .cpu_on = rockchip_amp_cpu_on, 175 }; 176 177 U_BOOT_DRIVER(rockchip_amp) = { 178 .name = "rockchip_amp", 179 .id = UCLASS_AMP, 180 .ops = &rockchip_amp_ops, 181 }; 182 183 /* AMP bus driver as all amp parent */ 184 static int rockchip_amp_bus_bind(struct udevice *dev) 185 { 186 return amp_bind_children(dev, "rockchip_amp"); 187 } 188 189 static const struct udevice_id rockchip_amp_bus_match[] = { 190 { .compatible = "uboot,rockchip-amp", }, 191 {}, 192 }; 193 194 U_BOOT_DRIVER(rockchip_amp_bus) = { 195 .name = "rockchip_amp_bus", 196 .id = UCLASS_SIMPLE_BUS, 197 .of_match = rockchip_amp_bus_match, 198 .bind = rockchip_amp_bus_bind, 199 }; 200