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_rcar_gen5 __initconst __maybe_unused = { 40 .name = "R-Car Gen5", 41 }; 42 43 static const struct renesas_family fam_rmobile __initconst __maybe_unused = { 44 .name = "R-Mobile", 45 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ 46 }; 47 48 static const struct renesas_family fam_rza1 __initconst __maybe_unused = { 49 .name = "RZ/A1", 50 }; 51 52 static const struct renesas_family fam_rza2 __initconst __maybe_unused = { 53 .name = "RZ/A2", 54 }; 55 56 static const struct renesas_family fam_rzfive __initconst __maybe_unused = { 57 .name = "RZ/Five", 58 }; 59 60 static const struct renesas_family fam_rzg1 __initconst __maybe_unused = { 61 .name = "RZ/G1", 62 .reg = 0xff000044, /* PRR (Product Register) */ 63 }; 64 65 static const struct renesas_family fam_rzg2 __initconst __maybe_unused = { 66 .name = "RZ/G2", 67 .reg = 0xfff00044, /* PRR (Product Register) */ 68 }; 69 70 static const struct renesas_family fam_rzg2l __initconst __maybe_unused = { 71 .name = "RZ/G2L", 72 }; 73 74 static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = { 75 .name = "RZ/G2UL", 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_v2l __initconst __maybe_unused = { 176 .family = &fam_rzv2l, 177 .id = 0x8447447, 178 }; 179 180 static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = { 181 .family = &fam_rzv2m, 182 }; 183 184 static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { 185 .family = &fam_rcar_gen1, 186 }; 187 188 static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = { 189 .family = &fam_rcar_gen1, 190 .id = 0x3b, 191 }; 192 193 static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = { 194 .family = &fam_rcar_gen2, 195 .id = 0x45, 196 }; 197 198 static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = { 199 .family = &fam_rcar_gen2, 200 .id = 0x47, 201 }; 202 203 static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = { 204 .family = &fam_rcar_gen2, 205 .id = 0x4a, 206 }; 207 208 static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = { 209 .family = &fam_rcar_gen2, 210 .id = 0x4b, 211 }; 212 213 static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = { 214 .family = &fam_rcar_gen2, 215 .id = 0x4c, 216 }; 217 218 static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = { 219 .family = &fam_rcar_gen3, 220 .id = 0x4f, 221 }; 222 223 static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = { 224 .family = &fam_rcar_gen3, 225 .id = 0x52, 226 }; 227 228 static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = { 229 .family = &fam_rcar_gen3, 230 .id = 0x55, 231 }; 232 233 static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = { 234 .family = &fam_rcar_gen3, 235 .id = 0x54, 236 }; 237 238 static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = { 239 .family = &fam_rcar_gen3, 240 .id = 0x56, 241 }; 242 243 static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = { 244 .family = &fam_rcar_gen3, 245 .id = 0x57, 246 }; 247 248 static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = { 249 .family = &fam_rcar_gen3, 250 .id = 0x58, 251 }; 252 253 static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = { 254 .family = &fam_rcar_gen4, 255 .id = 0x59, 256 }; 257 258 static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = { 259 .family = &fam_rcar_gen4, 260 .id = 0x5a, 261 }; 262 263 static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = { 264 .family = &fam_rcar_gen4, 265 .id = 0x5c, 266 }; 267 268 static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = { 269 .family = &fam_rcar_gen4, 270 .id = 0x5d, 271 }; 272 273 static const struct renesas_soc soc_rcar_x5h __initconst __maybe_unused = { 274 .family = &fam_rcar_gen5, 275 .id = 0x60, 276 }; 277 278 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { 279 .family = &fam_shmobile, 280 .id = 0x37, 281 }; 282 283 static const struct of_device_id renesas_socs[] __initconst __maybe_unused = { 284 #ifdef CONFIG_ARCH_R7S72100 285 { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h }, 286 #endif 287 #ifdef CONFIG_ARCH_R7S9210 288 { .compatible = "renesas,r7s9210", .data = &soc_rz_a2m }, 289 #endif 290 #ifdef CONFIG_ARCH_R8A73A4 291 { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 }, 292 #endif 293 #ifdef CONFIG_ARCH_R8A7740 294 { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 }, 295 #endif 296 #ifdef CONFIG_ARCH_R8A7742 297 { .compatible = "renesas,r8a7742", .data = &soc_rz_g1h }, 298 #endif 299 #ifdef CONFIG_ARCH_R8A7743 300 { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m }, 301 #endif 302 #ifdef CONFIG_ARCH_R8A7744 303 { .compatible = "renesas,r8a7744", .data = &soc_rz_g1n }, 304 #endif 305 #ifdef CONFIG_ARCH_R8A7745 306 { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, 307 #endif 308 #ifdef CONFIG_ARCH_R8A77470 309 { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c }, 310 #endif 311 #ifdef CONFIG_ARCH_R8A774A1 312 { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m }, 313 #endif 314 #ifdef CONFIG_ARCH_R8A774B1 315 { .compatible = "renesas,r8a774b1", .data = &soc_rz_g2n }, 316 #endif 317 #ifdef CONFIG_ARCH_R8A774C0 318 { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e }, 319 #endif 320 #ifdef CONFIG_ARCH_R8A774E1 321 { .compatible = "renesas,r8a774e1", .data = &soc_rz_g2h }, 322 #endif 323 #ifdef CONFIG_ARCH_R8A7778 324 { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, 325 #endif 326 #ifdef CONFIG_ARCH_R8A7779 327 { .compatible = "renesas,r8a7779", .data = &soc_rcar_h1 }, 328 #endif 329 #ifdef CONFIG_ARCH_R8A7790 330 { .compatible = "renesas,r8a7790", .data = &soc_rcar_h2 }, 331 #endif 332 #ifdef CONFIG_ARCH_R8A7791 333 { .compatible = "renesas,r8a7791", .data = &soc_rcar_m2_w }, 334 #endif 335 #ifdef CONFIG_ARCH_R8A7792 336 { .compatible = "renesas,r8a7792", .data = &soc_rcar_v2h }, 337 #endif 338 #ifdef CONFIG_ARCH_R8A7793 339 { .compatible = "renesas,r8a7793", .data = &soc_rcar_m2_n }, 340 #endif 341 #ifdef CONFIG_ARCH_R8A7794 342 { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, 343 #endif 344 #ifdef CONFIG_ARCH_R8A77951 345 { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, 346 { .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 }, 347 { .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 }, 348 { .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 }, 349 { .compatible = "renesas,r8a779mb", .data = &soc_rcar_h3 }, 350 #endif 351 #ifdef CONFIG_ARCH_R8A77960 352 { .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w }, 353 #endif 354 #ifdef CONFIG_ARCH_R8A77961 355 { .compatible = "renesas,r8a77961", .data = &soc_rcar_m3_w }, 356 { .compatible = "renesas,r8a779m2", .data = &soc_rcar_m3_w }, 357 { .compatible = "renesas,r8a779m3", .data = &soc_rcar_m3_w }, 358 #endif 359 #ifdef CONFIG_ARCH_R8A77965 360 { .compatible = "renesas,r8a77965", .data = &soc_rcar_m3_n }, 361 { .compatible = "renesas,r8a779m4", .data = &soc_rcar_m3_n }, 362 { .compatible = "renesas,r8a779m5", .data = &soc_rcar_m3_n }, 363 #endif 364 #ifdef CONFIG_ARCH_R8A77970 365 { .compatible = "renesas,r8a77970", .data = &soc_rcar_v3m }, 366 #endif 367 #ifdef CONFIG_ARCH_R8A77980 368 { .compatible = "renesas,r8a77980", .data = &soc_rcar_v3h }, 369 #endif 370 #ifdef CONFIG_ARCH_R8A77990 371 { .compatible = "renesas,r8a77990", .data = &soc_rcar_e3 }, 372 { .compatible = "renesas,r8a779m6", .data = &soc_rcar_e3 }, 373 #endif 374 #ifdef CONFIG_ARCH_R8A77995 375 { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 }, 376 { .compatible = "renesas,r8a779m7", .data = &soc_rcar_d3 }, 377 #endif 378 #ifdef CONFIG_ARCH_R8A779A0 379 { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u }, 380 #endif 381 #ifdef CONFIG_ARCH_R8A779F0 382 { .compatible = "renesas,r8a779f0", .data = &soc_rcar_s4 }, 383 #endif 384 #ifdef CONFIG_ARCH_R8A779G0 385 { .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h }, 386 #endif 387 #ifdef CONFIG_ARCH_R8A779H0 388 { .compatible = "renesas,r8a779h0", .data = &soc_rcar_v4m }, 389 #endif 390 #ifdef CONFIG_ARCH_R8A78000 391 { .compatible = "renesas,r8a78000", .data = &soc_rcar_x5h }, 392 #endif 393 #ifdef CONFIG_ARCH_R9A07G043 394 #ifdef CONFIG_RISCV 395 { .compatible = "renesas,r9a07g043", .data = &soc_rz_five }, 396 #else 397 { .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul }, 398 #endif 399 #endif 400 #ifdef CONFIG_ARCH_R9A07G044 401 { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, 402 #endif 403 #ifdef CONFIG_ARCH_R9A07G054 404 { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l }, 405 #endif 406 #ifdef CONFIG_ARCH_R9A09G011 407 { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m }, 408 #endif 409 #ifdef CONFIG_ARCH_SH73A0 410 { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, 411 #endif 412 { /* sentinel */ } 413 }; 414 415 struct renesas_id { 416 unsigned int offset; 417 u32 mask; 418 }; 419 420 static const struct renesas_id id_bsid __initconst = { 421 .offset = 0, 422 .mask = 0xff0000, 423 /* 424 * TODO: Upper 4 bits of BSID are for chip version, but the format is 425 * not known at this time so we don't know how to specify eshi and eslo 426 */ 427 }; 428 429 static const struct renesas_id id_rzg2l __initconst = { 430 .offset = 0xa04, 431 .mask = 0xfffffff, 432 }; 433 434 static const struct renesas_id id_rzv2m __initconst = { 435 .offset = 0x104, 436 .mask = 0xff, 437 }; 438 439 static const struct renesas_id id_prr __initconst = { 440 .offset = 0, 441 .mask = 0xff00, 442 }; 443 444 static const struct of_device_id renesas_ids[] __initconst = { 445 { .compatible = "renesas,bsid", .data = &id_bsid }, 446 { .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l }, 447 { .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l }, 448 { .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l }, 449 { .compatible = "renesas,r9a08g045-sysc", .data = &id_rzg2l }, 450 { .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m }, 451 { .compatible = "renesas,prr", .data = &id_prr }, 452 { /* sentinel */ } 453 }; 454 455 static int __init renesas_soc_init(void) 456 { 457 struct soc_device_attribute *soc_dev_attr; 458 unsigned int product, eshi = 0, eslo; 459 const struct renesas_family *family; 460 const struct of_device_id *match; 461 const struct renesas_soc *soc; 462 const struct renesas_id *id; 463 void __iomem *chipid = NULL; 464 const char *rev_prefix = ""; 465 struct soc_device *soc_dev; 466 struct device_node *np; 467 const char *soc_id; 468 int ret; 469 470 match = of_match_node(renesas_socs, of_root); 471 if (!match) 472 return -ENODEV; 473 474 soc_id = strchr(match->compatible, ',') + 1; 475 soc = match->data; 476 family = soc->family; 477 478 np = of_find_matching_node_and_match(NULL, renesas_ids, &match); 479 if (np) { 480 id = match->data; 481 chipid = of_iomap(np, 0); 482 of_node_put(np); 483 } else if (soc->id && family->reg) { 484 /* Try hardcoded CCCR/PRR fallback */ 485 id = &id_prr; 486 chipid = ioremap(family->reg, 4); 487 } 488 489 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 490 if (!soc_dev_attr) { 491 if (chipid) 492 iounmap(chipid); 493 return -ENOMEM; 494 } 495 496 soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); 497 soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL); 498 499 if (chipid) { 500 product = readl(chipid + id->offset); 501 iounmap(chipid); 502 503 if (id == &id_prr) { 504 /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ 505 if ((product & 0x7fff) == 0x5210) 506 product ^= 0x11; 507 /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ 508 if ((product & 0x7fff) == 0x5211) 509 product ^= 0x12; 510 511 eshi = ((product >> 4) & 0x0f) + 1; 512 eslo = product & 0xf; 513 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", 514 eshi, eslo); 515 } else if (id == &id_rzg2l) { 516 eshi = ((product >> 28) & 0x0f); 517 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u", 518 eshi); 519 rev_prefix = "Rev "; 520 } else if (id == &id_rzv2m) { 521 eshi = ((product >> 4) & 0x0f); 522 eslo = product & 0xf; 523 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u.%u", 524 eshi, eslo); 525 } 526 527 if (soc->id && 528 ((product & id->mask) >> __ffs(id->mask)) != soc->id) { 529 pr_warn("SoC mismatch (product = 0x%x)\n", product); 530 ret = -ENODEV; 531 goto free_soc_dev_attr; 532 } 533 } 534 535 pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr->family, 536 soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: ""); 537 538 soc_dev = soc_device_register(soc_dev_attr); 539 if (IS_ERR(soc_dev)) { 540 ret = PTR_ERR(soc_dev); 541 goto free_soc_dev_attr; 542 } 543 544 return 0; 545 546 free_soc_dev_attr: 547 kfree(soc_dev_attr->revision); 548 kfree_const(soc_dev_attr->soc_id); 549 kfree_const(soc_dev_attr->family); 550 kfree(soc_dev_attr); 551 return ret; 552 } 553 early_initcall(renesas_soc_init); 554