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(renesas_socs, 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, renesas_ids, &match); 480 if (np) { 481 id = match->data; 482 chipid = of_iomap(np, 0); 483 of_node_put(np); 484 } else if (soc->id && family->reg) { 485 /* Try hardcoded CCCR/PRR fallback */ 486 id = &id_prr; 487 chipid = ioremap(family->reg, 4); 488 } 489 490 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 491 if (!soc_dev_attr) { 492 if (chipid) 493 iounmap(chipid); 494 return -ENOMEM; 495 } 496 497 soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); 498 soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL); 499 500 if (chipid) { 501 product = readl(chipid + id->offset); 502 iounmap(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, "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, "%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, "%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_dev_attr); 540 if (IS_ERR(soc_dev)) { 541 ret = PTR_ERR(soc_dev); 542 goto free_soc_dev_attr; 543 } 544 545 return 0; 546 547 free_soc_dev_attr: 548 kfree(soc_dev_attr->revision); 549 kfree_const(soc_dev_attr->soc_id); 550 kfree_const(soc_dev_attr->family); 551 kfree(soc_dev_attr); 552 return ret; 553 } 554 early_initcall(renesas_soc_init); 555