14388decaSJoseph Chen // SPDX-License-Identifier: GPL-2.0 24388decaSJoseph Chen /* 34388decaSJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 44388decaSJoseph Chen */ 54388decaSJoseph Chen #include <common.h> 64388decaSJoseph Chen #include <amp.h> 74388decaSJoseph Chen #include <boot_rkimg.h> 84388decaSJoseph Chen #include <bidram.h> 94388decaSJoseph Chen #include <dm.h> 104388decaSJoseph Chen #include <sysmem.h> 114388decaSJoseph Chen #include <asm/arch/rockchip_smccc.h> 124388decaSJoseph Chen 134388decaSJoseph Chen #define AMP_I(fmt, args...) printf("AMP: "fmt, ##args) 144388decaSJoseph Chen #define AMP_E(fmt, args...) printf("AMP Error: "fmt, ##args) 154388decaSJoseph Chen 164388decaSJoseph Chen /* 17*0df2c3dfSJoseph Chen * non-OTA packaged kernel.img & boot.img return the image size on success, 18*0df2c3dfSJoseph Chen * and a negative value on error. 19*0df2c3dfSJoseph Chen */ 20*0df2c3dfSJoseph Chen static int read_rockchip_image(struct blk_desc *dev_desc, 21*0df2c3dfSJoseph Chen disk_partition_t *part, void *dst) 22*0df2c3dfSJoseph Chen { 23*0df2c3dfSJoseph Chen struct rockchip_image *img; 24*0df2c3dfSJoseph Chen int header_len = 8; 25*0df2c3dfSJoseph Chen int cnt, ret; 26*0df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC 27*0df2c3dfSJoseph Chen u32 crc32; 28*0df2c3dfSJoseph Chen #endif 29*0df2c3dfSJoseph Chen 30*0df2c3dfSJoseph Chen img = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 31*0df2c3dfSJoseph Chen if (!img) 32*0df2c3dfSJoseph Chen return -ENOMEM; 33*0df2c3dfSJoseph Chen 34*0df2c3dfSJoseph Chen /* read first block with header imformation */ 35*0df2c3dfSJoseph Chen ret = blk_dread(dev_desc, part->start, 1, img); 36*0df2c3dfSJoseph Chen if (ret != 1) { 37*0df2c3dfSJoseph Chen ret = -EIO; 38*0df2c3dfSJoseph Chen goto err; 39*0df2c3dfSJoseph Chen } 40*0df2c3dfSJoseph Chen 41*0df2c3dfSJoseph Chen if (img->tag != TAG_KERNEL) { 42*0df2c3dfSJoseph Chen printf("Invalid %s image tag(0x%x)\n", part->name, img->tag); 43*0df2c3dfSJoseph Chen ret = -EINVAL; 44*0df2c3dfSJoseph Chen goto err; 45*0df2c3dfSJoseph Chen } 46*0df2c3dfSJoseph Chen 47*0df2c3dfSJoseph Chen /* 48*0df2c3dfSJoseph Chen * read the rest blks 49*0df2c3dfSJoseph Chen * total size = image size + 8 bytes header + 4 bytes crc32 50*0df2c3dfSJoseph Chen */ 51*0df2c3dfSJoseph Chen cnt = DIV_ROUND_UP(img->size + 8 + 4, RK_BLK_SIZE); 52*0df2c3dfSJoseph Chen if (!sysmem_alloc_base_by_name((const char *)part->name, 53*0df2c3dfSJoseph Chen (phys_addr_t)dst, 54*0df2c3dfSJoseph Chen cnt * dev_desc->blksz)) { 55*0df2c3dfSJoseph Chen ret = -ENXIO; 56*0df2c3dfSJoseph Chen goto err; 57*0df2c3dfSJoseph Chen } 58*0df2c3dfSJoseph Chen 59*0df2c3dfSJoseph Chen memcpy(dst, img->image, RK_BLK_SIZE - header_len); 60*0df2c3dfSJoseph Chen ret = blk_dread(dev_desc, part->start + 1, cnt - 1, 61*0df2c3dfSJoseph Chen dst + RK_BLK_SIZE - header_len); 62*0df2c3dfSJoseph Chen if (ret != (cnt - 1)) { 63*0df2c3dfSJoseph Chen printf("Failed to read %s part, ret=%d\n", part->name, ret); 64*0df2c3dfSJoseph Chen ret = -EIO; 65*0df2c3dfSJoseph Chen } else { 66*0df2c3dfSJoseph Chen ret = img->size; 67*0df2c3dfSJoseph Chen } 68*0df2c3dfSJoseph Chen 69*0df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC 70*0df2c3dfSJoseph Chen printf("%s image rk crc32 verify... ", part->name); 71*0df2c3dfSJoseph Chen crc32 = crc32_verify((uchar *)(ulong)dst, img->size + 4); 72*0df2c3dfSJoseph Chen if (!crc32) { 73*0df2c3dfSJoseph Chen printf("fail!\n"); 74*0df2c3dfSJoseph Chen ret = -EINVAL; 75*0df2c3dfSJoseph Chen } else { 76*0df2c3dfSJoseph Chen printf("okay.\n"); 77*0df2c3dfSJoseph Chen } 78*0df2c3dfSJoseph Chen #endif 79*0df2c3dfSJoseph Chen 80*0df2c3dfSJoseph Chen err: 81*0df2c3dfSJoseph Chen free(img); 82*0df2c3dfSJoseph Chen return ret; 83*0df2c3dfSJoseph Chen } 84*0df2c3dfSJoseph Chen 85*0df2c3dfSJoseph Chen /* 864388decaSJoseph Chen * An example for amps dts node configure: 874388decaSJoseph Chen * 884388decaSJoseph Chen * amps { 894388decaSJoseph Chen * compatible = "uboot,rockchip-amp"; 904388decaSJoseph Chen * status = "okay"; 914388decaSJoseph Chen * 924388decaSJoseph Chen * amp@0 { 934388decaSJoseph Chen * description = "mcu-os1"; 944388decaSJoseph Chen * partition = "mcu1"; 954388decaSJoseph Chen * cpu = <0x1>; // this is mpidr! 964388decaSJoseph Chen * load = <0x800000>; 974388decaSJoseph Chen * entry = <0x800000>; 984388decaSJoseph Chen * memory = <0x800000 0x400000>; 994388decaSJoseph Chen * }; 1004388decaSJoseph Chen * 1014388decaSJoseph Chen * amp@1 { 1024388decaSJoseph Chen * ...... 1034388decaSJoseph Chen * }; 1044388decaSJoseph Chen * 1054388decaSJoseph Chen * ...... 1064388decaSJoseph Chen * }; 1074388decaSJoseph Chen * 1084388decaSJoseph Chen * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton 1094388decaSJoseph Chen * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And 1104388decaSJoseph Chen * U-Boot reserve memory from 0x800000 with 0x400000 size in order 1114388decaSJoseph Chen * to make it invisible for kernel. 1124388decaSJoseph Chen * 1134388decaSJoseph Chen * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: 1144388decaSJoseph Chen * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img 1154388decaSJoseph Chen */ 1164388decaSJoseph Chen 1174388decaSJoseph Chen static int rockchip_amp_cpu_on(struct udevice *dev) 1184388decaSJoseph Chen { 1194388decaSJoseph Chen struct dm_amp_uclass_platdata *uc_pdata; 1204388decaSJoseph Chen struct blk_desc *dev_desc; 1214388decaSJoseph Chen disk_partition_t part_info; 1224388decaSJoseph Chen int ret, size; 1234388decaSJoseph Chen 1244388decaSJoseph Chen uc_pdata = dev_get_uclass_platdata(dev); 1254388decaSJoseph Chen if (!uc_pdata) 1264388decaSJoseph Chen return -ENXIO; 1274388decaSJoseph Chen 1284388decaSJoseph Chen dev_desc = rockchip_get_bootdev(); 1294388decaSJoseph Chen if (!dev_desc) 1304388decaSJoseph Chen return -EEXIST; 1314388decaSJoseph Chen 1324388decaSJoseph Chen ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); 1334388decaSJoseph Chen if (ret < 0) { 1344388decaSJoseph Chen AMP_E("\"%s\" find partition \"%s\" failed\n", 1354388decaSJoseph Chen uc_pdata->desc, uc_pdata->partition); 1364388decaSJoseph Chen return ret; 1374388decaSJoseph Chen } 1384388decaSJoseph Chen 1394388decaSJoseph Chen ret = bidram_reserve_by_name(uc_pdata->partition, 1404388decaSJoseph Chen uc_pdata->reserved_mem[0], 1414388decaSJoseph Chen uc_pdata->reserved_mem[1]); 1424388decaSJoseph Chen if (ret) { 1434388decaSJoseph Chen AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 1444388decaSJoseph Chen uc_pdata->desc, uc_pdata->reserved_mem[0], 1454388decaSJoseph Chen uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret); 1464388decaSJoseph Chen return -ENOMEM; 1474388decaSJoseph Chen } 1484388decaSJoseph Chen 1494388decaSJoseph Chen size = read_rockchip_image(dev_desc, &part_info, 1504388decaSJoseph Chen (void *)(ulong)uc_pdata->load); 1514388decaSJoseph Chen if (size < 0) { 1524388decaSJoseph Chen AMP_E("\"%s\" load at 0x%08x failed\n", 1534388decaSJoseph Chen uc_pdata->desc, uc_pdata->load); 1544388decaSJoseph Chen return size; 1554388decaSJoseph Chen } 1564388decaSJoseph Chen 1574388decaSJoseph Chen flush_dcache_range(uc_pdata->load, 1584388decaSJoseph Chen uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); 1594388decaSJoseph Chen 1604388decaSJoseph Chen AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...", 1614388decaSJoseph Chen uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry); 1624388decaSJoseph Chen 1634388decaSJoseph Chen ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); 1644388decaSJoseph Chen if (ret) { 1654388decaSJoseph Chen printf("failed\n"); 1664388decaSJoseph Chen return ret; 1674388decaSJoseph Chen } 1684388decaSJoseph Chen printf("OK\n"); 1694388decaSJoseph Chen 1704388decaSJoseph Chen return 0; 1714388decaSJoseph Chen } 1724388decaSJoseph Chen 1734388decaSJoseph Chen static const struct dm_amp_ops rockchip_amp_ops = { 1744388decaSJoseph Chen .cpu_on = rockchip_amp_cpu_on, 1754388decaSJoseph Chen }; 1764388decaSJoseph Chen 1774388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp) = { 1784388decaSJoseph Chen .name = "rockchip_amp", 1794388decaSJoseph Chen .id = UCLASS_AMP, 1804388decaSJoseph Chen .ops = &rockchip_amp_ops, 1814388decaSJoseph Chen }; 1824388decaSJoseph Chen 1834388decaSJoseph Chen /* AMP bus driver as all amp parent */ 1844388decaSJoseph Chen static int rockchip_amp_bus_bind(struct udevice *dev) 1854388decaSJoseph Chen { 1864388decaSJoseph Chen return amp_bind_children(dev, "rockchip_amp"); 1874388decaSJoseph Chen } 1884388decaSJoseph Chen 1894388decaSJoseph Chen static const struct udevice_id rockchip_amp_bus_match[] = { 1904388decaSJoseph Chen { .compatible = "uboot,rockchip-amp", }, 1914388decaSJoseph Chen {}, 1924388decaSJoseph Chen }; 1934388decaSJoseph Chen 1944388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp_bus) = { 1954388decaSJoseph Chen .name = "rockchip_amp_bus", 1964388decaSJoseph Chen .id = UCLASS_SIMPLE_BUS, 1974388decaSJoseph Chen .of_match = rockchip_amp_bus_match, 1984388decaSJoseph Chen .bind = rockchip_amp_bus_bind, 1994388decaSJoseph Chen }; 200