1 /*
2 * Copyright (C) 2017 Rockchip Electronics Co. Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14 #include <linux/crc32.h>
15 #include <linux/io.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/nvmem-consumer.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 #include <asm/system_info.h>
22 #include <linux/rockchip/cpu.h>
23
24 unsigned long rockchip_soc_id;
25 EXPORT_SYMBOL(rockchip_soc_id);
26
rockchip_cpuinfo_probe(struct platform_device * pdev)27 static int rockchip_cpuinfo_probe(struct platform_device *pdev)
28 {
29 struct device *dev = &pdev->dev;
30 struct nvmem_cell *cell;
31 unsigned char *efuse_buf, buf[16];
32 size_t len = 0;
33 int i;
34
35 cell = nvmem_cell_get(dev, "cpu-code");
36 if (!IS_ERR(cell)) {
37 efuse_buf = nvmem_cell_read(cell, &len);
38 nvmem_cell_put(cell);
39 if (IS_ERR(efuse_buf))
40 return PTR_ERR(efuse_buf);
41
42 if (len == 2)
43 rockchip_set_cpu((efuse_buf[0] << 8 | efuse_buf[1]));
44 kfree(efuse_buf);
45 }
46
47 cell = nvmem_cell_get(dev, "cpu-version");
48 if (!IS_ERR(cell)) {
49 efuse_buf = nvmem_cell_read(cell, &len);
50 nvmem_cell_put(cell);
51 if (IS_ERR(efuse_buf))
52 return PTR_ERR(efuse_buf);
53
54 if ((len == 1) && (efuse_buf[0] > rockchip_get_cpu_version()))
55 rockchip_set_cpu_version(efuse_buf[0]);
56 kfree(efuse_buf);
57 }
58
59 cell = nvmem_cell_get(dev, "id");
60 if (IS_ERR(cell)) {
61 dev_err(dev, "failed to get id cell: %ld\n", PTR_ERR(cell));
62 if (PTR_ERR(cell) == -EPROBE_DEFER)
63 return PTR_ERR(cell);
64 return PTR_ERR(cell);
65 }
66 efuse_buf = nvmem_cell_read(cell, &len);
67 nvmem_cell_put(cell);
68 if (IS_ERR(efuse_buf))
69 return PTR_ERR(efuse_buf);
70
71 if (len != 16) {
72 kfree(efuse_buf);
73 dev_err(dev, "invalid id len: %zu\n", len);
74 return -EINVAL;
75 }
76
77 for (i = 0; i < 8; i++) {
78 buf[i] = efuse_buf[1 + (i << 1)];
79 buf[i + 8] = efuse_buf[i << 1];
80 }
81
82 kfree(efuse_buf);
83
84 dev_info(dev, "SoC\t\t: %lx\n", rockchip_soc_id);
85
86 #ifdef CONFIG_NO_GKI
87 system_serial_low = crc32(0, buf, 8);
88 system_serial_high = crc32(system_serial_low, buf + 8, 8);
89
90 dev_info(dev, "Serial\t\t: %08x%08x\n",
91 system_serial_high, system_serial_low);
92 #endif
93
94 return 0;
95 }
96
97 static const struct of_device_id rockchip_cpuinfo_of_match[] = {
98 { .compatible = "rockchip,cpuinfo", },
99 { },
100 };
101 MODULE_DEVICE_TABLE(of, rockchip_cpuinfo_of_match);
102
103 static struct platform_driver rockchip_cpuinfo_driver = {
104 .probe = rockchip_cpuinfo_probe,
105 .driver = {
106 .name = "rockchip-cpuinfo",
107 .of_match_table = rockchip_cpuinfo_of_match,
108 },
109 };
110
rockchip_set_cpu_version_from_os_reg(u32 reg)111 static void rockchip_set_cpu_version_from_os_reg(u32 reg)
112 {
113 void __iomem *r = ioremap(reg, 0x4);
114
115 if (r) {
116 rockchip_set_cpu_version(readl_relaxed(r) & GENMASK(2, 0));
117 iounmap(r);
118 }
119 }
120
px30_init(void)121 static void px30_init(void)
122 {
123 void __iomem *base;
124
125 rockchip_soc_id = ROCKCHIP_SOC_PX30;
126 #define PX30_DDR_GRF_BASE 0xFF630000
127 #define PX30_DDR_GRF_CON1 0x04
128 base = ioremap(PX30_DDR_GRF_BASE, SZ_4K);
129 if (base) {
130 unsigned int val = readl_relaxed(base + PX30_DDR_GRF_CON1);
131
132 if (((val >> 14) & 0x03) == 0x03)
133 rockchip_soc_id = ROCKCHIP_SOC_PX30S;
134 iounmap(base);
135 }
136 }
137
138 #define RV1106_OS_REG1 0xff020204
rv1103_init(void)139 static void rv1103_init(void)
140 {
141 rockchip_soc_id = ROCKCHIP_SOC_RV1103;
142 rockchip_set_cpu_version_from_os_reg(RV1106_OS_REG1);
143 }
144
rv1106_init(void)145 static void rv1106_init(void)
146 {
147 rockchip_soc_id = ROCKCHIP_SOC_RV1106;
148 rockchip_set_cpu_version_from_os_reg(RV1106_OS_REG1);
149 }
150
rv1109_init(void)151 static void rv1109_init(void)
152 {
153 rockchip_soc_id = ROCKCHIP_SOC_RV1109;
154 }
155
rv1126_init(void)156 static void rv1126_init(void)
157 {
158 rockchip_soc_id = ROCKCHIP_SOC_RV1126;
159 }
160
rk3288_init(void)161 static void rk3288_init(void)
162 {
163 void __iomem *base;
164
165 rockchip_soc_id = ROCKCHIP_SOC_RK3288;
166 #define RK3288_HDMI_PHYS 0xFF980000
167 base = ioremap(RK3288_HDMI_PHYS, SZ_4K);
168 if (base) {
169 /* RK3288W HDMI Revision ID is 0x1A */
170 if (readl_relaxed(base + 4) == 0x1A)
171 rockchip_soc_id = ROCKCHIP_SOC_RK3288W;
172 iounmap(base);
173 }
174 }
175
rk3126_init(void)176 static void rk3126_init(void)
177 {
178 void __iomem *base;
179
180 rockchip_soc_id = ROCKCHIP_SOC_RK3126;
181 #define RK312X_GRF_PHYS 0x20008000
182 #define RK312X_GRF_SOC_CON1 0x00000144
183 #define RK312X_GRF_CHIP_TAG 0x00000300
184 base = ioremap(RK312X_GRF_PHYS, SZ_4K);
185 if (base) {
186 if (readl_relaxed(base + RK312X_GRF_CHIP_TAG) == 0x3136) {
187 if (readl_relaxed(base + RK312X_GRF_SOC_CON1) & 0x1)
188 rockchip_soc_id = ROCKCHIP_SOC_RK3126C;
189 else
190 rockchip_soc_id = ROCKCHIP_SOC_RK3126B;
191 }
192 iounmap(base);
193 }
194 }
195
rk3308_init(void)196 static void rk3308_init(void)
197 {
198 void __iomem *base;
199
200 rockchip_soc_id = ROCKCHIP_SOC_RK3308;
201 #define RK3308_GRF_PHYS 0xFF000000
202 #define RK3308_GRF_CHIP_ID 0x800
203 base = ioremap(RK3308_GRF_PHYS, SZ_4K);
204 if (base) {
205 u32 v = readl_relaxed(base + RK3308_GRF_CHIP_ID);
206
207 if (v == 0x3308)
208 rockchip_soc_id = ROCKCHIP_SOC_RK3308B;
209 if (v == 0x3308c)
210 rockchip_soc_id = ROCKCHIP_SOC_RK3308BS;
211 iounmap(base);
212 }
213 }
214
rk3528_init(void)215 static void rk3528_init(void)
216 {
217 rockchip_soc_id = ROCKCHIP_SOC_RK3528;
218 }
219
220 #define RK356X_PMU_GRF_PHYS 0xfdc20000
221 #define RK356X_PMU_GRF_SOC_CON0 0x00000100
222 #define RK356X_CHIP_VERSION_MASK 0x00008000
rk356x_set_cpu_version(void)223 static void rk356x_set_cpu_version(void)
224 {
225 void __iomem *base;
226
227 base = ioremap(RK356X_PMU_GRF_PHYS, SZ_4K);
228 if (base) {
229 if (readl_relaxed(base + RK356X_PMU_GRF_SOC_CON0) & RK356X_CHIP_VERSION_MASK)
230 rockchip_set_cpu_version(1);
231 iounmap(base);
232 }
233 }
234
rk3566_init(void)235 static void rk3566_init(void)
236 {
237 rockchip_soc_id = ROCKCHIP_SOC_RK3566;
238 rk356x_set_cpu_version();
239 }
240
rk3568_init(void)241 static void rk3568_init(void)
242 {
243 rockchip_soc_id = ROCKCHIP_SOC_RK3568;
244 rk356x_set_cpu_version();
245 }
246
rockchip_soc_id_init(void)247 int rockchip_soc_id_init(void)
248 {
249 if (rockchip_soc_id)
250 return 0;
251
252 if (cpu_is_rk3288()) {
253 rk3288_init();
254 } else if (cpu_is_rk312x()) {
255 if (of_machine_is_compatible("rockchip,rk3128"))
256 rockchip_soc_id = ROCKCHIP_SOC_RK3128;
257 else
258 rk3126_init();
259 } else if (cpu_is_rk3308()) {
260 rk3308_init();
261 } else if (cpu_is_rv1103()) {
262 rv1103_init();
263 } else if (cpu_is_rv1106()) {
264 rv1106_init();
265 } else if (cpu_is_rv1109()) {
266 rv1109_init();
267 } else if (cpu_is_rv1126()) {
268 rv1126_init();
269 } else if (cpu_is_rk3528()) {
270 rk3528_init();
271 } else if (cpu_is_rk3566()) {
272 rk3566_init();
273 } else if (cpu_is_rk3568()) {
274 rk3568_init();
275 } else if (cpu_is_px30()) {
276 px30_init();
277 }
278
279 return 0;
280 }
281 EXPORT_SYMBOL(rockchip_soc_id_init);
282 #ifndef MODULE
283 pure_initcall(rockchip_soc_id_init);
284 #endif
285
rockchip_cpuinfo_init(void)286 static int __init rockchip_cpuinfo_init(void)
287 {
288 #ifdef MODULE
289 rockchip_soc_id_init();
290 #endif
291 return platform_driver_register(&rockchip_cpuinfo_driver);
292 }
293 subsys_initcall_sync(rockchip_cpuinfo_init);
294
rockchip_cpuinfo_exit(void)295 static void __exit rockchip_cpuinfo_exit(void)
296 {
297 platform_driver_unregister(&rockchip_cpuinfo_driver);
298 }
299 module_exit(rockchip_cpuinfo_exit);
300
301 MODULE_LICENSE("GPL");
302