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