1 // SPDX-License-Identifier: GPL-2.0
3 * Renesas SoC Identification
5 * Copyright (C) 2014-2016 Glider bvba
10 #include <linux/of_address.h>
11 #include <linux/slab.h>
12 #include <linux/string.h>
13 #include <linux/sys_soc.h>
15 struct renesas_family
{
17 u32 reg
; /* CCCR or PRR, if not in DT */
20 static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused
= {
22 .reg
= 0xff000044, /* PRR (Product Register) */
25 static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused
= {
27 .reg
= 0xff000044, /* PRR (Product Register) */
30 static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused
= {
32 .reg
= 0xfff00044, /* PRR (Product Register) */
35 static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused
= {
39 static const struct renesas_family fam_rmobile __initconst __maybe_unused
= {
41 .reg
= 0xe600101c, /* CCCR (Common Chip Code Register) */
44 static const struct renesas_family fam_rza1 __initconst __maybe_unused
= {
48 static const struct renesas_family fam_rza2 __initconst __maybe_unused
= {
52 static const struct renesas_family fam_rzfive __initconst __maybe_unused
= {
56 static const struct renesas_family fam_rzg1 __initconst __maybe_unused
= {
58 .reg
= 0xff000044, /* PRR (Product Register) */
61 static const struct renesas_family fam_rzg2 __initconst __maybe_unused
= {
63 .reg
= 0xfff00044, /* PRR (Product Register) */
66 static const struct renesas_family fam_rzg2l __initconst __maybe_unused
= {
70 static const struct renesas_family fam_rzg2ul __initconst __maybe_unused
= {
74 static const struct renesas_family fam_rzg3s __initconst __maybe_unused
= {
78 static const struct renesas_family fam_rzv2l __initconst __maybe_unused
= {
82 static const struct renesas_family fam_rzv2m __initconst __maybe_unused
= {
86 static const struct renesas_family fam_shmobile __initconst __maybe_unused
= {
88 .reg
= 0xe600101c, /* CCCR (Common Chip Code Register) */
92 const struct renesas_family
*family
;
96 static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused
= {
100 static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused
= {
105 static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused
= {
106 .family
= &fam_rmobile
,
110 static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused
= {
111 .family
= &fam_rmobile
,
115 static const struct renesas_soc soc_rz_five __initconst __maybe_unused
= {
116 .family
= &fam_rzfive
,
120 static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused
= {
125 static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused
= {
130 static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused
= {
135 static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused
= {
140 static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused
= {
145 static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused
= {
150 static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused
= {
155 static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused
= {
160 static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused
= {
165 static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused
= {
166 .family
= &fam_rzg2l
,
170 static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused
= {
171 .family
= &fam_rzg2ul
,
175 static const struct renesas_soc soc_rz_g3s __initconst __maybe_unused
= {
176 .family
= &fam_rzg3s
,
180 static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused
= {
181 .family
= &fam_rzv2l
,
185 static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused
= {
186 .family
= &fam_rzv2m
,
189 static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused
= {
190 .family
= &fam_rcar_gen1
,
193 static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused
= {
194 .family
= &fam_rcar_gen1
,
198 static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused
= {
199 .family
= &fam_rcar_gen2
,
203 static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused
= {
204 .family
= &fam_rcar_gen2
,
208 static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused
= {
209 .family
= &fam_rcar_gen2
,
213 static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused
= {
214 .family
= &fam_rcar_gen2
,
218 static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused
= {
219 .family
= &fam_rcar_gen2
,
223 static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused
= {
224 .family
= &fam_rcar_gen3
,
228 static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused
= {
229 .family
= &fam_rcar_gen3
,
233 static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused
= {
234 .family
= &fam_rcar_gen3
,
238 static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused
= {
239 .family
= &fam_rcar_gen3
,
243 static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused
= {
244 .family
= &fam_rcar_gen3
,
248 static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused
= {
249 .family
= &fam_rcar_gen3
,
253 static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused
= {
254 .family
= &fam_rcar_gen3
,
258 static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused
= {
259 .family
= &fam_rcar_gen4
,
263 static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused
= {
264 .family
= &fam_rcar_gen4
,
268 static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused
= {
269 .family
= &fam_rcar_gen4
,
273 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused
= {
274 .family
= &fam_shmobile
,
279 static const struct of_device_id renesas_socs
[] __initconst __maybe_unused
= {
280 #ifdef CONFIG_ARCH_R7S72100
281 { .compatible
= "renesas,r7s72100", .data
= &soc_rz_a1h
},
283 #ifdef CONFIG_ARCH_R7S9210
284 { .compatible
= "renesas,r7s9210", .data
= &soc_rz_a2m
},
286 #ifdef CONFIG_ARCH_R8A73A4
287 { .compatible
= "renesas,r8a73a4", .data
= &soc_rmobile_ape6
},
289 #ifdef CONFIG_ARCH_R8A7740
290 { .compatible
= "renesas,r8a7740", .data
= &soc_rmobile_a1
},
292 #ifdef CONFIG_ARCH_R8A7742
293 { .compatible
= "renesas,r8a7742", .data
= &soc_rz_g1h
},
295 #ifdef CONFIG_ARCH_R8A7743
296 { .compatible
= "renesas,r8a7743", .data
= &soc_rz_g1m
},
298 #ifdef CONFIG_ARCH_R8A7744
299 { .compatible
= "renesas,r8a7744", .data
= &soc_rz_g1n
},
301 #ifdef CONFIG_ARCH_R8A7745
302 { .compatible
= "renesas,r8a7745", .data
= &soc_rz_g1e
},
304 #ifdef CONFIG_ARCH_R8A77470
305 { .compatible
= "renesas,r8a77470", .data
= &soc_rz_g1c
},
307 #ifdef CONFIG_ARCH_R8A774A1
308 { .compatible
= "renesas,r8a774a1", .data
= &soc_rz_g2m
},
310 #ifdef CONFIG_ARCH_R8A774B1
311 { .compatible
= "renesas,r8a774b1", .data
= &soc_rz_g2n
},
313 #ifdef CONFIG_ARCH_R8A774C0
314 { .compatible
= "renesas,r8a774c0", .data
= &soc_rz_g2e
},
316 #ifdef CONFIG_ARCH_R8A774E1
317 { .compatible
= "renesas,r8a774e1", .data
= &soc_rz_g2h
},
319 #ifdef CONFIG_ARCH_R8A7778
320 { .compatible
= "renesas,r8a7778", .data
= &soc_rcar_m1a
},
322 #ifdef CONFIG_ARCH_R8A7779
323 { .compatible
= "renesas,r8a7779", .data
= &soc_rcar_h1
},
325 #ifdef CONFIG_ARCH_R8A7790
326 { .compatible
= "renesas,r8a7790", .data
= &soc_rcar_h2
},
328 #ifdef CONFIG_ARCH_R8A7791
329 { .compatible
= "renesas,r8a7791", .data
= &soc_rcar_m2_w
},
331 #ifdef CONFIG_ARCH_R8A7792
332 { .compatible
= "renesas,r8a7792", .data
= &soc_rcar_v2h
},
334 #ifdef CONFIG_ARCH_R8A7793
335 { .compatible
= "renesas,r8a7793", .data
= &soc_rcar_m2_n
},
337 #ifdef CONFIG_ARCH_R8A7794
338 { .compatible
= "renesas,r8a7794", .data
= &soc_rcar_e2
},
340 #ifdef CONFIG_ARCH_R8A77951
341 { .compatible
= "renesas,r8a7795", .data
= &soc_rcar_h3
},
342 { .compatible
= "renesas,r8a779m0", .data
= &soc_rcar_h3
},
343 { .compatible
= "renesas,r8a779m1", .data
= &soc_rcar_h3
},
344 { .compatible
= "renesas,r8a779m8", .data
= &soc_rcar_h3
},
345 { .compatible
= "renesas,r8a779mb", .data
= &soc_rcar_h3
},
347 #ifdef CONFIG_ARCH_R8A77960
348 { .compatible
= "renesas,r8a7796", .data
= &soc_rcar_m3_w
},
350 #ifdef CONFIG_ARCH_R8A77961
351 { .compatible
= "renesas,r8a77961", .data
= &soc_rcar_m3_w
},
352 { .compatible
= "renesas,r8a779m2", .data
= &soc_rcar_m3_w
},
353 { .compatible
= "renesas,r8a779m3", .data
= &soc_rcar_m3_w
},
355 #ifdef CONFIG_ARCH_R8A77965
356 { .compatible
= "renesas,r8a77965", .data
= &soc_rcar_m3_n
},
357 { .compatible
= "renesas,r8a779m4", .data
= &soc_rcar_m3_n
},
358 { .compatible
= "renesas,r8a779m5", .data
= &soc_rcar_m3_n
},
360 #ifdef CONFIG_ARCH_R8A77970
361 { .compatible
= "renesas,r8a77970", .data
= &soc_rcar_v3m
},
363 #ifdef CONFIG_ARCH_R8A77980
364 { .compatible
= "renesas,r8a77980", .data
= &soc_rcar_v3h
},
366 #ifdef CONFIG_ARCH_R8A77990
367 { .compatible
= "renesas,r8a77990", .data
= &soc_rcar_e3
},
368 { .compatible
= "renesas,r8a779m6", .data
= &soc_rcar_e3
},
370 #ifdef CONFIG_ARCH_R8A77995
371 { .compatible
= "renesas,r8a77995", .data
= &soc_rcar_d3
},
372 { .compatible
= "renesas,r8a779m7", .data
= &soc_rcar_d3
},
374 #ifdef CONFIG_ARCH_R8A779A0
375 { .compatible
= "renesas,r8a779a0", .data
= &soc_rcar_v3u
},
377 #ifdef CONFIG_ARCH_R8A779F0
378 { .compatible
= "renesas,r8a779f0", .data
= &soc_rcar_s4
},
380 #ifdef CONFIG_ARCH_R8A779G0
381 { .compatible
= "renesas,r8a779g0", .data
= &soc_rcar_v4h
},
383 #ifdef CONFIG_ARCH_R9A07G043
385 { .compatible
= "renesas,r9a07g043", .data
= &soc_rz_five
},
387 { .compatible
= "renesas,r9a07g043", .data
= &soc_rz_g2ul
},
390 #ifdef CONFIG_ARCH_R9A07G044
391 { .compatible
= "renesas,r9a07g044", .data
= &soc_rz_g2l
},
393 #ifdef CONFIG_ARCH_R9A07G054
394 { .compatible
= "renesas,r9a07g054", .data
= &soc_rz_v2l
},
396 #ifdef CONFIG_ARCH_R9A08G045
397 { .compatible
= "renesas,r9a08g045", .data
= &soc_rz_g3s
},
399 #ifdef CONFIG_ARCH_R9A09G011
400 { .compatible
= "renesas,r9a09g011", .data
= &soc_rz_v2m
},
402 #ifdef CONFIG_ARCH_SH73A0
403 { .compatible
= "renesas,sh73a0", .data
= &soc_shmobile_ag5
},
413 static const struct renesas_id id_bsid __initconst
= {
417 * TODO: Upper 4 bits of BSID are for chip version, but the format is
418 * not known at this time so we don't know how to specify eshi and eslo
422 static const struct renesas_id id_rzg2l __initconst
= {
427 static const struct renesas_id id_rzv2m __initconst
= {
432 static const struct renesas_id id_prr __initconst
= {
437 static const struct of_device_id renesas_ids
[] __initconst
= {
438 { .compatible
= "renesas,bsid", .data
= &id_bsid
},
439 { .compatible
= "renesas,r9a07g043-sysc", .data
= &id_rzg2l
},
440 { .compatible
= "renesas,r9a07g044-sysc", .data
= &id_rzg2l
},
441 { .compatible
= "renesas,r9a07g054-sysc", .data
= &id_rzg2l
},
442 { .compatible
= "renesas,r9a08g045-sysc", .data
= &id_rzg2l
},
443 { .compatible
= "renesas,r9a09g011-sys", .data
= &id_rzv2m
},
444 { .compatible
= "renesas,prr", .data
= &id_prr
},
448 static int __init
renesas_soc_init(void)
450 struct soc_device_attribute
*soc_dev_attr
;
451 unsigned int product
, eshi
= 0, eslo
;
452 const struct renesas_family
*family
;
453 const struct of_device_id
*match
;
454 const struct renesas_soc
*soc
;
455 const struct renesas_id
*id
;
456 void __iomem
*chipid
= NULL
;
457 const char *rev_prefix
= "";
458 struct soc_device
*soc_dev
;
459 struct device_node
*np
;
463 match
= of_match_node(renesas_socs
, of_root
);
467 soc_id
= strchr(match
->compatible
, ',') + 1;
469 family
= soc
->family
;
471 np
= of_find_matching_node_and_match(NULL
, renesas_ids
, &match
);
474 chipid
= of_iomap(np
, 0);
476 } else if (soc
->id
&& family
->reg
) {
477 /* Try hardcoded CCCR/PRR fallback */
479 chipid
= ioremap(family
->reg
, 4);
482 soc_dev_attr
= kzalloc(sizeof(*soc_dev_attr
), GFP_KERNEL
);
489 soc_dev_attr
->family
= kstrdup_const(family
->name
, GFP_KERNEL
);
490 soc_dev_attr
->soc_id
= kstrdup_const(soc_id
, GFP_KERNEL
);
493 product
= readl(chipid
+ id
->offset
);
497 /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
498 if ((product
& 0x7fff) == 0x5210)
500 /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
501 if ((product
& 0x7fff) == 0x5211)
504 eshi
= ((product
>> 4) & 0x0f) + 1;
505 eslo
= product
& 0xf;
506 soc_dev_attr
->revision
= kasprintf(GFP_KERNEL
, "ES%u.%u",
508 } else if (id
== &id_rzg2l
) {
509 eshi
= ((product
>> 28) & 0x0f);
510 soc_dev_attr
->revision
= kasprintf(GFP_KERNEL
, "%u",
513 } else if (id
== &id_rzv2m
) {
514 eshi
= ((product
>> 4) & 0x0f);
515 eslo
= product
& 0xf;
516 soc_dev_attr
->revision
= kasprintf(GFP_KERNEL
, "%u.%u",
521 ((product
& id
->mask
) >> __ffs(id
->mask
)) != soc
->id
) {
522 pr_warn("SoC mismatch (product = 0x%x)\n", product
);
524 goto free_soc_dev_attr
;
528 pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr
->family
,
529 soc_dev_attr
->soc_id
, rev_prefix
, soc_dev_attr
->revision
?: "");
531 soc_dev
= soc_device_register(soc_dev_attr
);
532 if (IS_ERR(soc_dev
)) {
533 ret
= PTR_ERR(soc_dev
);
534 goto free_soc_dev_attr
;
540 kfree(soc_dev_attr
->revision
);
541 kfree_const(soc_dev_attr
->soc_id
);
542 kfree_const(soc_dev_attr
->family
);
546 early_initcall(renesas_soc_init
);