FILE
renesas-soc.c
File preview with syntax highlighting.
linux-6.19.14/drivers/soc/renesas/renesas-soc.c
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/bitfield.h> 9#include <linux/io.h> 10#include <linux/of.h> 11#include <linux/of_address.h> 12#include <linux/slab.h> 13#include <linux/string.h> 14#include <linux/sys_soc.h> 15 16struct renesas_family { 17 const char name[16]; 18 u32 reg; /* CCCR or PRR, if not in DT */ 19}; 20 21static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = { 22 .name = "R-Car Gen1", 23 .reg = 0xff000044, /* PRR (Product Register) */ 24}; 25 26static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = { 27 .name = "R-Car Gen2", 28 .reg = 0xff000044, /* PRR (Product Register) */ 29}; 30 31static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = { 32 .name = "R-Car Gen3", 33 .reg = 0xfff00044, /* PRR (Product Register) */ 34}; 35 36static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = { 37 .name = "R-Car Gen4", 38}; 39 40static const struct renesas_family fam_rcar_gen5 __initconst __maybe_unused = { 41 .name = "R-Car Gen5", 42}; 43 44static const struct renesas_family fam_rmobile __initconst __maybe_unused = { 45 .name = "R-Mobile", 46 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ 47}; 48 49static const struct renesas_family fam_rza1 __initconst __maybe_unused = { 50 .name = "RZ/A1", 51}; 52 53static const struct renesas_family fam_rza2 __initconst __maybe_unused = { 54 .name = "RZ/A2", 55}; 56 57static const struct renesas_family fam_rzfive __initconst __maybe_unused = { 58 .name = "RZ/Five", 59}; 60 61static const struct renesas_family fam_rzg1 __initconst __maybe_unused = { 62 .name = "RZ/G1", 63 .reg = 0xff000044, /* PRR (Product Register) */ 64}; 65 66static const struct renesas_family fam_rzg2 __initconst __maybe_unused = { 67 .name = "RZ/G2", 68 .reg = 0xfff00044, /* PRR (Product Register) */ 69}; 70 71static const struct renesas_family fam_rzg2l __initconst __maybe_unused = { 72 .name = "RZ/G2L", 73}; 74 75static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = { 76 .name = "RZ/G2UL", 77}; 78 79static const struct renesas_family fam_rzv2l __initconst __maybe_unused = { 80 .name = "RZ/V2L", 81}; 82 83static const struct renesas_family fam_rzv2m __initconst __maybe_unused = { 84 .name = "RZ/V2M", 85}; 86 87static const struct renesas_family fam_shmobile __initconst __maybe_unused = { 88 .name = "SH-Mobile", 89 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ 90}; 91 92struct renesas_soc { 93 const struct renesas_family *family; 94 u32 id; 95}; 96 97static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { 98 .family = &fam_rza1, 99}; 100 101static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = { 102 .family = &fam_rza2, 103 .id = 0x3b, 104}; 105 106static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = { 107 .family = &fam_rmobile, 108 .id = 0x3f, 109}; 110 111static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = { 112 .family = &fam_rmobile, 113 .id = 0x40, 114}; 115 116static const struct renesas_soc soc_rz_five __initconst __maybe_unused = { 117 .family = &fam_rzfive, 118 .id = 0x847c447, 119}; 120 121static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = { 122 .family = &fam_rzg1, 123 .id = 0x45, 124}; 125 126static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { 127 .family = &fam_rzg1, 128 .id = 0x47, 129}; 130 131static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = { 132 .family = &fam_rzg1, 133 .id = 0x4b, 134}; 135 136static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { 137 .family = &fam_rzg1, 138 .id = 0x4c, 139}; 140 141static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = { 142 .family = &fam_rzg1, 143 .id = 0x53, 144}; 145 146static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = { 147 .family = &fam_rzg2, 148 .id = 0x52, 149}; 150 151static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = { 152 .family = &fam_rzg2, 153 .id = 0x55, 154}; 155 156static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = { 157 .family = &fam_rzg2, 158 .id = 0x57, 159}; 160 161static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = { 162 .family = &fam_rzg2, 163 .id = 0x4f, 164}; 165 166static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = { 167 .family = &fam_rzg2l, 168 .id = 0x841c447, 169}; 170 171static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused = { 172 .family = &fam_rzg2ul, 173 .id = 0x8450447, 174}; 175 176static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = { 177 .family = &fam_rzv2l, 178 .id = 0x8447447, 179}; 180 181static const struct renesas_soc soc_rz_v2m __initconst __maybe_unused = { 182 .family = &fam_rzv2m, 183}; 184 185static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { 186 .family = &fam_rcar_gen1, 187}; 188 189static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = { 190 .family = &fam_rcar_gen1, 191 .id = 0x3b, 192}; 193 194static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = { 195 .family = &fam_rcar_gen2, 196 .id = 0x45, 197}; 198 199static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = { 200 .family = &fam_rcar_gen2, 201 .id = 0x47, 202}; 203 204static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = { 205 .family = &fam_rcar_gen2, 206 .id = 0x4a, 207}; 208 209static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = { 210 .family = &fam_rcar_gen2, 211 .id = 0x4b, 212}; 213 214static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = { 215 .family = &fam_rcar_gen2, 216 .id = 0x4c, 217}; 218 219static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = { 220 .family = &fam_rcar_gen3, 221 .id = 0x4f, 222}; 223 224static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = { 225 .family = &fam_rcar_gen3, 226 .id = 0x52, 227}; 228 229static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = { 230 .family = &fam_rcar_gen3, 231 .id = 0x55, 232}; 233 234static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = { 235 .family = &fam_rcar_gen3, 236 .id = 0x54, 237}; 238 239static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = { 240 .family = &fam_rcar_gen3, 241 .id = 0x56, 242}; 243 244static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = { 245 .family = &fam_rcar_gen3, 246 .id = 0x57, 247}; 248 249static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = { 250 .family = &fam_rcar_gen3, 251 .id = 0x58, 252}; 253 254static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = { 255 .family = &fam_rcar_gen4, 256 .id = 0x59, 257}; 258 259static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = { 260 .family = &fam_rcar_gen4, 261 .id = 0x5a, 262}; 263 264static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = { 265 .family = &fam_rcar_gen4, 266 .id = 0x5c, 267}; 268 269static const struct renesas_soc soc_rcar_v4m __initconst __maybe_unused = { 270 .family = &fam_rcar_gen4, 271 .id = 0x5d, 272}; 273 274static const struct renesas_soc soc_rcar_x5h __initconst __maybe_unused = { 275 .family = &fam_rcar_gen5, 276 .id = 0x60, 277}; 278 279static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { 280 .family = &fam_shmobile, 281 .id = 0x37, 282}; 283 284static 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_R8A78000 392 { .compatible = "renesas,r8a78000", .data = &soc_rcar_x5h }, 393#endif 394#ifdef CONFIG_ARCH_R9A07G043 395#ifdef CONFIG_RISCV 396 { .compatible = "renesas,r9a07g043", .data = &soc_rz_five }, 397#else 398 { .compatible = "renesas,r9a07g043", .data = &soc_rz_g2ul }, 399#endif 400#endif 401#ifdef CONFIG_ARCH_R9A07G044 402 { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, 403#endif 404#ifdef CONFIG_ARCH_R9A07G054 405 { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l }, 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 416struct renesas_id { 417 unsigned int offset; 418 u32 mask; 419}; 420 421static 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 430static const struct renesas_id id_rzg2l __initconst = { 431 .offset = 0xa04, 432 .mask = 0xfffffff, 433}; 434 435static const struct renesas_id id_rzv2m __initconst = { 436 .offset = 0x104, 437 .mask = 0xff, 438}; 439 440static const struct renesas_id id_prr __initconst = { 441 .offset = 0, 442 .mask = 0xff00, 443}; 444 445static 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 456static 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 && field_get(id->mask, product) != 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 546free_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} 553early_initcall(renesas_soc_init);
~/
Read-only file preview.