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> 12*39be8a08SJoseph Chen #include <asm/u-boot-arm.h> 134388decaSJoseph Chen 144388decaSJoseph Chen #define AMP_I(fmt, args...) printf("AMP: "fmt, ##args) 154388decaSJoseph Chen #define AMP_E(fmt, args...) printf("AMP Error: "fmt, ##args) 164388decaSJoseph Chen 174388decaSJoseph Chen /* 180df2c3dfSJoseph Chen * non-OTA packaged kernel.img & boot.img return the image size on success, 190df2c3dfSJoseph Chen * and a negative value on error. 200df2c3dfSJoseph Chen */ 210df2c3dfSJoseph Chen static int read_rockchip_image(struct blk_desc *dev_desc, 220df2c3dfSJoseph Chen disk_partition_t *part, void *dst) 230df2c3dfSJoseph Chen { 240df2c3dfSJoseph Chen struct rockchip_image *img; 250df2c3dfSJoseph Chen int header_len = 8; 260df2c3dfSJoseph Chen int cnt, ret; 270df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC 280df2c3dfSJoseph Chen u32 crc32; 290df2c3dfSJoseph Chen #endif 300df2c3dfSJoseph Chen 310df2c3dfSJoseph Chen img = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 320df2c3dfSJoseph Chen if (!img) 330df2c3dfSJoseph Chen return -ENOMEM; 340df2c3dfSJoseph Chen 350df2c3dfSJoseph Chen /* read first block with header imformation */ 360df2c3dfSJoseph Chen ret = blk_dread(dev_desc, part->start, 1, img); 370df2c3dfSJoseph Chen if (ret != 1) { 380df2c3dfSJoseph Chen ret = -EIO; 390df2c3dfSJoseph Chen goto err; 400df2c3dfSJoseph Chen } 410df2c3dfSJoseph Chen 420df2c3dfSJoseph Chen if (img->tag != TAG_KERNEL) { 430df2c3dfSJoseph Chen printf("Invalid %s image tag(0x%x)\n", part->name, img->tag); 440df2c3dfSJoseph Chen ret = -EINVAL; 450df2c3dfSJoseph Chen goto err; 460df2c3dfSJoseph Chen } 470df2c3dfSJoseph Chen 480df2c3dfSJoseph Chen /* 490df2c3dfSJoseph Chen * read the rest blks 500df2c3dfSJoseph Chen * total size = image size + 8 bytes header + 4 bytes crc32 510df2c3dfSJoseph Chen */ 520df2c3dfSJoseph Chen cnt = DIV_ROUND_UP(img->size + 8 + 4, RK_BLK_SIZE); 530df2c3dfSJoseph Chen if (!sysmem_alloc_base_by_name((const char *)part->name, 540df2c3dfSJoseph Chen (phys_addr_t)dst, 550df2c3dfSJoseph Chen cnt * dev_desc->blksz)) { 560df2c3dfSJoseph Chen ret = -ENXIO; 570df2c3dfSJoseph Chen goto err; 580df2c3dfSJoseph Chen } 590df2c3dfSJoseph Chen 600df2c3dfSJoseph Chen memcpy(dst, img->image, RK_BLK_SIZE - header_len); 610df2c3dfSJoseph Chen ret = blk_dread(dev_desc, part->start + 1, cnt - 1, 620df2c3dfSJoseph Chen dst + RK_BLK_SIZE - header_len); 630df2c3dfSJoseph Chen if (ret != (cnt - 1)) { 640df2c3dfSJoseph Chen printf("Failed to read %s part, ret=%d\n", part->name, ret); 650df2c3dfSJoseph Chen ret = -EIO; 660df2c3dfSJoseph Chen } else { 670df2c3dfSJoseph Chen ret = img->size; 680df2c3dfSJoseph Chen } 690df2c3dfSJoseph Chen 700df2c3dfSJoseph Chen #ifdef CONFIG_ROCKCHIP_CRC 710df2c3dfSJoseph Chen printf("%s image rk crc32 verify... ", part->name); 720df2c3dfSJoseph Chen crc32 = crc32_verify((uchar *)(ulong)dst, img->size + 4); 730df2c3dfSJoseph Chen if (!crc32) { 740df2c3dfSJoseph Chen printf("fail!\n"); 750df2c3dfSJoseph Chen ret = -EINVAL; 760df2c3dfSJoseph Chen } else { 770df2c3dfSJoseph Chen printf("okay.\n"); 780df2c3dfSJoseph Chen } 790df2c3dfSJoseph Chen #endif 800df2c3dfSJoseph Chen 810df2c3dfSJoseph Chen err: 820df2c3dfSJoseph Chen free(img); 830df2c3dfSJoseph Chen return ret; 840df2c3dfSJoseph Chen } 850df2c3dfSJoseph Chen 860df2c3dfSJoseph Chen /* 874388decaSJoseph Chen * An example for amps dts node configure: 884388decaSJoseph Chen * 894388decaSJoseph Chen * amps { 904388decaSJoseph Chen * compatible = "uboot,rockchip-amp"; 914388decaSJoseph Chen * status = "okay"; 924388decaSJoseph Chen * 934388decaSJoseph Chen * amp@0 { 944388decaSJoseph Chen * description = "mcu-os1"; 954388decaSJoseph Chen * partition = "mcu1"; 964388decaSJoseph Chen * cpu = <0x1>; // this is mpidr! 97f06413e4SJoseph Chen * aarch64 = <1>; // 0: aarch32, 1: aarch64 98f06413e4SJoseph Chen * thumb = <0>; // 0: arm, 1: thumb 99f06413e4SJoseph Chen * hyp = <1>; // 0: el1/svc, 1: el2/hyp 100f06413e4SJoseph Chen * secure = <0>; // 0: non-secure, 1: secure 1014388decaSJoseph Chen * load = <0x800000>; 1024388decaSJoseph Chen * entry = <0x800000>; 1034388decaSJoseph Chen * memory = <0x800000 0x400000>; 1044388decaSJoseph Chen * }; 1054388decaSJoseph Chen * 1064388decaSJoseph Chen * amp@1 { 1074388decaSJoseph Chen * ...... 1084388decaSJoseph Chen * }; 1094388decaSJoseph Chen * 1104388decaSJoseph Chen * ...... 1114388decaSJoseph Chen * }; 1124388decaSJoseph Chen * 113f06413e4SJoseph Chen * U-Boot load "mcu-os1" firmware to "0x800000" address from partiton 114f06413e4SJoseph Chen * "mcu1" for cpu[1] with ARM, aarch64, hyp(el2) and non-secure state, 115f06413e4SJoseph Chen * running on 0x800000. 116f06413e4SJoseph Chen * 1174388decaSJoseph Chen * U-Boot reserve memory from 0x800000 with 0x400000 size in order 1184388decaSJoseph Chen * to make it invisible for kernel. 1194388decaSJoseph Chen * 1204388decaSJoseph Chen * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: 1214388decaSJoseph Chen * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img 1224388decaSJoseph Chen */ 1234388decaSJoseph Chen 124*39be8a08SJoseph Chen static int rockchip_amp_cpu_on(struct udevice *dev, bool this_cpu) 1254388decaSJoseph Chen { 1264388decaSJoseph Chen struct dm_amp_uclass_platdata *uc_pdata; 1274388decaSJoseph Chen struct blk_desc *dev_desc; 1284388decaSJoseph Chen disk_partition_t part_info; 1294388decaSJoseph Chen int ret, size; 130f06413e4SJoseph Chen u32 pe_state; 131*39be8a08SJoseph Chen u32 es_to_aarch; 1324388decaSJoseph Chen 1334388decaSJoseph Chen uc_pdata = dev_get_uclass_platdata(dev); 1344388decaSJoseph Chen if (!uc_pdata) 1354388decaSJoseph Chen return -ENXIO; 1364388decaSJoseph Chen 1374388decaSJoseph Chen dev_desc = rockchip_get_bootdev(); 1384388decaSJoseph Chen if (!dev_desc) 1394388decaSJoseph Chen return -EEXIST; 1404388decaSJoseph Chen 1414388decaSJoseph Chen ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); 1424388decaSJoseph Chen if (ret < 0) { 1434388decaSJoseph Chen AMP_E("\"%s\" find partition \"%s\" failed\n", 1444388decaSJoseph Chen uc_pdata->desc, uc_pdata->partition); 1454388decaSJoseph Chen return ret; 1464388decaSJoseph Chen } 1474388decaSJoseph Chen 148f06413e4SJoseph Chen if (uc_pdata->reserved_mem[1]) { 1494388decaSJoseph Chen ret = bidram_reserve_by_name(uc_pdata->partition, 1504388decaSJoseph Chen uc_pdata->reserved_mem[0], 1514388decaSJoseph Chen uc_pdata->reserved_mem[1]); 1524388decaSJoseph Chen if (ret) { 1534388decaSJoseph Chen AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 1544388decaSJoseph Chen uc_pdata->desc, uc_pdata->reserved_mem[0], 155f06413e4SJoseph Chen uc_pdata->reserved_mem[0] + 156f06413e4SJoseph Chen uc_pdata->reserved_mem[1], ret); 1574388decaSJoseph Chen return -ENOMEM; 1584388decaSJoseph Chen } 159f06413e4SJoseph Chen } 1604388decaSJoseph Chen 1614388decaSJoseph Chen size = read_rockchip_image(dev_desc, &part_info, 1624388decaSJoseph Chen (void *)(ulong)uc_pdata->load); 1634388decaSJoseph Chen if (size < 0) { 1644388decaSJoseph Chen AMP_E("\"%s\" load at 0x%08x failed\n", 1654388decaSJoseph Chen uc_pdata->desc, uc_pdata->load); 1664388decaSJoseph Chen return size; 1674388decaSJoseph Chen } 1684388decaSJoseph Chen 1694388decaSJoseph Chen flush_dcache_range(uc_pdata->load, 1704388decaSJoseph Chen uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); 1714388decaSJoseph Chen 172f06413e4SJoseph Chen pe_state = PE_STATE(uc_pdata->aarch64, uc_pdata->hyp, 173f06413e4SJoseph Chen uc_pdata->thumb, uc_pdata->secure); 1744388decaSJoseph Chen 175*39be8a08SJoseph Chen if (this_cpu) { 176*39be8a08SJoseph Chen AMP_I("Brought up cpu[%x] from \"%s\" with state 0x%x, entry 0x%08x ...", 177*39be8a08SJoseph Chen uc_pdata->cpu, uc_pdata->desc, pe_state, uc_pdata->entry); 178f06413e4SJoseph Chen 179*39be8a08SJoseph Chen cleanup_before_linux(); 180*39be8a08SJoseph Chen es_to_aarch = uc_pdata->aarch64 ? ES_TO_AARCH64 : ES_TO_AARCH32; 181*39be8a08SJoseph Chen printf("OK\n"); 182*39be8a08SJoseph Chen armv8_switch_to_el2(0, 0, 0, pe_state, (u64)uc_pdata->entry, es_to_aarch); 183*39be8a08SJoseph Chen } else { 184*39be8a08SJoseph Chen AMP_I("Brought up cpu[%x] from \"%s\" with state 0x%x, entry 0x%08x ...", 185*39be8a08SJoseph Chen uc_pdata->cpu, uc_pdata->desc, pe_state, uc_pdata->entry); 186*39be8a08SJoseph Chen 187*39be8a08SJoseph Chen ret = sip_smc_amp_cfg(AMP_PE_STATE, uc_pdata->cpu, pe_state); 188*39be8a08SJoseph Chen if (ret) { 189*39be8a08SJoseph Chen printf("amp cfg failed, ret=%d\n", ret); 190*39be8a08SJoseph Chen return ret; 191*39be8a08SJoseph Chen } 1924388decaSJoseph Chen ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); 1934388decaSJoseph Chen if (ret) { 194*39be8a08SJoseph Chen printf("cpu up failed, ret=%d\n", ret); 1954388decaSJoseph Chen return ret; 1964388decaSJoseph Chen } 1974388decaSJoseph Chen printf("OK\n"); 198*39be8a08SJoseph Chen } 1994388decaSJoseph Chen 2004388decaSJoseph Chen return 0; 2014388decaSJoseph Chen } 2024388decaSJoseph Chen 2034388decaSJoseph Chen static const struct dm_amp_ops rockchip_amp_ops = { 2044388decaSJoseph Chen .cpu_on = rockchip_amp_cpu_on, 2054388decaSJoseph Chen }; 2064388decaSJoseph Chen 2074388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp) = { 2084388decaSJoseph Chen .name = "rockchip_amp", 2094388decaSJoseph Chen .id = UCLASS_AMP, 2104388decaSJoseph Chen .ops = &rockchip_amp_ops, 2114388decaSJoseph Chen }; 2124388decaSJoseph Chen 2134388decaSJoseph Chen /* AMP bus driver as all amp parent */ 2144388decaSJoseph Chen static int rockchip_amp_bus_bind(struct udevice *dev) 2154388decaSJoseph Chen { 2164388decaSJoseph Chen return amp_bind_children(dev, "rockchip_amp"); 2174388decaSJoseph Chen } 2184388decaSJoseph Chen 2194388decaSJoseph Chen static const struct udevice_id rockchip_amp_bus_match[] = { 2204388decaSJoseph Chen { .compatible = "uboot,rockchip-amp", }, 2214388decaSJoseph Chen {}, 2224388decaSJoseph Chen }; 2234388decaSJoseph Chen 2244388decaSJoseph Chen U_BOOT_DRIVER(rockchip_amp_bus) = { 2254388decaSJoseph Chen .name = "rockchip_amp_bus", 2264388decaSJoseph Chen .id = UCLASS_SIMPLE_BUS, 2274388decaSJoseph Chen .of_match = rockchip_amp_bus_match, 2284388decaSJoseph Chen .bind = rockchip_amp_bus_bind, 2294388decaSJoseph Chen }; 230