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