1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright 2020 NXP |
4 | */ |
5 | |
6 | #include <linux/mfd/syscon.h> |
7 | #include <linux/of.h> |
8 | #include <linux/of_address.h> |
9 | #include <linux/regmap.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/sys_soc.h> |
12 | |
13 | #include <soc/imx/cpu.h> |
14 | #include <soc/imx/revision.h> |
15 | |
16 | #define IIM_UID 0x820 |
17 | |
18 | #define OCOTP_UID_H 0x420 |
19 | #define OCOTP_UID_L 0x410 |
20 | |
21 | #define OCOTP_ULP_UID_1 0x4b0 |
22 | #define OCOTP_ULP_UID_2 0x4c0 |
23 | #define OCOTP_ULP_UID_3 0x4d0 |
24 | #define OCOTP_ULP_UID_4 0x4e0 |
25 | |
26 | static int __init imx_soc_device_init(void) |
27 | { |
28 | struct soc_device_attribute *soc_dev_attr; |
29 | const char *ocotp_compat = NULL; |
30 | struct soc_device *soc_dev; |
31 | struct device_node *root; |
32 | struct regmap *ocotp = NULL; |
33 | const char *soc_id; |
34 | u64 soc_uid = 0; |
35 | u32 val; |
36 | int ret; |
37 | int i; |
38 | |
39 | /* Return early if this is running on devices with different SoCs */ |
40 | if (!__mxc_cpu_type) |
41 | return 0; |
42 | |
43 | soc_dev_attr = kzalloc(size: sizeof(*soc_dev_attr), GFP_KERNEL); |
44 | if (!soc_dev_attr) |
45 | return -ENOMEM; |
46 | |
47 | soc_dev_attr->family = "Freescale i.MX" ; |
48 | |
49 | root = of_find_node_by_path(path: "/" ); |
50 | ret = of_property_read_string(np: root, propname: "model" , out_string: &soc_dev_attr->machine); |
51 | of_node_put(node: root); |
52 | if (ret) |
53 | goto free_soc; |
54 | |
55 | switch (__mxc_cpu_type) { |
56 | case MXC_CPU_MX1: |
57 | soc_id = "i.MX1" ; |
58 | break; |
59 | case MXC_CPU_MX21: |
60 | soc_id = "i.MX21" ; |
61 | break; |
62 | case MXC_CPU_MX25: |
63 | soc_id = "i.MX25" ; |
64 | break; |
65 | case MXC_CPU_MX27: |
66 | soc_id = "i.MX27" ; |
67 | break; |
68 | case MXC_CPU_MX31: |
69 | soc_id = "i.MX31" ; |
70 | break; |
71 | case MXC_CPU_MX35: |
72 | soc_id = "i.MX35" ; |
73 | break; |
74 | case MXC_CPU_MX50: |
75 | soc_id = "i.MX50" ; |
76 | break; |
77 | case MXC_CPU_MX51: |
78 | ocotp_compat = "fsl,imx51-iim" ; |
79 | soc_id = "i.MX51" ; |
80 | break; |
81 | case MXC_CPU_MX53: |
82 | ocotp_compat = "fsl,imx53-iim" ; |
83 | soc_id = "i.MX53" ; |
84 | break; |
85 | case MXC_CPU_IMX6SL: |
86 | ocotp_compat = "fsl,imx6sl-ocotp" ; |
87 | soc_id = "i.MX6SL" ; |
88 | break; |
89 | case MXC_CPU_IMX6DL: |
90 | ocotp_compat = "fsl,imx6q-ocotp" ; |
91 | soc_id = "i.MX6DL" ; |
92 | break; |
93 | case MXC_CPU_IMX6SX: |
94 | ocotp_compat = "fsl,imx6sx-ocotp" ; |
95 | soc_id = "i.MX6SX" ; |
96 | break; |
97 | case MXC_CPU_IMX6Q: |
98 | ocotp_compat = "fsl,imx6q-ocotp" ; |
99 | soc_id = "i.MX6Q" ; |
100 | break; |
101 | case MXC_CPU_IMX6UL: |
102 | ocotp_compat = "fsl,imx6ul-ocotp" ; |
103 | soc_id = "i.MX6UL" ; |
104 | break; |
105 | case MXC_CPU_IMX6ULL: |
106 | ocotp_compat = "fsl,imx6ull-ocotp" ; |
107 | soc_id = "i.MX6ULL" ; |
108 | break; |
109 | case MXC_CPU_IMX6ULZ: |
110 | ocotp_compat = "fsl,imx6ull-ocotp" ; |
111 | soc_id = "i.MX6ULZ" ; |
112 | break; |
113 | case MXC_CPU_IMX6SLL: |
114 | ocotp_compat = "fsl,imx6sll-ocotp" ; |
115 | soc_id = "i.MX6SLL" ; |
116 | break; |
117 | case MXC_CPU_IMX7D: |
118 | ocotp_compat = "fsl,imx7d-ocotp" ; |
119 | soc_id = "i.MX7D" ; |
120 | break; |
121 | case MXC_CPU_IMX7ULP: |
122 | ocotp_compat = "fsl,imx7ulp-ocotp" ; |
123 | soc_id = "i.MX7ULP" ; |
124 | break; |
125 | case MXC_CPU_VF500: |
126 | ocotp_compat = "fsl,vf610-ocotp" ; |
127 | soc_id = "VF500" ; |
128 | break; |
129 | case MXC_CPU_VF510: |
130 | ocotp_compat = "fsl,vf610-ocotp" ; |
131 | soc_id = "VF510" ; |
132 | break; |
133 | case MXC_CPU_VF600: |
134 | ocotp_compat = "fsl,vf610-ocotp" ; |
135 | soc_id = "VF600" ; |
136 | break; |
137 | case MXC_CPU_VF610: |
138 | ocotp_compat = "fsl,vf610-ocotp" ; |
139 | soc_id = "VF610" ; |
140 | break; |
141 | default: |
142 | soc_id = "Unknown" ; |
143 | } |
144 | soc_dev_attr->soc_id = soc_id; |
145 | |
146 | if (ocotp_compat) { |
147 | ocotp = syscon_regmap_lookup_by_compatible(s: ocotp_compat); |
148 | if (IS_ERR(ptr: ocotp)) |
149 | pr_err("%s: failed to find %s regmap!\n" , __func__, ocotp_compat); |
150 | } |
151 | |
152 | if (!IS_ERR_OR_NULL(ptr: ocotp)) { |
153 | if (__mxc_cpu_type == MXC_CPU_IMX7ULP) { |
154 | regmap_read(map: ocotp, OCOTP_ULP_UID_4, val: &val); |
155 | soc_uid = val & 0xffff; |
156 | regmap_read(map: ocotp, OCOTP_ULP_UID_3, val: &val); |
157 | soc_uid <<= 16; |
158 | soc_uid |= val & 0xffff; |
159 | regmap_read(map: ocotp, OCOTP_ULP_UID_2, val: &val); |
160 | soc_uid <<= 16; |
161 | soc_uid |= val & 0xffff; |
162 | regmap_read(map: ocotp, OCOTP_ULP_UID_1, val: &val); |
163 | soc_uid <<= 16; |
164 | soc_uid |= val & 0xffff; |
165 | } else if (__mxc_cpu_type == MXC_CPU_MX51 || |
166 | __mxc_cpu_type == MXC_CPU_MX53) { |
167 | for (i=0; i < 8; i++) { |
168 | regmap_read(map: ocotp, IIM_UID + i*4, val: &val); |
169 | soc_uid <<= 8; |
170 | soc_uid |= (val & 0xff); |
171 | } |
172 | } else { |
173 | regmap_read(map: ocotp, OCOTP_UID_H, val: &val); |
174 | soc_uid = val; |
175 | regmap_read(map: ocotp, OCOTP_UID_L, val: &val); |
176 | soc_uid <<= 32; |
177 | soc_uid |= val; |
178 | } |
179 | } |
180 | |
181 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, fmt: "%d.%d" , |
182 | (imx_get_soc_revision() >> 4) & 0xf, |
183 | imx_get_soc_revision() & 0xf); |
184 | if (!soc_dev_attr->revision) { |
185 | ret = -ENOMEM; |
186 | goto free_soc; |
187 | } |
188 | |
189 | soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, fmt: "%016llX" , soc_uid); |
190 | if (!soc_dev_attr->serial_number) { |
191 | ret = -ENOMEM; |
192 | goto free_rev; |
193 | } |
194 | |
195 | soc_dev = soc_device_register(soc_plat_dev_attr: soc_dev_attr); |
196 | if (IS_ERR(ptr: soc_dev)) { |
197 | ret = PTR_ERR(ptr: soc_dev); |
198 | goto free_serial_number; |
199 | } |
200 | |
201 | return 0; |
202 | |
203 | free_serial_number: |
204 | kfree(objp: soc_dev_attr->serial_number); |
205 | free_rev: |
206 | kfree(objp: soc_dev_attr->revision); |
207 | free_soc: |
208 | kfree(objp: soc_dev_attr); |
209 | return ret; |
210 | } |
211 | device_initcall(imx_soc_device_init); |
212 | |