xref: /rk3399_rockchip-uboot/drivers/cpu/rockchip_amp.c (revision f36ea2f6e17621c4d9dd97c4dbfab62d03d061df)
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