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_shmobile_ag5 __initconst __maybe_unused = { 274 .family = &fam_shmobile, 275 .id = 0x37, 276 }; 277 278 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 }, 282 #endif 283 #ifdef CONFIG_ARCH_R7S9210 284 { .compatible = "renesas,r7s9210", .data = &soc_rz_a2m }, 285 #endif 286 #ifdef CONFIG_ARCH_R8A73A4 287 { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 }, 288 #endif 289 #ifdef CONFIG_ARCH_R8A7740 290 { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 }, 291 #endif 292 #ifdef CONFIG_ARCH_R8A7742 293 { .compatible = "renesas,r8a7742", .data = &soc_rz_g1h }, 294 #endif 295 #ifdef CONFIG_ARCH_R8A7743 296 { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m }, 297 #endif 298 #ifdef CONFIG_ARCH_R8A7744 299 { .compatible = "renesas,r8a7744", .data = &soc_rz_g1n }, 300 #endif 301 #ifdef CONFIG_ARCH_R8A7745 302 { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, 303 #endif 304 #ifdef CONFIG_ARCH_R8A77470 305 { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c }, 306 #endif 307 #ifdef CONFIG_ARCH_R8A774A1 308 { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m }, 309 #endif 310 #ifdef CONFIG_ARCH_R8A774B1 311 { .compatible = "renesas,r8a774b1", .data = &soc_rz_g2n }, 312 #endif 313 #ifdef CONFIG_ARCH_R8A774C0 314 { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e }, 315 #endif 316 #ifdef CONFIG_ARCH_R8A774E1 317 { .compatible = "renesas,r8a774e1", .data = &soc_rz_g2h }, 318 #endif 319 #ifdef CONFIG_ARCH_R8A7778 320 { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, 321 #endif 322 #ifdef CONFIG_ARCH_R8A7779 323 { .compatible = "renesas,r8a7779", .data = &soc_rcar_h1 }, 324 #endif 325 #ifdef CONFIG_ARCH_R8A7790 326 { .compatible = "renesas,r8a7790", .data = &soc_rcar_h2 }, 327 #endif 328 #ifdef CONFIG_ARCH_R8A7791 329 { .compatible = "renesas,r8a7791", .data = &soc_rcar_m2_w }, 330 #endif 331 #ifdef CONFIG_ARCH_R8A7792 332 { .compatible = "renesas,r8a7792", .data = &soc_rcar_v2h }, 333 #endif 334 #ifdef CONFIG_ARCH_R8A7793 335 { .compatible = "renesas,r8a7793", .data = &soc_rcar_m2_n }, 336 #endif 337 #ifdef CONFIG_ARCH_R8A7794 338 { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, 339 #endif 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 }, 346 #endif 347 #ifdef CONFIG_ARCH_R8A77960 348 { .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w }, 349 #endif 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 }, 354 #endif 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 }, 359 #endif 360 #ifdef CONFIG_ARCH_R8A77970 361 { .compatible = "renesas,r8a77970", .data = &soc_rcar_v3m }, 362 #endif 363 #ifdef CONFIG_ARCH_R8A77980 364 { .compatible = "renesas,r8a77980", .data = &soc_rcar_v3h }, 365 #endif 366 #ifdef CONFIG_ARCH_R8A77990 367 { .compatible = "renesas,r8a77990", .data = &soc_rcar_e3 }, 368 { .compatible = "renesas,r8a779m6", .data = &soc_rcar_e3 }, 369 #endif 370 #ifdef CONFIG_ARCH_R8A77995 371 { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 }, 372 { .compatible = "renesas,r8a779m7", .data = &soc_rcar_d3 }, 373 #endif 374 #ifdef CONFIG_ARCH_R8A779A0 375 { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u }, 376 #endif 377 #ifdef CONFIG_ARCH_R8A779F0 378 { .compatible = "renesas,r8a779f0", .data = &soc_rcar_s4 }, 379 #endif 380 #ifdef CONFIG_ARCH_R8A779G0 381 { .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h }, 382 #endif 383 #ifdef CONFIG_ARCH_R9A07G043 384 #ifdef CONFIG_RISCV 385 { .compatible = "renesas,r9a07g043", .data = &soc_rz_five }, 386 #else 387 { .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul }, 388 #endif 389 #endif 390 #ifdef CONFIG_ARCH_R9A07G044 391 { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, 392 #endif 393 #ifdef CONFIG_ARCH_R9A07G054 394 { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l }, 395 #endif 396 #ifdef CONFIG_ARCH_R9A08G045 397 { .compatible = "renesas,r9a08g045", .data = &soc_rz_g3s }, 398 #endif 399 #ifdef CONFIG_ARCH_R9A09G011 400 { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m }, 401 #endif 402 #ifdef CONFIG_ARCH_SH73A0 403 { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, 404 #endif 405 { /* sentinel */ } 406 }; 407 408 struct renesas_id { 409 unsigned int offset; 410 u32 mask; 411 }; 412 413 static const struct renesas_id id_bsid __initconst = { 414 .offset = 0, 415 .mask = 0xff0000, 416 /* 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 419 */ 420 }; 421 422 static const struct renesas_id id_rzg2l __initconst = { 423 .offset = 0xa04, 424 .mask = 0xfffffff, 425 }; 426 427 static const struct renesas_id id_rzv2m __initconst = { 428 .offset = 0x104, 429 .mask = 0xff, 430 }; 431 432 static const struct renesas_id id_prr __initconst = { 433 .offset = 0, 434 .mask = 0xff00, 435 }; 436 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 }, 445 { /* sentinel */ } 446 }; 447 448 static int __init renesas_soc_init(void) 449 { 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; 460 const char *soc_id; 461 int ret; 462 463 match = of_match_node(renesas_socs, of_root); 464 if (!match) 465 return -ENODEV; 466 467 soc_id = strchr(match->compatible, ',') + 1; 468 soc = match->data; 469 family = soc->family; 470 471 np = of_find_matching_node_and_match(NULL, renesas_ids, &match); 472 if (np) { 473 id = match->data; 474 chipid = of_iomap(np, 0); 475 of_node_put(np); 476 } else if (soc->id && family->reg) { 477 /* Try hardcoded CCCR/PRR fallback */ 478 id = &id_prr; 479 chipid = ioremap(family->reg, 4); 480 } 481 482 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 483 if (!soc_dev_attr) { 484 if (chipid) 485 iounmap(chipid); 486 return -ENOMEM; 487 } 488 489 soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); 490 soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL); 491 492 if (chipid) { 493 product = readl(chipid + id->offset); 494 iounmap(chipid); 495 496 if (id == &id_prr) { 497 /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ 498 if ((product & 0x7fff) == 0x5210) 499 product ^= 0x11; 500 /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ 501 if ((product & 0x7fff) == 0x5211) 502 product ^= 0x12; 503 504 eshi = ((product >> 4) & 0x0f) + 1; 505 eslo = product & 0xf; 506 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", 507 eshi, eslo); 508 } else if (id == &id_rzg2l) { 509 eshi = ((product >> 28) & 0x0f); 510 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u", 511 eshi); 512 rev_prefix = "Rev "; 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", 517 eshi, eslo); 518 } 519 520 if (soc->id && 521 ((product & id->mask) >> __ffs(id->mask)) != soc->id) { 522 pr_warn("SoC mismatch (product = 0x%x)\n", product); 523 ret = -ENODEV; 524 goto free_soc_dev_attr; 525 } 526 } 527 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 ?: ""); 530 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; 535 } 536 537 return 0; 538 539 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); 543 kfree(soc_dev_attr); 544 return ret; 545 } 546 early_initcall(renesas_soc_init); 547