blob: 9d1d8d7ab890c2d23cce4e01b731e6c4f55fa441 [file] [log] [blame]
Peng Fan43c50872019-08-26 08:12:19 +00001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 NXP
4 */
5
6#include <common.h>
7#include <cpu.h>
8#include <dm.h>
9#include <thermal.h>
Simon Glass90526e92020-05-10 11:39:56 -060010#include <asm/system.h>
Peng Fan43c50872019-08-26 08:12:19 +000011#include <asm/arch/sci/sci.h>
12#include <asm/arch/sys_proto.h>
13#include <asm/arch-imx/cpu.h>
14#include <asm/armv8/cpu.h>
15
16DECLARE_GLOBAL_DATA_PTR;
17
18struct cpu_imx_platdata {
19 const char *name;
20 const char *rev;
21 const char *type;
22 u32 cpurev;
23 u32 freq_mhz;
Peng Fan177f9992020-05-03 21:58:52 +080024 u32 mpidr;
Peng Fan43c50872019-08-26 08:12:19 +000025};
26
27const char *get_imx8_type(u32 imxtype)
28{
29 switch (imxtype) {
30 case MXC_CPU_IMX8QXP:
31 case MXC_CPU_IMX8QXP_A0:
32 return "QXP";
33 case MXC_CPU_IMX8QM:
34 return "QM";
35 default:
36 return "??";
37 }
38}
39
40const char *get_imx8_rev(u32 rev)
41{
42 switch (rev) {
43 case CHIP_REV_A:
44 return "A";
45 case CHIP_REV_B:
46 return "B";
Frank Li8142a972020-05-03 21:58:55 +080047 case CHIP_REV_C:
48 return "C";
Peng Fan43c50872019-08-26 08:12:19 +000049 default:
50 return "?";
51 }
52}
53
Peng Fan55bc96f2020-05-03 21:58:53 +080054const char *get_core_name(struct udevice *dev)
Peng Fan43c50872019-08-26 08:12:19 +000055{
Peng Fan55bc96f2020-05-03 21:58:53 +080056 if (!device_is_compatible(dev, "arm,cortex-a35"))
Peng Fan43c50872019-08-26 08:12:19 +000057 return "A35";
Peng Fan55bc96f2020-05-03 21:58:53 +080058 else if (!device_is_compatible(dev, "arm,cortex-a53"))
Peng Fan43c50872019-08-26 08:12:19 +000059 return "A53";
Peng Fan55bc96f2020-05-03 21:58:53 +080060 else if (!device_is_compatible(dev, "arm,cortex-a72"))
Peng Fan43c50872019-08-26 08:12:19 +000061 return "A72";
62 else
63 return "?";
64}
65
66#if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
Ye Li3ee6ea42020-05-03 21:58:54 +080067static int cpu_imx_get_temp(struct cpu_imx_platdata *plat)
Peng Fan43c50872019-08-26 08:12:19 +000068{
69 struct udevice *thermal_dev;
70 int cpu_tmp, ret;
71
Ye Li3ee6ea42020-05-03 21:58:54 +080072 if (!strcmp(plat->name, "A72"))
73 ret = uclass_get_device(UCLASS_THERMAL, 1, &thermal_dev);
74 else
75 ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev);
Peng Fan43c50872019-08-26 08:12:19 +000076
77 if (!ret) {
78 ret = thermal_get_temp(thermal_dev, &cpu_tmp);
79 if (ret)
80 return 0xdeadbeef;
81 } else {
82 return 0xdeadbeef;
83 }
84
85 return cpu_tmp;
86}
87#else
Ye Li3ee6ea42020-05-03 21:58:54 +080088static int cpu_imx_get_temp(struct cpu_imx_platdata *plat)
Peng Fan43c50872019-08-26 08:12:19 +000089{
90 return 0;
91}
92#endif
93
94int cpu_imx_get_desc(struct udevice *dev, char *buf, int size)
95{
96 struct cpu_imx_platdata *plat = dev_get_platdata(dev);
Ye Li3ee6ea42020-05-03 21:58:54 +080097 int ret, temp;
Peng Fan43c50872019-08-26 08:12:19 +000098
99 if (size < 100)
100 return -ENOSPC;
101
102 ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
103 plat->type, plat->rev, plat->name, plat->freq_mhz);
104
105 if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
Ye Li3ee6ea42020-05-03 21:58:54 +0800106 temp = cpu_imx_get_temp(plat);
Peng Fan43c50872019-08-26 08:12:19 +0000107 buf = buf + ret;
108 size = size - ret;
Ye Li3ee6ea42020-05-03 21:58:54 +0800109 if (temp != 0xdeadbeef)
110 ret = snprintf(buf, size, " at %dC", temp);
111 else
112 ret = snprintf(buf, size, " - invalid sensor data");
Peng Fan43c50872019-08-26 08:12:19 +0000113 }
114
115 snprintf(buf + ret, size - ret, "\n");
116
117 return 0;
118}
119
120static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info)
121{
122 struct cpu_imx_platdata *plat = dev_get_platdata(dev);
123
124 info->cpu_freq = plat->freq_mhz * 1000;
125 info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
126 return 0;
127}
128
129static int cpu_imx_get_count(struct udevice *dev)
130{
Peng Fanadb3bd72020-05-03 21:58:51 +0800131 ofnode node;
132 int num = 0;
133
134 ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
135 const char *device_type;
136
137 if (!ofnode_is_available(node))
138 continue;
139
140 device_type = ofnode_read_string(node, "device_type");
141 if (!device_type)
142 continue;
143
144 if (!strcmp(device_type, "cpu"))
145 num++;
146 }
147
148 return num;
Peng Fan43c50872019-08-26 08:12:19 +0000149}
150
151static int cpu_imx_get_vendor(struct udevice *dev, char *buf, int size)
152{
153 snprintf(buf, size, "NXP");
154 return 0;
155}
156
Peng Fan177f9992020-05-03 21:58:52 +0800157static int cpu_imx_is_current(struct udevice *dev)
158{
159 struct cpu_imx_platdata *plat = dev_get_platdata(dev);
160
161 if (plat->mpidr == (read_mpidr() & 0xffff))
162 return 1;
163
164 return 0;
165}
166
Peng Fan43c50872019-08-26 08:12:19 +0000167static const struct cpu_ops cpu_imx8_ops = {
168 .get_desc = cpu_imx_get_desc,
169 .get_info = cpu_imx_get_info,
170 .get_count = cpu_imx_get_count,
171 .get_vendor = cpu_imx_get_vendor,
Peng Fan177f9992020-05-03 21:58:52 +0800172 .is_current = cpu_imx_is_current,
Peng Fan43c50872019-08-26 08:12:19 +0000173};
174
175static const struct udevice_id cpu_imx8_ids[] = {
176 { .compatible = "arm,cortex-a35" },
177 { .compatible = "arm,cortex-a53" },
Peng Fan177f9992020-05-03 21:58:52 +0800178 { .compatible = "arm,cortex-a72" },
Peng Fan43c50872019-08-26 08:12:19 +0000179 { }
180};
181
Peng Fan55bc96f2020-05-03 21:58:53 +0800182static ulong imx8_get_cpu_rate(struct udevice *dev)
Peng Fan43c50872019-08-26 08:12:19 +0000183{
184 ulong rate;
Peng Fan55bc96f2020-05-03 21:58:53 +0800185 int ret, type;
186
187 if (!device_is_compatible(dev, "arm,cortex-a35"))
188 type = SC_R_A35;
189 else if (!device_is_compatible(dev, "arm,cortex-a53"))
190 type = SC_R_A53;
191 else if (!device_is_compatible(dev, "arm,cortex-a72"))
192 type = SC_R_A72;
193 else
194 return 0;
Peng Fan43c50872019-08-26 08:12:19 +0000195
196 ret = sc_pm_get_clock_rate(-1, type, SC_PM_CLK_CPU,
197 (sc_pm_clock_rate_t *)&rate);
198 if (ret) {
199 printf("Could not read CPU frequency: %d\n", ret);
200 return 0;
201 }
202
203 return rate;
204}
205
206static int imx8_cpu_probe(struct udevice *dev)
207{
208 struct cpu_imx_platdata *plat = dev_get_platdata(dev);
209 u32 cpurev;
210
211 cpurev = get_cpu_rev();
212 plat->cpurev = cpurev;
Peng Fan55bc96f2020-05-03 21:58:53 +0800213 plat->name = get_core_name(dev);
Peng Fan43c50872019-08-26 08:12:19 +0000214 plat->rev = get_imx8_rev(cpurev & 0xFFF);
215 plat->type = get_imx8_type((cpurev & 0xFF000) >> 12);
Peng Fan55bc96f2020-05-03 21:58:53 +0800216 plat->freq_mhz = imx8_get_cpu_rate(dev) / 1000000;
Peng Fan177f9992020-05-03 21:58:52 +0800217 plat->mpidr = dev_read_addr(dev);
218 if (plat->mpidr == FDT_ADDR_T_NONE) {
219 printf("%s: Failed to get CPU reg property\n", __func__);
220 return -EINVAL;
221 }
222
Peng Fan43c50872019-08-26 08:12:19 +0000223 return 0;
224}
225
226U_BOOT_DRIVER(cpu_imx8_drv) = {
227 .name = "imx8x_cpu",
228 .id = UCLASS_CPU,
229 .of_match = cpu_imx8_ids,
230 .ops = &cpu_imx8_ops,
231 .probe = imx8_cpu_probe,
232 .platdata_auto_alloc_size = sizeof(struct cpu_imx_platdata),
233 .flags = DM_FLAG_PRE_RELOC,
234};