"Das U-Boot" Source Tree
at master 353 lines 8.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2019, 2024 NXP 4 */ 5 6#include <cpu.h> 7#include <dm.h> 8#include <thermal.h> 9#include <asm/global_data.h> 10#include <asm/ptrace.h> 11#include <asm/system.h> 12#include <firmware/imx/sci/sci.h> 13#include <asm/arch/sys_proto.h> 14#include <asm/arch-imx/cpu.h> 15#include <asm/armv8/cpu.h> 16#include <imx_thermal.h> 17#include <linux/bitops.h> 18#include <linux/clk-provider.h> 19#include <linux/psci.h> 20 21DECLARE_GLOBAL_DATA_PTR; 22 23#define IMX_REV_LEN 4 24struct cpu_imx_plat { 25 const char *name; 26 const char *type; 27 char rev[IMX_REV_LEN]; 28 u32 cpu_rsrc; 29 u32 cpurev; 30 u32 freq_mhz; 31 u32 mpidr; 32}; 33 34static const char *get_imx_type_str(u32 imxtype) 35{ 36 switch (imxtype) { 37 case MXC_CPU_IMX8MM: 38 return "8MM"; 39 case MXC_CPU_IMX8MN: 40 return "8MN"; 41 case MXC_CPU_IMX8MP: 42 return "8MP"; 43 case MXC_CPU_IMX8QXP: 44 case MXC_CPU_IMX8QXP_A0: 45 return "8QXP"; 46 case MXC_CPU_IMX8QM: 47 return "8QM"; 48 case MXC_CPU_IMX93: 49 return "93(52)";/* iMX93 Dual core with NPU */ 50 case MXC_CPU_IMX9351: 51 return "93(51)";/* iMX93 Single core with NPU */ 52 case MXC_CPU_IMX9332: 53 return "93(32)";/* iMX93 Dual core without NPU */ 54 case MXC_CPU_IMX9331: 55 return "93(31)";/* iMX93 Single core without NPU */ 56 case MXC_CPU_IMX9322: 57 return "93(22)";/* iMX93 9x9 Dual core */ 58 case MXC_CPU_IMX9321: 59 return "93(21)";/* iMX93 9x9 Single core */ 60 case MXC_CPU_IMX9312: 61 return "93(12)";/* iMX93 9x9 Dual core without NPU */ 62 case MXC_CPU_IMX9311: 63 return "93(11)";/* iMX93 9x9 Single core without NPU */ 64 case MXC_CPU_IMX9302: 65 return "93(02)";/* iMX93 900Mhz Low performance Dual core without NPU */ 66 case MXC_CPU_IMX9301: 67 return "93(01)";/* iMX93 900Mhz Low performance Single core without NPU */ 68 case MXC_CPU_IMX91: 69 return "91(31)";/* iMX91 11x11 Full feature */ 70 case MXC_CPU_IMX9121: 71 return "91(21)";/* iMX91 11x11 Low drive mode */ 72 case MXC_CPU_IMX9111: 73 return "91(11)";/* iMX91 9x9 Reduced feature */ 74 case MXC_CPU_IMX9101: 75 return "91(01)";/* iMX91 9x9 Specific feature */ 76 default: 77 return "??"; 78 } 79} 80 81static void get_imx_rev_str(struct cpu_imx_plat *plat, u32 rev) 82{ 83 if (IS_ENABLED(CONFIG_IMX8)) { 84 switch (rev) { 85 case CHIP_REV_A: 86 plat->rev[0] = 'A'; 87 break; 88 case CHIP_REV_B: 89 plat->rev[0] = 'B'; 90 break; 91 case CHIP_REV_C: 92 plat->rev[0] = 'C'; 93 break; 94 default: 95 plat->rev[0] = '?'; 96 break; 97 } 98 plat->rev[1] = '\0'; 99 } else { 100 plat->rev[0] = '1' + (((rev & 0xf0) - CHIP_REV_1_0) >> 4); 101 plat->rev[1] = '.'; 102 plat->rev[2] = '0' + (rev & 0xf); 103 plat->rev[3] = '\0'; 104 } 105} 106 107static void set_core_data(struct udevice *dev) 108{ 109 struct cpu_imx_plat *plat = dev_get_plat(dev); 110 111 if (device_is_compatible(dev, "arm,cortex-a35")) { 112 plat->cpu_rsrc = SC_R_A35; 113 plat->name = "A35"; 114 } else if (device_is_compatible(dev, "arm,cortex-a53")) { 115 plat->cpu_rsrc = SC_R_A53; 116 plat->name = "A53"; 117 } else if (device_is_compatible(dev, "arm,cortex-a72")) { 118 plat->cpu_rsrc = SC_R_A72; 119 plat->name = "A72"; 120 } else if (device_is_compatible(dev, "arm,cortex-a55")) { 121 plat->name = "A55"; 122 } else { 123 plat->cpu_rsrc = SC_R_A53; 124 plat->name = "?"; 125 } 126} 127 128#if IS_ENABLED(CONFIG_DM_THERMAL) 129static int cpu_imx_get_temp(struct cpu_imx_plat *plat) 130{ 131 struct udevice *thermal_dev; 132 int cpu_tmp, ret; 133 int idx = 1; /* use "cpu-thermal0" device */ 134 135 if (IS_ENABLED(CONFIG_IMX8)) { 136 if (plat->cpu_rsrc == SC_R_A72) 137 idx = 2; /* use "cpu-thermal1" device */ 138 } else if (IS_ENABLED(CONFIG_IMX91)) { 139 idx = 0; 140 } else { 141 idx = 1; 142 } 143 144 ret = uclass_get_device(UCLASS_THERMAL, idx, &thermal_dev); 145 if (!ret) { 146 ret = thermal_get_temp(thermal_dev, &cpu_tmp); 147 if (ret) 148 return 0xdeadbeef; 149 } else { 150 return 0xdeadbeef; 151 } 152 153 return cpu_tmp; 154} 155#else 156static int cpu_imx_get_temp(struct cpu_imx_plat *plat) 157{ 158 return 0; 159} 160#endif 161 162__weak u32 get_cpu_temp_grade(int *minc, int *maxc) 163{ 164 return 0; 165} 166 167static int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size) 168{ 169 struct cpu_imx_plat *plat = dev_get_plat(dev); 170 const char *grade; 171 int ret, temp; 172 int minc, maxc; 173 174 if (size < 100) 175 return -ENOSPC; 176 177 ret = snprintf(buf, size, "NXP i.MX%s Rev%s %s at %u MHz", 178 plat->type, plat->rev, plat->name, plat->freq_mhz); 179 180 if (IS_ENABLED(CONFIG_IMX9)) { 181 switch (get_cpu_temp_grade(&minc, &maxc)) { 182 case TEMP_AUTOMOTIVE: 183 grade = "Automotive temperature grade "; 184 break; 185 case TEMP_INDUSTRIAL: 186 grade = "Industrial temperature grade "; 187 break; 188 case TEMP_EXTCOMMERCIAL: 189 grade = "Extended Consumer temperature grade "; 190 break; 191 default: 192 grade = "Consumer temperature grade "; 193 break; 194 } 195 196 buf = buf + ret; 197 size = size - ret; 198 ret = snprintf(buf, size, "\nCPU: %s (%dC to %dC)", grade, minc, maxc); 199 } 200 201 if (IS_ENABLED(CONFIG_DM_THERMAL)) { 202 temp = cpu_imx_get_temp(plat); 203 buf = buf + ret; 204 size = size - ret; 205 if (temp != 0xdeadbeef) 206 ret = snprintf(buf, size, " at %dC", temp); 207 else 208 ret = snprintf(buf, size, " - invalid sensor data"); 209 } 210 211 return 0; 212} 213 214static int cpu_imx_get_info(const struct udevice *dev, struct cpu_info *info) 215{ 216 struct cpu_imx_plat *plat = dev_get_plat(dev); 217 218 info->cpu_freq = plat->freq_mhz * 1000000; 219 info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); 220 return 0; 221} 222 223static int cpu_imx_get_count(const struct udevice *dev) 224{ 225 ofnode node; 226 int num = 0; 227 228 ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { 229 const char *device_type; 230 231 if (!ofnode_is_enabled(node)) 232 continue; 233 234 device_type = ofnode_read_string(node, "device_type"); 235 if (!device_type) 236 continue; 237 238 if (!strcmp(device_type, "cpu")) 239 num++; 240 } 241 242 return num; 243} 244 245static int cpu_imx_get_vendor(const struct udevice *dev, char *buf, int size) 246{ 247 snprintf(buf, size, "NXP"); 248 return 0; 249} 250 251static int cpu_imx_is_current(struct udevice *dev) 252{ 253 struct cpu_imx_plat *plat = dev_get_plat(dev); 254 255 if (plat->mpidr == (read_mpidr() & 0xffff)) 256 return 1; 257 258 return 0; 259} 260 261static int cpu_imx_release_core(const struct udevice *dev, phys_addr_t addr) 262{ 263 struct cpu_imx_plat *plat = dev_get_plat(dev); 264 struct pt_regs regs; 265 266 regs.regs[0] = PSCI_0_2_FN64_CPU_ON; 267 regs.regs[1] = plat->mpidr; 268 regs.regs[2] = addr; 269 regs.regs[3] = 0; 270 271 smc_call(&regs); 272 if (regs.regs[0]) { 273 printf("Failed to release CPU core (mpidr: 0x%x)\n", plat->mpidr); 274 return -1; 275 } 276 277 printf("Released CPU core (mpidr: 0x%x) to address 0x%llx\n", plat->mpidr, addr); 278 279 return 0; 280} 281 282static const struct cpu_ops cpu_imx_ops = { 283 .get_desc = cpu_imx_get_desc, 284 .get_info = cpu_imx_get_info, 285 .get_count = cpu_imx_get_count, 286 .get_vendor = cpu_imx_get_vendor, 287 .is_current = cpu_imx_is_current, 288 .release_core = cpu_imx_release_core, 289}; 290 291static const struct udevice_id cpu_imx_ids[] = { 292 { .compatible = "arm,cortex-a35" }, 293 { .compatible = "arm,cortex-a53" }, 294 { .compatible = "arm,cortex-a55" }, 295 { .compatible = "arm,cortex-a72" }, 296 { } 297}; 298 299static ulong imx_get_cpu_rate(struct udevice *dev) 300{ 301 struct cpu_imx_plat *plat = dev_get_plat(dev); 302 struct clk clk; 303 ulong rate; 304 int ret; 305 306 if (IS_ENABLED(CONFIG_IMX8)) { 307 ret = sc_pm_get_clock_rate(-1, plat->cpu_rsrc, SC_PM_CLK_CPU, 308 (sc_pm_clock_rate_t *)&rate); 309 } else { 310 ret = clk_get_by_index(dev, 0, &clk); 311 if (!ret) { 312 rate = clk_get_rate(&clk); 313 if (!rate) 314 ret = -EOPNOTSUPP; 315 } 316 } 317 if (ret) { 318 printf("Could not read CPU frequency: %d\n", ret); 319 return 0; 320 } 321 322 return rate; 323} 324 325static int imx_cpu_probe(struct udevice *dev) 326{ 327 struct cpu_imx_plat *plat = dev_get_plat(dev); 328 u32 cpurev; 329 330 set_core_data(dev); 331 cpurev = get_cpu_rev(); 332 plat->cpurev = cpurev; 333 get_imx_rev_str(plat, cpurev & 0xFFF); 334 plat->type = get_imx_type_str((cpurev & 0x1FF000) >> 12); 335 plat->freq_mhz = imx_get_cpu_rate(dev) / 1000000; 336 plat->mpidr = dev_read_addr(dev); 337 if (plat->mpidr == FDT_ADDR_T_NONE) { 338 printf("%s: Failed to get CPU reg property\n", __func__); 339 return -EINVAL; 340 } 341 342 return 0; 343} 344 345U_BOOT_DRIVER(cpu_imx_drv) = { 346 .name = "imx_cpu", 347 .id = UCLASS_CPU, 348 .of_match = cpu_imx_ids, 349 .ops = &cpu_imx_ops, 350 .probe = imx_cpu_probe, 351 .plat_auto = sizeof(struct cpu_imx_plat), 352 .flags = DM_FLAG_PRE_RELOC, 353};