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