blob: 66534fe6d17f23c9e97e40c00d89b41b3f051494 [file] [log] [blame]
Peng Fan99ac6c72023-04-28 12:08:09 +08001// 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/global_data.h>
11#include <asm/system.h>
12#include <firmware/linux/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 <linux/bitops.h>
17
18DECLARE_GLOBAL_DATA_PTR;
19
20struct cpu_imx_plat {
21 const char *name;
22 const char *rev;
23 const char *type;
24 u32 cpu_rsrc;
25 u32 cpurev;
26 u32 freq_mhz;
27 u32 mpidr;
28};
29
30const char *get_imx9_type(u32 imxtype)
31{
32 switch (imxtype) {
33 case MXC_CPU_IMX93:
34 return "93";
35 default:
36 return "??";
37 }
38}
39
40const char *get_imx9_rev(u32 rev)
41{
42 switch (rev) {
43 case CHIP_REV_1_0:
44 return "1.";
45 case CHIP_REV_B:
46 return "B";
47 case CHIP_REV_C:
48 return "C";
49 default:
50 return "?";
51 }
52}
53
54static void set_core_data(struct udevice *dev)
55{
56 struct cpu_imx_plat *plat = dev_get_plat(dev);
57
58 if (device_is_compatible(dev, "arm,cortex-a35"))
59 plat->name = "A35";
60 else
61 plat->name = "?";
62}
63
64#if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
65static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
66{
67 struct udevice *thermal_dev;
68 int cpu_tmp, ret;
69 int idx = 1; /* use "cpu-thermal0" device */
70
71 if (plat->cpu_rsrc == SC_R_A72)
72 idx = 2; /* use "cpu-thermal1" device */
73
74 ret = uclass_get_device(UCLASS_THERMAL, idx, &thermal_dev);
75 if (!ret) {
76 ret = thermal_get_temp(thermal_dev, &cpu_tmp);
77 if (ret)
78 return 0xdeadbeef;
79 } else {
80 return 0xdeadbeef;
81 }
82
83 return cpu_tmp;
84}
85#else
86static int cpu_imx_get_temp(struct cpu_imx_plat *plat)
87{
88 return 0;
89}
90#endif
91
92int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size)
93{
94 struct cpu_imx_plat *plat = dev_get_plat(dev);
95 int ret, temp;
96
97 if (size < 100)
98 return -ENOSPC;
99
100 ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
101 plat->type, plat->rev, plat->name, plat->freq_mhz);
102
103 if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
104 temp = cpu_imx_get_temp(plat);
105 buf = buf + ret;
106 size = size - ret;
107 if (temp != 0xdeadbeef)
108 ret = snprintf(buf, size, " at %dC", temp);
109 else
110 ret = snprintf(buf, size, " - invalid sensor data");
111 }
112
113 snprintf(buf + ret, size - ret, "\n");
114
115 return 0;
116}
117
118static int cpu_imx_get_info(const struct udevice *dev, struct cpu_info *info)
119{
120 struct cpu_imx_plat *plat = dev_get_plat(dev);
121
122 info->cpu_freq = plat->freq_mhz * 1000;
123 info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
124 return 0;
125}
126
127static int cpu_imx_get_count(const struct udevice *dev)
128{
129 ofnode node;
130 int num = 0;
131
132 ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
133 const char *device_type;
134
135 if (!ofnode_is_enabled(node))
136 continue;
137
138 device_type = ofnode_read_string(node, "device_type");
139 if (!device_type)
140 continue;
141
142 if (!strcmp(device_type, "cpu"))
143 num++;
144 }
145
146 return num;
147}
148
149static int cpu_imx_get_vendor(const struct udevice *dev, char *buf, int size)
150{
151 snprintf(buf, size, "NXP");
152 return 0;
153}
154
155static int cpu_imx_is_current(struct udevice *dev)
156{
157 struct cpu_imx_plat *plat = dev_get_plat(dev);
158
159 if (plat->mpidr == (read_mpidr() & 0xffff))
160 return 1;
161
162 return 0;
163}
164
165static const struct cpu_ops cpu_imx9_ops = {
166 .get_desc = cpu_imx_get_desc,
167 .get_info = cpu_imx_get_info,
168 .get_count = cpu_imx_get_count,
169 .get_vendor = cpu_imx_get_vendor,
170 .is_current = cpu_imx_is_current,
171};
172
173static const struct udevice_id cpu_imx9_ids[] = {
174 { .compatible = "arm,cortex-a35" },
175 { .compatible = "arm,cortex-a53" },
176 { .compatible = "arm,cortex-a72" },
177 { }
178};
179
180static ulong imx9_get_cpu_rate(struct udevice *dev)
181{
182 struct cpu_imx_plat *plat = dev_get_plat(dev);
183 ulong rate;
184 int ret;
185
186 ret = sc_pm_get_clock_rate(-1, plat->cpu_rsrc, SC_PM_CLK_CPU,
187 (sc_pm_clock_rate_t *)&rate);
188 if (ret) {
189 printf("Could not read CPU frequency: %d\n", ret);
190 return 0;
191 }
192
193 return rate;
194}
195
196static int imx9_cpu_probe(struct udevice *dev)
197{
198 struct cpu_imx_plat *plat = dev_get_plat(dev);
199 u32 cpurev;
200
201 set_core_data(dev);
202 cpurev = get_cpu_rev();
203 plat->cpurev = cpurev;
204 plat->rev = get_imx9_rev(cpurev & 0xFFF);
205 plat->type = get_imx9_type((cpurev & 0xFF000) >> 12);
206 plat->freq_mhz = imx9_get_cpu_rate(dev) / 1000000;
207 plat->mpidr = dev_read_addr(dev);
208 if (plat->mpidr == FDT_ADDR_T_NONE) {
209 printf("%s: Failed to get CPU reg property\n", __func__);
210 return -EINVAL;
211 }
212
213 return 0;
214}
215
216U_BOOT_DRIVER(cpu_imx9_drv) = {
217 .name = "imx9x_cpu",
218 .id = UCLASS_CPU,
219 .of_match = cpu_imx9_ids,
220 .ops = &cpu_imx9_ops,
221 .probe = imx9_cpu_probe,
222 .plat_auto = sizeof(struct cpu_imx_plat),
223 .flags = DM_FLAG_PRE_RELOC,
224};