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