]>
Commit | Line | Data |
---|---|---|
43c50873 PF |
1 | // 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> | |
10 | #include <asm/arch/sci/sci.h> | |
11 | #include <asm/arch/sys_proto.h> | |
12 | #include <asm/arch-imx/cpu.h> | |
13 | #include <asm/armv8/cpu.h> | |
14 | ||
15 | DECLARE_GLOBAL_DATA_PTR; | |
16 | ||
17 | struct cpu_imx_platdata { | |
18 | const char *name; | |
19 | const char *rev; | |
20 | const char *type; | |
21 | u32 cpurev; | |
22 | u32 freq_mhz; | |
177f9996 | 23 | u32 mpidr; |
43c50873 PF |
24 | }; |
25 | ||
26 | const char *get_imx8_type(u32 imxtype) | |
27 | { | |
28 | switch (imxtype) { | |
29 | case MXC_CPU_IMX8QXP: | |
30 | case MXC_CPU_IMX8QXP_A0: | |
31 | return "QXP"; | |
32 | case MXC_CPU_IMX8QM: | |
33 | return "QM"; | |
34 | default: | |
35 | return "??"; | |
36 | } | |
37 | } | |
38 | ||
39 | const char *get_imx8_rev(u32 rev) | |
40 | { | |
41 | switch (rev) { | |
42 | case CHIP_REV_A: | |
43 | return "A"; | |
44 | case CHIP_REV_B: | |
45 | return "B"; | |
8142a97d FL |
46 | case CHIP_REV_C: |
47 | return "C"; | |
43c50873 PF |
48 | default: |
49 | return "?"; | |
50 | } | |
51 | } | |
52 | ||
55bc96f3 | 53 | const char *get_core_name(struct udevice *dev) |
43c50873 | 54 | { |
55bc96f3 | 55 | if (!device_is_compatible(dev, "arm,cortex-a35")) |
43c50873 | 56 | return "A35"; |
55bc96f3 | 57 | else if (!device_is_compatible(dev, "arm,cortex-a53")) |
43c50873 | 58 | return "A53"; |
55bc96f3 | 59 | else if (!device_is_compatible(dev, "arm,cortex-a72")) |
43c50873 PF |
60 | return "A72"; |
61 | else | |
62 | return "?"; | |
63 | } | |
64 | ||
65 | #if IS_ENABLED(CONFIG_IMX_SCU_THERMAL) | |
3ee6ea44 | 66 | static int cpu_imx_get_temp(struct cpu_imx_platdata *plat) |
43c50873 PF |
67 | { |
68 | struct udevice *thermal_dev; | |
69 | int cpu_tmp, ret; | |
70 | ||
3ee6ea44 YL |
71 | if (!strcmp(plat->name, "A72")) |
72 | ret = uclass_get_device(UCLASS_THERMAL, 1, &thermal_dev); | |
73 | else | |
74 | ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev); | |
43c50873 PF |
75 | |
76 | if (!ret) { | |
77 | ret = thermal_get_temp(thermal_dev, &cpu_tmp); | |
78 | if (ret) | |
79 | return 0xdeadbeef; | |
80 | } else { | |
81 | return 0xdeadbeef; | |
82 | } | |
83 | ||
84 | return cpu_tmp; | |
85 | } | |
86 | #else | |
3ee6ea44 | 87 | static int cpu_imx_get_temp(struct cpu_imx_platdata *plat) |
43c50873 PF |
88 | { |
89 | return 0; | |
90 | } | |
91 | #endif | |
92 | ||
93 | int cpu_imx_get_desc(struct udevice *dev, char *buf, int size) | |
94 | { | |
95 | struct cpu_imx_platdata *plat = dev_get_platdata(dev); | |
3ee6ea44 | 96 | int ret, temp; |
43c50873 PF |
97 | |
98 | if (size < 100) | |
99 | return -ENOSPC; | |
100 | ||
101 | ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz", | |
102 | plat->type, plat->rev, plat->name, plat->freq_mhz); | |
103 | ||
104 | if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) { | |
3ee6ea44 | 105 | temp = cpu_imx_get_temp(plat); |
43c50873 PF |
106 | buf = buf + ret; |
107 | size = size - ret; | |
3ee6ea44 YL |
108 | if (temp != 0xdeadbeef) |
109 | ret = snprintf(buf, size, " at %dC", temp); | |
110 | else | |
111 | ret = snprintf(buf, size, " - invalid sensor data"); | |
43c50873 PF |
112 | } |
113 | ||
114 | snprintf(buf + ret, size - ret, "\n"); | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info) | |
120 | { | |
121 | struct cpu_imx_platdata *plat = dev_get_platdata(dev); | |
122 | ||
123 | info->cpu_freq = plat->freq_mhz * 1000; | |
124 | info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | static int cpu_imx_get_count(struct udevice *dev) | |
129 | { | |
adb3bd76 PF |
130 | ofnode node; |
131 | int num = 0; | |
132 | ||
133 | ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) { | |
134 | const char *device_type; | |
135 | ||
136 | if (!ofnode_is_available(node)) | |
137 | continue; | |
138 | ||
139 | device_type = ofnode_read_string(node, "device_type"); | |
140 | if (!device_type) | |
141 | continue; | |
142 | ||
143 | if (!strcmp(device_type, "cpu")) | |
144 | num++; | |
145 | } | |
146 | ||
147 | return num; | |
43c50873 PF |
148 | } |
149 | ||
150 | static int cpu_imx_get_vendor(struct udevice *dev, char *buf, int size) | |
151 | { | |
152 | snprintf(buf, size, "NXP"); | |
153 | return 0; | |
154 | } | |
155 | ||
177f9996 PF |
156 | static int cpu_imx_is_current(struct udevice *dev) |
157 | { | |
158 | struct cpu_imx_platdata *plat = dev_get_platdata(dev); | |
159 | ||
160 | if (plat->mpidr == (read_mpidr() & 0xffff)) | |
161 | return 1; | |
162 | ||
163 | return 0; | |
164 | } | |
165 | ||
43c50873 PF |
166 | static const struct cpu_ops cpu_imx8_ops = { |
167 | .get_desc = cpu_imx_get_desc, | |
168 | .get_info = cpu_imx_get_info, | |
169 | .get_count = cpu_imx_get_count, | |
170 | .get_vendor = cpu_imx_get_vendor, | |
177f9996 | 171 | .is_current = cpu_imx_is_current, |
43c50873 PF |
172 | }; |
173 | ||
174 | static const struct udevice_id cpu_imx8_ids[] = { | |
175 | { .compatible = "arm,cortex-a35" }, | |
176 | { .compatible = "arm,cortex-a53" }, | |
177f9996 | 177 | { .compatible = "arm,cortex-a72" }, |
43c50873 PF |
178 | { } |
179 | }; | |
180 | ||
55bc96f3 | 181 | static ulong imx8_get_cpu_rate(struct udevice *dev) |
43c50873 PF |
182 | { |
183 | ulong rate; | |
55bc96f3 PF |
184 | int ret, type; |
185 | ||
186 | if (!device_is_compatible(dev, "arm,cortex-a35")) | |
187 | type = SC_R_A35; | |
188 | else if (!device_is_compatible(dev, "arm,cortex-a53")) | |
189 | type = SC_R_A53; | |
190 | else if (!device_is_compatible(dev, "arm,cortex-a72")) | |
191 | type = SC_R_A72; | |
192 | else | |
193 | return 0; | |
43c50873 PF |
194 | |
195 | ret = sc_pm_get_clock_rate(-1, type, SC_PM_CLK_CPU, | |
196 | (sc_pm_clock_rate_t *)&rate); | |
197 | if (ret) { | |
198 | printf("Could not read CPU frequency: %d\n", ret); | |
199 | return 0; | |
200 | } | |
201 | ||
202 | return rate; | |
203 | } | |
204 | ||
205 | static int imx8_cpu_probe(struct udevice *dev) | |
206 | { | |
207 | struct cpu_imx_platdata *plat = dev_get_platdata(dev); | |
208 | u32 cpurev; | |
209 | ||
210 | cpurev = get_cpu_rev(); | |
211 | plat->cpurev = cpurev; | |
55bc96f3 | 212 | plat->name = get_core_name(dev); |
43c50873 PF |
213 | plat->rev = get_imx8_rev(cpurev & 0xFFF); |
214 | plat->type = get_imx8_type((cpurev & 0xFF000) >> 12); | |
55bc96f3 | 215 | plat->freq_mhz = imx8_get_cpu_rate(dev) / 1000000; |
177f9996 PF |
216 | plat->mpidr = dev_read_addr(dev); |
217 | if (plat->mpidr == FDT_ADDR_T_NONE) { | |
218 | printf("%s: Failed to get CPU reg property\n", __func__); | |
219 | return -EINVAL; | |
220 | } | |
221 | ||
43c50873 PF |
222 | return 0; |
223 | } | |
224 | ||
225 | U_BOOT_DRIVER(cpu_imx8_drv) = { | |
226 | .name = "imx8x_cpu", | |
227 | .id = UCLASS_CPU, | |
228 | .of_match = cpu_imx8_ids, | |
229 | .ops = &cpu_imx8_ops, | |
230 | .probe = imx8_cpu_probe, | |
231 | .platdata_auto_alloc_size = sizeof(struct cpu_imx_platdata), | |
232 | .flags = DM_FLAG_PRE_RELOC, | |
233 | }; |