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 * An example for amps dts node configure: 18 * 19 * amps { 20 * compatible = "uboot,rockchip-amp"; 21 * status = "okay"; 22 * 23 * amp@0 { 24 * description = "mcu-os1"; 25 * partition = "mcu1"; 26 * cpu = <0x1>; // this is mpidr! 27 * load = <0x800000>; 28 * entry = <0x800000>; 29 * memory = <0x800000 0x400000>; 30 * }; 31 * 32 * amp@1 { 33 * ...... 34 * }; 35 * 36 * ...... 37 * }; 38 * 39 * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton 40 * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And 41 * U-Boot reserve memory from 0x800000 with 0x400000 size in order 42 * to make it invisible for kernel. 43 * 44 * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example: 45 * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img 46 */ 47 48 static int rockchip_amp_cpu_on(struct udevice *dev) 49 { 50 struct dm_amp_uclass_platdata *uc_pdata; 51 struct blk_desc *dev_desc; 52 disk_partition_t part_info; 53 int ret, size; 54 55 uc_pdata = dev_get_uclass_platdata(dev); 56 if (!uc_pdata) 57 return -ENXIO; 58 59 dev_desc = rockchip_get_bootdev(); 60 if (!dev_desc) 61 return -EEXIST; 62 63 ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info); 64 if (ret < 0) { 65 AMP_E("\"%s\" find partition \"%s\" failed\n", 66 uc_pdata->desc, uc_pdata->partition); 67 return ret; 68 } 69 70 ret = bidram_reserve_by_name(uc_pdata->partition, 71 uc_pdata->reserved_mem[0], 72 uc_pdata->reserved_mem[1]); 73 if (ret) { 74 AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 75 uc_pdata->desc, uc_pdata->reserved_mem[0], 76 uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret); 77 return -ENOMEM; 78 } 79 80 size = read_rockchip_image(dev_desc, &part_info, 81 (void *)(ulong)uc_pdata->load); 82 if (size < 0) { 83 AMP_E("\"%s\" load at 0x%08x failed\n", 84 uc_pdata->desc, uc_pdata->load); 85 return size; 86 } 87 88 flush_dcache_range(uc_pdata->load, 89 uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN)); 90 91 AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...", 92 uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry); 93 94 ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry); 95 if (ret) { 96 printf("failed\n"); 97 return ret; 98 } 99 printf("OK\n"); 100 101 return 0; 102 } 103 104 static const struct dm_amp_ops rockchip_amp_ops = { 105 .cpu_on = rockchip_amp_cpu_on, 106 }; 107 108 U_BOOT_DRIVER(rockchip_amp) = { 109 .name = "rockchip_amp", 110 .id = UCLASS_AMP, 111 .ops = &rockchip_amp_ops, 112 }; 113 114 /* AMP bus driver as all amp parent */ 115 static int rockchip_amp_bus_bind(struct udevice *dev) 116 { 117 return amp_bind_children(dev, "rockchip_amp"); 118 } 119 120 static const struct udevice_id rockchip_amp_bus_match[] = { 121 { .compatible = "uboot,rockchip-amp", }, 122 {}, 123 }; 124 125 U_BOOT_DRIVER(rockchip_amp_bus) = { 126 .name = "rockchip_amp_bus", 127 .id = UCLASS_SIMPLE_BUS, 128 .of_match = rockchip_amp_bus_match, 129 .bind = rockchip_amp_bus_bind, 130 }; 131