1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2021 Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <amp.h> 8 #include <bidram.h> 9 #include <boot_rkimg.h> 10 #include <sysmem.h> 11 #include <asm/arch/rockchip_smccc.h> 12 13 #define AMP_PART "amp" 14 15 static u32 primary_pe_arch; 16 static u32 primary_pe_state; 17 18 static u32 fit_get_u32_default(const void *fit, int noffset, 19 const char *prop, u32 def) 20 { 21 const fdt32_t *val; 22 23 val = fdt_getprop(fit, noffset, prop, NULL); 24 if (!val) 25 return def; 26 27 return fdt32_to_cpu(*val); 28 } 29 30 static int brought_up_all_amp(void *fit, const char *fit_uname_cfg) 31 { 32 const char *uname, *desc; 33 u32 cpu, aarch64, hyp; 34 u32 thumb, us, secure = 0; 35 u32 pe_state, entry, load; 36 u32 reserved_mem[2] = { 0, 0, }; 37 u32 primary_pe_entry = 0; 38 int primary_on_linux = 0; 39 int conf_noffset, noffset; 40 int loadables_index; 41 int data_size = -ENODATA; 42 u8 arch = -ENODATA; 43 int ret; 44 45 aarch64 = IS_ENABLED(CONFIG_ARM64) ? 1 : 0; 46 conf_noffset = fit_conf_get_node(fit, fit_uname_cfg); 47 for (loadables_index = 0; 48 uname = fdt_stringlist_get(fit, conf_noffset, 49 FIT_LOADABLE_PROP, loadables_index, NULL), uname; 50 loadables_index++) { 51 noffset = fit_image_get_node(fit, uname); 52 53 desc = fdt_getprop(fit, noffset, "description", NULL); 54 cpu = fit_get_u32_default(fit, noffset, "cpu", -ENODATA); 55 hyp = fit_get_u32_default(fit, noffset, "hyp", 0); 56 thumb = fit_get_u32_default(fit, noffset, "thumb", 0); 57 load = fit_get_u32_default(fit, noffset, "load", -ENODATA); 58 us = fit_get_u32_default(fit, noffset, "udelay", 0); 59 fit_image_get_arch(fit, noffset, &arch); 60 fit_image_get_data_size(fit, noffset, &data_size); 61 fdtdec_get_int_array(fit, noffset, "memory", reserved_mem, 2); 62 63 if (!desc || cpu == -ENODATA || data_size == -ENODATA || 64 load == -ENODATA || arch == -ENODATA) { 65 AMP_I("property missing!\n"); 66 return -EINVAL; 67 } 68 69 entry = load; 70 aarch64 = (arch == IH_ARCH_ARM) ? 0 : 1; 71 pe_state = PE_STATE(aarch64, hyp, thumb, secure); 72 73 #ifdef DEBUG 74 AMP_I(" pe_state: 0x%08x\n", pe_state); 75 AMP_I(" cpu: 0x%x\n", cpu); 76 AMP_I(" aarch64: %d\n", aarch64); 77 AMP_I(" hyp: %d\n", hyp); 78 AMP_I(" thumb: %d\n", thumb); 79 AMP_I(" secure: %d\n", secure); 80 AMP_I(" entry: 0x%08x\n", entry); 81 AMP_I(" mem: 0x%08x - 0x%08x\n\n", 82 reserved_mem[0], reserved_mem[0] + reserved_mem[1]); 83 #endif 84 if (!data_size) 85 continue; 86 87 if ((read_mpidr() & 0x0fff) == cpu) { 88 primary_pe_arch = arch; 89 primary_pe_state = pe_state; 90 primary_pe_entry = entry; 91 primary_on_linux = 92 !!fdt_getprop(fit, noffset, "linux-os", NULL); 93 continue; 94 } 95 96 if (reserved_mem[1]) { 97 ret = bidram_reserve_by_name(desc, reserved_mem[0], 98 reserved_mem[1]); 99 if (ret) { 100 AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n", 101 desc, reserved_mem[0], 102 reserved_mem[0] + reserved_mem[1], ret); 103 return -ENOMEM; 104 } 105 } else if (!sysmem_alloc_base_by_name(desc, 106 (phys_addr_t)load, data_size)) { 107 return -ENXIO; 108 } 109 110 AMP_I("Brought up cpu[%x] with state 0x%x, entry 0x%08x ...", 111 cpu, pe_state, entry); 112 113 ret = sip_smc_amp_cfg(AMP_PE_STATE, cpu, pe_state); 114 if (ret) { 115 printf("amp cfg failed, ret=%d\n", ret); 116 return ret; 117 } 118 119 ret = psci_cpu_on(cpu, entry); 120 if (ret) { 121 printf("cpu up failed, ret=%d\n", ret); 122 return ret; 123 } 124 printf("OK\n"); 125 if (us) 126 udelay(us); 127 } 128 129 if (!primary_on_linux && primary_pe_entry) { 130 flush_dcache_all(); 131 AMP_I("Brought up cpu[%x, self] with state 0x%x, entry 0x%08x ...", 132 (u32)read_mpidr() & 0x0fff, primary_pe_state, primary_pe_entry); 133 cleanup_before_linux(); 134 printf("OK\n"); 135 armv8_switch_to_el2(0, 0, 0, primary_pe_state, 136 (u64)primary_pe_entry, 137 aarch64 ? ES_TO_AARCH64 : ES_TO_AARCH32); 138 } 139 140 return ret; 141 } 142 143 int amp_cpus_on(void) 144 { 145 struct blk_desc *dev_desc; 146 bootm_headers_t images; 147 disk_partition_t part; 148 void *fit; 149 int ret = 0; 150 151 dev_desc = rockchip_get_bootdev(); 152 if (!dev_desc) 153 return -EIO; 154 155 if (part_get_info_by_name(dev_desc, AMP_PART, &part) < 0) 156 return -ENODEV; 157 158 fit = sysmem_alloc(MEM_FIT, part.size * part.blksz); 159 if (!fit) 160 return -ENOMEM; 161 162 if (blk_dread(dev_desc, part.start, part.size, fit) != part.size) { 163 ret = -EIO; 164 goto out; 165 } 166 167 if (fdt_check_header(fit)) { 168 printf("No fdt header\n"); 169 ret = -EINVAL; 170 goto out; 171 } 172 173 memset(&images, 0, sizeof(images)); 174 images.fit_uname_cfg = "conf"; 175 images.fit_hdr_os = fit; 176 images.verify = 1; 177 ret = boot_get_loadable(0, NULL, &images, 178 IH_ARCH_DEFAULT, NULL, NULL); 179 if (ret) { 180 AMP_E("Failed to load image, ret=%d\n", ret); 181 return ret; 182 } 183 184 /* flush */ 185 flush_dcache_all(); 186 187 ret = brought_up_all_amp(images.fit_hdr_os, images.fit_uname_cfg); 188 out: 189 sysmem_free((phys_addr_t)fit); 190 191 return ret; 192 } 193 194 int arm64_switch_amp_pe(bootm_headers_t *images) 195 { 196 images->os.arch = primary_pe_arch; 197 return primary_pe_state; 198 } 199 200