// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd */ #include #include #include #include #include #include #include #define AMP_I(fmt, args...) printf("AMP: "fmt, ##args) #define AMP_E(fmt, args...) printf("AMP Error: "fmt, ##args) /* * An example for amps dts node configure: * * amps { * compatible = "uboot,rockchip-amp"; * status = "okay"; * * amp@0 { * description = "mcu-os1"; * partition = "mcu1"; * cpu = <0x1>; // this is mpidr! * load = <0x800000>; * entry = <0x800000>; * memory = <0x800000 0x400000>; * }; * * amp@1 { * ...... * }; * * ...... * }; * * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And * U-Boot reserve memory from 0x800000 with 0x400000 size in order * to make it invisible for kernel. * * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img */ static int rockchip_amp_cpu_on(struct udevice *dev) { struct dm_amp_uclass_platdata *uc_pdata; struct blk_desc *dev_desc; disk_partition_t part_info; int ret, size; uc_pdata = dev_get_uclass_platdata(dev); if (!uc_pdata) return -ENXIO; dev_desc = rockchip_get_bootdev(); if (!dev_desc) return -EEXIST; ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); if (ret < 0) { AMP_E("\"%s\" find partition \"%s\" failed\n", uc_pdata->desc, uc_pdata->partition); return ret; } ret = bidram_reserve_by_name(uc_pdata->partition, uc_pdata->reserved_mem[0], uc_pdata->reserved_mem[1]); if (ret) { AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", uc_pdata->desc, uc_pdata->reserved_mem[0], uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret); return -ENOMEM; } size = read_rockchip_image(dev_desc, &part_info, (void *)(ulong)uc_pdata->load); if (size < 0) { AMP_E("\"%s\" load at 0x%08x failed\n", uc_pdata->desc, uc_pdata->load); return size; } flush_dcache_range(uc_pdata->load, uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...", uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry); ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); if (ret) { printf("failed\n"); return ret; } printf("OK\n"); return 0; } static const struct dm_amp_ops rockchip_amp_ops = { .cpu_on = rockchip_amp_cpu_on, }; U_BOOT_DRIVER(rockchip_amp) = { .name = "rockchip_amp", .id = UCLASS_AMP, .ops = &rockchip_amp_ops, }; /* AMP bus driver as all amp parent */ static int rockchip_amp_bus_bind(struct udevice *dev) { return amp_bind_children(dev, "rockchip_amp"); } static const struct udevice_id rockchip_amp_bus_match[] = { { .compatible = "uboot,rockchip-amp", }, {}, }; U_BOOT_DRIVER(rockchip_amp_bus) = { .name = "rockchip_amp_bus", .id = UCLASS_SIMPLE_BUS, .of_match = rockchip_amp_bus_match, .bind = rockchip_amp_bus_bind, };