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_cpuinfo_init(void)111 static int __init rockchip_cpuinfo_init(void)
112 {
113 return platform_driver_register(&rockchip_cpuinfo_driver);
114 }
115 subsys_initcall_sync(rockchip_cpuinfo_init);
116
rockchip_cpuinfo_exit(void)117 static void __exit rockchip_cpuinfo_exit(void)
118 {
119 platform_driver_unregister(&rockchip_cpuinfo_driver);
120 }
121 module_exit(rockchip_cpuinfo_exit);
122
123 MODULE_LICENSE("GPL");
124