cpu: imx8: support a72 as boot cpu
[oweals/u-boot.git] / drivers / cpu / imx8_cpu.c
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;
23         u32 mpidr;
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";
46         default:
47                 return "?";
48         }
49 }
50
51 const char *get_core_name(void)
52 {
53         if (is_cortex_a35())
54                 return "A35";
55         else if (is_cortex_a53())
56                 return "A53";
57         else if (is_cortex_a72())
58                 return "A72";
59         else
60                 return "?";
61 }
62
63 #if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
64 static int cpu_imx_get_temp(void)
65 {
66         struct udevice *thermal_dev;
67         int cpu_tmp, ret;
68
69         ret = uclass_get_device_by_name(UCLASS_THERMAL, "cpu-thermal0",
70                                         &thermal_dev);
71
72         if (!ret) {
73                 ret = thermal_get_temp(thermal_dev, &cpu_tmp);
74                 if (ret)
75                         return 0xdeadbeef;
76         } else {
77                 return 0xdeadbeef;
78         }
79
80         return cpu_tmp;
81 }
82 #else
83 static int cpu_imx_get_temp(void)
84 {
85         return 0;
86 }
87 #endif
88
89 int cpu_imx_get_desc(struct udevice *dev, char *buf, int size)
90 {
91         struct cpu_imx_platdata *plat = dev_get_platdata(dev);
92         int ret;
93
94         if (size < 100)
95                 return -ENOSPC;
96
97         ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
98                        plat->type, plat->rev, plat->name, plat->freq_mhz);
99
100         if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
101                 buf = buf + ret;
102                 size = size - ret;
103                 ret = snprintf(buf, size, " at %dC", cpu_imx_get_temp());
104         }
105
106         snprintf(buf + ret, size - ret, "\n");
107
108         return 0;
109 }
110
111 static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info)
112 {
113         struct cpu_imx_platdata *plat = dev_get_platdata(dev);
114
115         info->cpu_freq = plat->freq_mhz * 1000;
116         info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
117         return 0;
118 }
119
120 static int cpu_imx_get_count(struct udevice *dev)
121 {
122         ofnode node;
123         int num = 0;
124
125         ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
126                 const char *device_type;
127
128                 if (!ofnode_is_available(node))
129                         continue;
130
131                 device_type = ofnode_read_string(node, "device_type");
132                 if (!device_type)
133                         continue;
134
135                 if (!strcmp(device_type, "cpu"))
136                         num++;
137         }
138
139         return num;
140 }
141
142 static int cpu_imx_get_vendor(struct udevice *dev,  char *buf, int size)
143 {
144         snprintf(buf, size, "NXP");
145         return 0;
146 }
147
148 static int cpu_imx_is_current(struct udevice *dev)
149 {
150         struct cpu_imx_platdata *plat = dev_get_platdata(dev);
151
152         if (plat->mpidr == (read_mpidr() & 0xffff))
153                 return 1;
154
155         return 0;
156 }
157
158 static const struct cpu_ops cpu_imx8_ops = {
159         .get_desc       = cpu_imx_get_desc,
160         .get_info       = cpu_imx_get_info,
161         .get_count      = cpu_imx_get_count,
162         .get_vendor     = cpu_imx_get_vendor,
163         .is_current     = cpu_imx_is_current,
164 };
165
166 static const struct udevice_id cpu_imx8_ids[] = {
167         { .compatible = "arm,cortex-a35" },
168         { .compatible = "arm,cortex-a53" },
169         { .compatible = "arm,cortex-a72" },
170         { }
171 };
172
173 static ulong imx8_get_cpu_rate(void)
174 {
175         ulong rate;
176         int ret;
177         int type = is_cortex_a35() ? SC_R_A35 : is_cortex_a53() ?
178                    SC_R_A53 : SC_R_A72;
179
180         ret = sc_pm_get_clock_rate(-1, type, SC_PM_CLK_CPU,
181                                    (sc_pm_clock_rate_t *)&rate);
182         if (ret) {
183                 printf("Could not read CPU frequency: %d\n", ret);
184                 return 0;
185         }
186
187         return rate;
188 }
189
190 static int imx8_cpu_probe(struct udevice *dev)
191 {
192         struct cpu_imx_platdata *plat = dev_get_platdata(dev);
193         u32 cpurev;
194
195         cpurev = get_cpu_rev();
196         plat->cpurev = cpurev;
197         plat->name = get_core_name();
198         plat->rev = get_imx8_rev(cpurev & 0xFFF);
199         plat->type = get_imx8_type((cpurev & 0xFF000) >> 12);
200         plat->freq_mhz = imx8_get_cpu_rate() / 1000000;
201         plat->mpidr = dev_read_addr(dev);
202         if (plat->mpidr == FDT_ADDR_T_NONE) {
203                 printf("%s: Failed to get CPU reg property\n", __func__);
204                 return -EINVAL;
205         }
206
207         return 0;
208 }
209
210 U_BOOT_DRIVER(cpu_imx8_drv) = {
211         .name           = "imx8x_cpu",
212         .id             = UCLASS_CPU,
213         .of_match       = cpu_imx8_ids,
214         .ops            = &cpu_imx8_ops,
215         .probe          = imx8_cpu_probe,
216         .platdata_auto_alloc_size = sizeof(struct cpu_imx_platdata),
217         .flags          = DM_FLAG_PRE_RELOC,
218 };