1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Renesas SoC Identification |
4 | * |
5 | * Copyright (C) 2014-2016 Glider bvba |
6 | */ |
7 | |
8 | #include <linux/io.h> |
9 | #include <linux/of.h> |
10 | #include <linux/of_address.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/string.h> |
13 | #include <linux/sys_soc.h> |
14 | |
15 | struct renesas_family { |
16 | const char name[16]; |
17 | u32 reg; /* CCCR or PRR, if not in DT */ |
18 | }; |
19 | |
20 | static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = { |
21 | .name = "R-Car Gen1" , |
22 | .reg = 0xff000044, /* PRR (Product Register) */ |
23 | }; |
24 | |
25 | static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = { |
26 | .name = "R-Car Gen2" , |
27 | .reg = 0xff000044, /* PRR (Product Register) */ |
28 | }; |
29 | |
30 | static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = { |
31 | .name = "R-Car Gen3" , |
32 | .reg = 0xfff00044, /* PRR (Product Register) */ |
33 | }; |
34 | |
35 | static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = { |
36 | .name = "R-Car Gen4" , |
37 | }; |
38 | |
39 | static const struct renesas_family fam_rmobile __initconst __maybe_unused = { |
40 | .name = "R-Mobile" , |
41 | .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ |
42 | }; |
43 | |
44 | static const struct renesas_family fam_rza1 __initconst __maybe_unused = { |
45 | .name = "RZ/A1" , |
46 | }; |
47 | |
48 | static const struct renesas_family fam_rza2 __initconst __maybe_unused = { |
49 | .name = "RZ/A2" , |
50 | }; |
51 | |
52 | static const struct renesas_family fam_rzfive __initconst __maybe_unused = { |
53 | .name = "RZ/Five" , |
54 | }; |
55 | |
56 | static const struct renesas_family fam_rzg1 __initconst __maybe_unused = { |
57 | .name = "RZ/G1" , |
58 | .reg = 0xff000044, /* PRR (Product Register) */ |
59 | }; |
60 | |
61 | static const struct renesas_family fam_rzg2 __initconst __maybe_unused = { |
62 | .name = "RZ/G2" , |
63 | .reg = 0xfff00044, /* PRR (Product Register) */ |
64 | }; |
65 | |
66 | static const struct renesas_family fam_rzg2l __initconst __maybe_unused = { |
67 | .name = "RZ/G2L" , |
68 | }; |
69 | |
70 | static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = { |
71 | .name = "RZ/G2UL" , |
72 | }; |
73 | |
74 | static const struct renesas_family fam_rzg3s __initconst __maybe_unused = { |
75 | .name = "RZ/G3S" , |
76 | }; |
77 | |
78 | static const struct renesas_family fam_rzv2l __initconst __maybe_unused = { |
79 | .name = "RZ/V2L" , |
80 | }; |
81 | |
82 | static const struct renesas_family fam_rzv2m __initconst __maybe_unused = { |
83 | .name = "RZ/V2M" , |
84 | }; |
85 | |
86 | static const struct renesas_family fam_shmobile __initconst __maybe_unused = { |
87 | .name = "SH-Mobile" , |
88 | .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ |
89 | }; |
90 | |
91 | struct renesas_soc { |
92 | const struct renesas_family *family; |
93 | u32 id; |
94 | }; |
95 | |
96 | static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { |
97 | .family = &fam_rza1, |
98 | }; |
99 | |
100 | static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = { |
101 | .family = &fam_rza2, |
102 | .id = 0x3b, |
103 | }; |
104 | |
105 | static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = { |
106 | .family = &fam_rmobile, |
107 | .id = 0x3f, |
108 | }; |
109 | |
110 | static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = { |
111 | .family = &fam_rmobile, |
112 | .id = 0x40, |
113 | }; |
114 | |
115 | static const struct renesas_soc soc_rz_five __initconst __maybe_unused = { |
116 | .family = &fam_rzfive, |
117 | .id = 0x847c447, |
118 | }; |
119 | |
120 | static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = { |
121 | .family = &fam_rzg1, |
122 | .id = 0x45, |
123 | }; |
124 | |
125 | static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { |
126 | .family = &fam_rzg1, |
127 | .id = 0x47, |
128 | }; |
129 | |
130 | static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = { |
131 | .family = &fam_rzg1, |
132 | .id = 0x4b, |
133 | }; |
134 | |
135 | static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { |
136 | .family = &fam_rzg1, |
137 | .id = 0x4c, |
138 | }; |
139 | |
140 | static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = { |
141 | .family = &fam_rzg1, |
142 | .id = 0x53, |
143 | }; |
144 | |
145 | static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = { |
146 | .family = &fam_rzg2, |
147 | .id = 0x52, |
148 | }; |
149 | |
150 | static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = { |
151 | .family = &fam_rzg2, |
152 | .id = 0x55, |
153 | }; |
154 | |
155 | static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = { |
156 | .family = &fam_rzg2, |
157 | .id = 0x57, |
158 | }; |
159 | |
160 | static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = { |
161 | .family = &fam_rzg2, |
162 | .id = 0x4f, |
163 | }; |
164 | |
165 | static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = { |
166 | .family = &fam_rzg2l, |
167 | .id = 0x841c447, |
168 | }; |
169 | |
170 | static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused = { |
171 | .family = &fam_rzg2ul, |
172 | .id = 0x8450447, |
173 | }; |
174 | |
175 | static const struct renesas_soc soc_rz_g3s __initconst __maybe_unused = { |
176 | .family = &fam_rzg3s, |
177 | .id = 0x85e0447, |
178 | }; |
179 | |
180 | static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = { |
181 | .family = &fam_rzv2l, |
182 | .id = 0x8447447, |
183 | }; |
184 | |
185 | static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = { |
186 | .family = &fam_rzv2m, |
187 | }; |
188 | |
189 | static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { |
190 | .family = &fam_rcar_gen1, |
191 | }; |
192 | |
193 | static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = { |
194 | .family = &fam_rcar_gen1, |
195 | .id = 0x3b, |
196 | }; |
197 | |
198 | static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = { |
199 | .family = &fam_rcar_gen2, |
200 | .id = 0x45, |
201 | }; |
202 | |
203 | static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = { |
204 | .family = &fam_rcar_gen2, |
205 | .id = 0x47, |
206 | }; |
207 | |
208 | static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = { |
209 | .family = &fam_rcar_gen2, |
210 | .id = 0x4a, |
211 | }; |
212 | |
213 | static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = { |
214 | .family = &fam_rcar_gen2, |
215 | .id = 0x4b, |
216 | }; |
217 | |
218 | static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = { |
219 | .family = &fam_rcar_gen2, |
220 | .id = 0x4c, |
221 | }; |
222 | |
223 | static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = { |
224 | .family = &fam_rcar_gen3, |
225 | .id = 0x4f, |
226 | }; |
227 | |
228 | static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = { |
229 | .family = &fam_rcar_gen3, |
230 | .id = 0x52, |
231 | }; |
232 | |
233 | static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = { |
234 | .family = &fam_rcar_gen3, |
235 | .id = 0x55, |
236 | }; |
237 | |
238 | static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = { |
239 | .family = &fam_rcar_gen3, |
240 | .id = 0x54, |
241 | }; |
242 | |
243 | static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = { |
244 | .family = &fam_rcar_gen3, |
245 | .id = 0x56, |
246 | }; |
247 | |
248 | static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = { |
249 | .family = &fam_rcar_gen3, |
250 | .id = 0x57, |
251 | }; |
252 | |
253 | static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = { |
254 | .family = &fam_rcar_gen3, |
255 | .id = 0x58, |
256 | }; |
257 | |
258 | static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = { |
259 | .family = &fam_rcar_gen4, |
260 | .id = 0x59, |
261 | }; |
262 | |
263 | static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = { |
264 | .family = &fam_rcar_gen4, |
265 | .id = 0x5a, |
266 | }; |
267 | |
268 | static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = { |
269 | .family = &fam_rcar_gen4, |
270 | .id = 0x5c, |
271 | }; |
272 | |
273 | static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = { |
274 | .family = &fam_rcar_gen4, |
275 | .id = 0x5d, |
276 | }; |
277 | |
278 | static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { |
279 | .family = &fam_shmobile, |
280 | .id = 0x37, |
281 | }; |
282 | |
283 | |
284 | static const struct of_device_id renesas_socs[] __initconst __maybe_unused = { |
285 | #ifdef CONFIG_ARCH_R7S72100 |
286 | { .compatible = "renesas,r7s72100" , .data = &soc_rz_a1h }, |
287 | #endif |
288 | #ifdef CONFIG_ARCH_R7S9210 |
289 | { .compatible = "renesas,r7s9210" , .data = &soc_rz_a2m }, |
290 | #endif |
291 | #ifdef CONFIG_ARCH_R8A73A4 |
292 | { .compatible = "renesas,r8a73a4" , .data = &soc_rmobile_ape6 }, |
293 | #endif |
294 | #ifdef CONFIG_ARCH_R8A7740 |
295 | { .compatible = "renesas,r8a7740" , .data = &soc_rmobile_a1 }, |
296 | #endif |
297 | #ifdef CONFIG_ARCH_R8A7742 |
298 | { .compatible = "renesas,r8a7742" , .data = &soc_rz_g1h }, |
299 | #endif |
300 | #ifdef CONFIG_ARCH_R8A7743 |
301 | { .compatible = "renesas,r8a7743" , .data = &soc_rz_g1m }, |
302 | #endif |
303 | #ifdef CONFIG_ARCH_R8A7744 |
304 | { .compatible = "renesas,r8a7744" , .data = &soc_rz_g1n }, |
305 | #endif |
306 | #ifdef CONFIG_ARCH_R8A7745 |
307 | { .compatible = "renesas,r8a7745" , .data = &soc_rz_g1e }, |
308 | #endif |
309 | #ifdef CONFIG_ARCH_R8A77470 |
310 | { .compatible = "renesas,r8a77470" , .data = &soc_rz_g1c }, |
311 | #endif |
312 | #ifdef CONFIG_ARCH_R8A774A1 |
313 | { .compatible = "renesas,r8a774a1" , .data = &soc_rz_g2m }, |
314 | #endif |
315 | #ifdef CONFIG_ARCH_R8A774B1 |
316 | { .compatible = "renesas,r8a774b1" , .data = &soc_rz_g2n }, |
317 | #endif |
318 | #ifdef CONFIG_ARCH_R8A774C0 |
319 | { .compatible = "renesas,r8a774c0" , .data = &soc_rz_g2e }, |
320 | #endif |
321 | #ifdef CONFIG_ARCH_R8A774E1 |
322 | { .compatible = "renesas,r8a774e1" , .data = &soc_rz_g2h }, |
323 | #endif |
324 | #ifdef CONFIG_ARCH_R8A7778 |
325 | { .compatible = "renesas,r8a7778" , .data = &soc_rcar_m1a }, |
326 | #endif |
327 | #ifdef CONFIG_ARCH_R8A7779 |
328 | { .compatible = "renesas,r8a7779" , .data = &soc_rcar_h1 }, |
329 | #endif |
330 | #ifdef CONFIG_ARCH_R8A7790 |
331 | { .compatible = "renesas,r8a7790" , .data = &soc_rcar_h2 }, |
332 | #endif |
333 | #ifdef CONFIG_ARCH_R8A7791 |
334 | { .compatible = "renesas,r8a7791" , .data = &soc_rcar_m2_w }, |
335 | #endif |
336 | #ifdef CONFIG_ARCH_R8A7792 |
337 | { .compatible = "renesas,r8a7792" , .data = &soc_rcar_v2h }, |
338 | #endif |
339 | #ifdef CONFIG_ARCH_R8A7793 |
340 | { .compatible = "renesas,r8a7793" , .data = &soc_rcar_m2_n }, |
341 | #endif |
342 | #ifdef CONFIG_ARCH_R8A7794 |
343 | { .compatible = "renesas,r8a7794" , .data = &soc_rcar_e2 }, |
344 | #endif |
345 | #ifdef CONFIG_ARCH_R8A77951 |
346 | { .compatible = "renesas,r8a7795" , .data = &soc_rcar_h3 }, |
347 | { .compatible = "renesas,r8a779m0" , .data = &soc_rcar_h3 }, |
348 | { .compatible = "renesas,r8a779m1" , .data = &soc_rcar_h3 }, |
349 | { .compatible = "renesas,r8a779m8" , .data = &soc_rcar_h3 }, |
350 | { .compatible = "renesas,r8a779mb" , .data = &soc_rcar_h3 }, |
351 | #endif |
352 | #ifdef CONFIG_ARCH_R8A77960 |
353 | { .compatible = "renesas,r8a7796" , .data = &soc_rcar_m3_w }, |
354 | #endif |
355 | #ifdef CONFIG_ARCH_R8A77961 |
356 | { .compatible = "renesas,r8a77961" , .data = &soc_rcar_m3_w }, |
357 | { .compatible = "renesas,r8a779m2" , .data = &soc_rcar_m3_w }, |
358 | { .compatible = "renesas,r8a779m3" , .data = &soc_rcar_m3_w }, |
359 | #endif |
360 | #ifdef CONFIG_ARCH_R8A77965 |
361 | { .compatible = "renesas,r8a77965" , .data = &soc_rcar_m3_n }, |
362 | { .compatible = "renesas,r8a779m4" , .data = &soc_rcar_m3_n }, |
363 | { .compatible = "renesas,r8a779m5" , .data = &soc_rcar_m3_n }, |
364 | #endif |
365 | #ifdef CONFIG_ARCH_R8A77970 |
366 | { .compatible = "renesas,r8a77970" , .data = &soc_rcar_v3m }, |
367 | #endif |
368 | #ifdef CONFIG_ARCH_R8A77980 |
369 | { .compatible = "renesas,r8a77980" , .data = &soc_rcar_v3h }, |
370 | #endif |
371 | #ifdef CONFIG_ARCH_R8A77990 |
372 | { .compatible = "renesas,r8a77990" , .data = &soc_rcar_e3 }, |
373 | { .compatible = "renesas,r8a779m6" , .data = &soc_rcar_e3 }, |
374 | #endif |
375 | #ifdef CONFIG_ARCH_R8A77995 |
376 | { .compatible = "renesas,r8a77995" , .data = &soc_rcar_d3 }, |
377 | { .compatible = "renesas,r8a779m7" , .data = &soc_rcar_d3 }, |
378 | #endif |
379 | #ifdef CONFIG_ARCH_R8A779A0 |
380 | { .compatible = "renesas,r8a779a0" , .data = &soc_rcar_v3u }, |
381 | #endif |
382 | #ifdef CONFIG_ARCH_R8A779F0 |
383 | { .compatible = "renesas,r8a779f0" , .data = &soc_rcar_s4 }, |
384 | #endif |
385 | #ifdef CONFIG_ARCH_R8A779G0 |
386 | { .compatible = "renesas,r8a779g0" , .data = &soc_rcar_v4h }, |
387 | #endif |
388 | #ifdef CONFIG_ARCH_R8A779H0 |
389 | { .compatible = "renesas,r8a779h0" , .data = &soc_rcar_v4m }, |
390 | #endif |
391 | #ifdef CONFIG_ARCH_R9A07G043 |
392 | #ifdef CONFIG_RISCV |
393 | { .compatible = "renesas,r9a07g043" , .data = &soc_rz_five }, |
394 | #else |
395 | { .compatible = "renesas,r9a07g043" , .data = &soc_rz_g2ul }, |
396 | #endif |
397 | #endif |
398 | #ifdef CONFIG_ARCH_R9A07G044 |
399 | { .compatible = "renesas,r9a07g044" , .data = &soc_rz_g2l }, |
400 | #endif |
401 | #ifdef CONFIG_ARCH_R9A07G054 |
402 | { .compatible = "renesas,r9a07g054" , .data = &soc_rz_v2l }, |
403 | #endif |
404 | #ifdef CONFIG_ARCH_R9A08G045 |
405 | { .compatible = "renesas,r9a08g045" , .data = &soc_rz_g3s }, |
406 | #endif |
407 | #ifdef CONFIG_ARCH_R9A09G011 |
408 | { .compatible = "renesas,r9a09g011" , .data = &soc_rz_v2m }, |
409 | #endif |
410 | #ifdef CONFIG_ARCH_SH73A0 |
411 | { .compatible = "renesas,sh73a0" , .data = &soc_shmobile_ag5 }, |
412 | #endif |
413 | { /* sentinel */ } |
414 | }; |
415 | |
416 | struct renesas_id { |
417 | unsigned int offset; |
418 | u32 mask; |
419 | }; |
420 | |
421 | static const struct renesas_id id_bsid __initconst = { |
422 | .offset = 0, |
423 | .mask = 0xff0000, |
424 | /* |
425 | * TODO: Upper 4 bits of BSID are for chip version, but the format is |
426 | * not known at this time so we don't know how to specify eshi and eslo |
427 | */ |
428 | }; |
429 | |
430 | static const struct renesas_id id_rzg2l __initconst = { |
431 | .offset = 0xa04, |
432 | .mask = 0xfffffff, |
433 | }; |
434 | |
435 | static const struct renesas_id id_rzv2m __initconst = { |
436 | .offset = 0x104, |
437 | .mask = 0xff, |
438 | }; |
439 | |
440 | static const struct renesas_id id_prr __initconst = { |
441 | .offset = 0, |
442 | .mask = 0xff00, |
443 | }; |
444 | |
445 | static const struct of_device_id renesas_ids[] __initconst = { |
446 | { .compatible = "renesas,bsid" , .data = &id_bsid }, |
447 | { .compatible = "renesas,r9a07g043-sysc" , .data = &id_rzg2l }, |
448 | { .compatible = "renesas,r9a07g044-sysc" , .data = &id_rzg2l }, |
449 | { .compatible = "renesas,r9a07g054-sysc" , .data = &id_rzg2l }, |
450 | { .compatible = "renesas,r9a08g045-sysc" , .data = &id_rzg2l }, |
451 | { .compatible = "renesas,r9a09g011-sys" , .data = &id_rzv2m }, |
452 | { .compatible = "renesas,prr" , .data = &id_prr }, |
453 | { /* sentinel */ } |
454 | }; |
455 | |
456 | static int __init renesas_soc_init(void) |
457 | { |
458 | struct soc_device_attribute *soc_dev_attr; |
459 | unsigned int product, eshi = 0, eslo; |
460 | const struct renesas_family *family; |
461 | const struct of_device_id *match; |
462 | const struct renesas_soc *soc; |
463 | const struct renesas_id *id; |
464 | void __iomem *chipid = NULL; |
465 | const char *rev_prefix = "" ; |
466 | struct soc_device *soc_dev; |
467 | struct device_node *np; |
468 | const char *soc_id; |
469 | int ret; |
470 | |
471 | match = of_match_node(matches: renesas_socs, node: of_root); |
472 | if (!match) |
473 | return -ENODEV; |
474 | |
475 | soc_id = strchr(match->compatible, ',') + 1; |
476 | soc = match->data; |
477 | family = soc->family; |
478 | |
479 | np = of_find_matching_node_and_match(NULL, matches: renesas_ids, match: &match); |
480 | if (np) { |
481 | id = match->data; |
482 | chipid = of_iomap(node: np, index: 0); |
483 | of_node_put(node: np); |
484 | } else if (soc->id && family->reg) { |
485 | /* Try hardcoded CCCR/PRR fallback */ |
486 | id = &id_prr; |
487 | chipid = ioremap(offset: family->reg, size: 4); |
488 | } |
489 | |
490 | soc_dev_attr = kzalloc(size: sizeof(*soc_dev_attr), GFP_KERNEL); |
491 | if (!soc_dev_attr) { |
492 | if (chipid) |
493 | iounmap(addr: chipid); |
494 | return -ENOMEM; |
495 | } |
496 | |
497 | soc_dev_attr->family = kstrdup_const(s: family->name, GFP_KERNEL); |
498 | soc_dev_attr->soc_id = kstrdup_const(s: soc_id, GFP_KERNEL); |
499 | |
500 | if (chipid) { |
501 | product = readl(addr: chipid + id->offset); |
502 | iounmap(addr: chipid); |
503 | |
504 | if (id == &id_prr) { |
505 | /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ |
506 | if ((product & 0x7fff) == 0x5210) |
507 | product ^= 0x11; |
508 | /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ |
509 | if ((product & 0x7fff) == 0x5211) |
510 | product ^= 0x12; |
511 | |
512 | eshi = ((product >> 4) & 0x0f) + 1; |
513 | eslo = product & 0xf; |
514 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, fmt: "ES%u.%u" , |
515 | eshi, eslo); |
516 | } else if (id == &id_rzg2l) { |
517 | eshi = ((product >> 28) & 0x0f); |
518 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, fmt: "%u" , |
519 | eshi); |
520 | rev_prefix = "Rev " ; |
521 | } else if (id == &id_rzv2m) { |
522 | eshi = ((product >> 4) & 0x0f); |
523 | eslo = product & 0xf; |
524 | soc_dev_attr->revision = kasprintf(GFP_KERNEL, fmt: "%u.%u" , |
525 | eshi, eslo); |
526 | } |
527 | |
528 | if (soc->id && |
529 | ((product & id->mask) >> __ffs(id->mask)) != soc->id) { |
530 | pr_warn("SoC mismatch (product = 0x%x)\n" , product); |
531 | ret = -ENODEV; |
532 | goto free_soc_dev_attr; |
533 | } |
534 | } |
535 | |
536 | pr_info("Detected Renesas %s %s %s%s\n" , soc_dev_attr->family, |
537 | soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: "" ); |
538 | |
539 | soc_dev = soc_device_register(soc_plat_dev_attr: soc_dev_attr); |
540 | if (IS_ERR(ptr: soc_dev)) { |
541 | ret = PTR_ERR(ptr: soc_dev); |
542 | goto free_soc_dev_attr; |
543 | } |
544 | |
545 | return 0; |
546 | |
547 | free_soc_dev_attr: |
548 | kfree(objp: soc_dev_attr->revision); |
549 | kfree_const(x: soc_dev_attr->soc_id); |
550 | kfree_const(x: soc_dev_attr->family); |
551 | kfree(objp: soc_dev_attr); |
552 | return ret; |
553 | } |
554 | early_initcall(renesas_soc_init); |
555 | |