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