Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Renesas SoC Identification
0004  *
0005  * Copyright (C) 2014-2016 Glider bvba
0006  */
0007 
0008 #include <linux/io.h>
0009 #include <linux/of.h>
0010 #include <linux/of_address.h>
0011 #include <linux/slab.h>
0012 #include <linux/string.h>
0013 #include <linux/sys_soc.h>
0014 
0015 
0016 struct renesas_family {
0017     const char name[16];
0018     u32 reg;            /* CCCR or PRR, if not in DT */
0019 };
0020 
0021 static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = {
0022     .name   = "R-Car Gen1",
0023     .reg    = 0xff000044,       /* PRR (Product Register) */
0024 };
0025 
0026 static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = {
0027     .name   = "R-Car Gen2",
0028     .reg    = 0xff000044,       /* PRR (Product Register) */
0029 };
0030 
0031 static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = {
0032     .name   = "R-Car Gen3",
0033     .reg    = 0xfff00044,       /* PRR (Product Register) */
0034 };
0035 
0036 static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = {
0037     .name   = "R-Car Gen4",
0038 };
0039 
0040 static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
0041     .name   = "R-Mobile",
0042     .reg    = 0xe600101c,       /* CCCR (Common Chip Code Register) */
0043 };
0044 
0045 static const struct renesas_family fam_rza1 __initconst __maybe_unused = {
0046     .name   = "RZ/A1",
0047 };
0048 
0049 static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
0050     .name   = "RZ/A2",
0051 };
0052 
0053 static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
0054     .name   = "RZ/G1",
0055     .reg    = 0xff000044,       /* PRR (Product Register) */
0056 };
0057 
0058 static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
0059     .name   = "RZ/G2",
0060     .reg    = 0xfff00044,       /* PRR (Product Register) */
0061 };
0062 
0063 static const struct renesas_family fam_rzg2l __initconst __maybe_unused = {
0064     .name   = "RZ/G2L",
0065 };
0066 
0067 static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = {
0068     .name   = "RZ/G2UL",
0069 };
0070 
0071 static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
0072     .name   = "RZ/V2L",
0073 };
0074 
0075 static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
0076     .name   = "SH-Mobile",
0077     .reg    = 0xe600101c,       /* CCCR (Common Chip Code Register) */
0078 };
0079 
0080 
0081 struct renesas_soc {
0082     const struct renesas_family *family;
0083     u32 id;
0084 };
0085 
0086 static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
0087     .family = &fam_rza1,
0088 };
0089 
0090 static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = {
0091     .family = &fam_rza2,
0092     .id = 0x3b,
0093 };
0094 
0095 static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = {
0096     .family = &fam_rmobile,
0097     .id = 0x3f,
0098 };
0099 
0100 static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
0101     .family = &fam_rmobile,
0102     .id = 0x40,
0103 };
0104 
0105 static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
0106     .family = &fam_rzg1,
0107     .id = 0x45,
0108 };
0109 
0110 static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
0111     .family = &fam_rzg1,
0112     .id = 0x47,
0113 };
0114 
0115 static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = {
0116     .family = &fam_rzg1,
0117     .id = 0x4b,
0118 };
0119 
0120 static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
0121     .family = &fam_rzg1,
0122     .id = 0x4c,
0123 };
0124 
0125 static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = {
0126     .family = &fam_rzg1,
0127     .id = 0x53,
0128 };
0129 
0130 static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
0131     .family = &fam_rzg2,
0132     .id = 0x52,
0133 };
0134 
0135 static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = {
0136     .family = &fam_rzg2,
0137     .id     = 0x55,
0138 };
0139 
0140 static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
0141     .family = &fam_rzg2,
0142     .id = 0x57,
0143 };
0144 
0145 static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = {
0146     .family = &fam_rzg2,
0147     .id = 0x4f,
0148 };
0149 
0150 static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = {
0151     .family = &fam_rzg2l,
0152     .id     = 0x841c447,
0153 };
0154 
0155 static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused = {
0156     .family = &fam_rzg2ul,
0157     .id     = 0x8450447,
0158 };
0159 
0160 static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
0161     .family = &fam_rzv2l,
0162     .id     = 0x8447447,
0163 };
0164 
0165 static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
0166     .family = &fam_rcar_gen1,
0167 };
0168 
0169 static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = {
0170     .family = &fam_rcar_gen1,
0171     .id = 0x3b,
0172 };
0173 
0174 static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = {
0175     .family = &fam_rcar_gen2,
0176     .id = 0x45,
0177 };
0178 
0179 static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = {
0180     .family = &fam_rcar_gen2,
0181     .id = 0x47,
0182 };
0183 
0184 static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = {
0185     .family = &fam_rcar_gen2,
0186     .id = 0x4a,
0187 };
0188 
0189 static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = {
0190     .family = &fam_rcar_gen2,
0191     .id = 0x4b,
0192 };
0193 
0194 static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = {
0195     .family = &fam_rcar_gen2,
0196     .id = 0x4c,
0197 };
0198 
0199 static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = {
0200     .family = &fam_rcar_gen3,
0201     .id = 0x4f,
0202 };
0203 
0204 static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = {
0205     .family = &fam_rcar_gen3,
0206     .id = 0x52,
0207 };
0208 
0209 static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = {
0210     .family = &fam_rcar_gen3,
0211     .id     = 0x55,
0212 };
0213 
0214 static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = {
0215     .family = &fam_rcar_gen3,
0216     .id = 0x54,
0217 };
0218 
0219 static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = {
0220     .family = &fam_rcar_gen3,
0221     .id = 0x56,
0222 };
0223 
0224 static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = {
0225     .family = &fam_rcar_gen3,
0226     .id = 0x57,
0227 };
0228 
0229 static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
0230     .family = &fam_rcar_gen3,
0231     .id = 0x58,
0232 };
0233 
0234 static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
0235     .family = &fam_rcar_gen4,
0236     .id = 0x59,
0237 };
0238 
0239 static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = {
0240     .family = &fam_rcar_gen4,
0241     .id = 0x5a,
0242 };
0243 
0244 static const struct renesas_soc soc_rcar_v4h __initconst __maybe_unused = {
0245     .family = &fam_rcar_gen4,
0246     .id = 0x5c,
0247 };
0248 
0249 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
0250     .family = &fam_shmobile,
0251     .id = 0x37,
0252 };
0253 
0254 
0255 static const struct of_device_id renesas_socs[] __initconst = {
0256 #ifdef CONFIG_ARCH_R7S72100
0257     { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
0258 #endif
0259 #ifdef CONFIG_ARCH_R7S9210
0260     { .compatible = "renesas,r7s9210",  .data = &soc_rz_a2m },
0261 #endif
0262 #ifdef CONFIG_ARCH_R8A73A4
0263     { .compatible = "renesas,r8a73a4",  .data = &soc_rmobile_ape6 },
0264 #endif
0265 #ifdef CONFIG_ARCH_R8A7740
0266     { .compatible = "renesas,r8a7740",  .data = &soc_rmobile_a1 },
0267 #endif
0268 #ifdef CONFIG_ARCH_R8A7742
0269     { .compatible = "renesas,r8a7742",  .data = &soc_rz_g1h },
0270 #endif
0271 #ifdef CONFIG_ARCH_R8A7743
0272     { .compatible = "renesas,r8a7743",  .data = &soc_rz_g1m },
0273 #endif
0274 #ifdef CONFIG_ARCH_R8A7744
0275     { .compatible = "renesas,r8a7744",  .data = &soc_rz_g1n },
0276 #endif
0277 #ifdef CONFIG_ARCH_R8A7745
0278     { .compatible = "renesas,r8a7745",  .data = &soc_rz_g1e },
0279 #endif
0280 #ifdef CONFIG_ARCH_R8A77470
0281     { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c },
0282 #endif
0283 #ifdef CONFIG_ARCH_R8A774A1
0284     { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m },
0285 #endif
0286 #ifdef CONFIG_ARCH_R8A774B1
0287     { .compatible = "renesas,r8a774b1", .data = &soc_rz_g2n },
0288 #endif
0289 #ifdef CONFIG_ARCH_R8A774C0
0290     { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e },
0291 #endif
0292 #ifdef CONFIG_ARCH_R8A774E1
0293     { .compatible = "renesas,r8a774e1", .data = &soc_rz_g2h },
0294 #endif
0295 #ifdef CONFIG_ARCH_R8A7778
0296     { .compatible = "renesas,r8a7778",  .data = &soc_rcar_m1a },
0297 #endif
0298 #ifdef CONFIG_ARCH_R8A7779
0299     { .compatible = "renesas,r8a7779",  .data = &soc_rcar_h1 },
0300 #endif
0301 #ifdef CONFIG_ARCH_R8A7790
0302     { .compatible = "renesas,r8a7790",  .data = &soc_rcar_h2 },
0303 #endif
0304 #ifdef CONFIG_ARCH_R8A7791
0305     { .compatible = "renesas,r8a7791",  .data = &soc_rcar_m2_w },
0306 #endif
0307 #ifdef CONFIG_ARCH_R8A7792
0308     { .compatible = "renesas,r8a7792",  .data = &soc_rcar_v2h },
0309 #endif
0310 #ifdef CONFIG_ARCH_R8A7793
0311     { .compatible = "renesas,r8a7793",  .data = &soc_rcar_m2_n },
0312 #endif
0313 #ifdef CONFIG_ARCH_R8A7794
0314     { .compatible = "renesas,r8a7794",  .data = &soc_rcar_e2 },
0315 #endif
0316 #if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951)
0317     { .compatible = "renesas,r8a7795",  .data = &soc_rcar_h3 },
0318 #endif
0319 #ifdef CONFIG_ARCH_R8A77951
0320     { .compatible = "renesas,r8a779m0", .data = &soc_rcar_h3 },
0321     { .compatible = "renesas,r8a779m1", .data = &soc_rcar_h3 },
0322     { .compatible = "renesas,r8a779m8", .data = &soc_rcar_h3 },
0323 #endif
0324 #ifdef CONFIG_ARCH_R8A77960
0325     { .compatible = "renesas,r8a7796",  .data = &soc_rcar_m3_w },
0326 #endif
0327 #ifdef CONFIG_ARCH_R8A77961
0328     { .compatible = "renesas,r8a77961", .data = &soc_rcar_m3_w },
0329     { .compatible = "renesas,r8a779m2", .data = &soc_rcar_m3_w },
0330     { .compatible = "renesas,r8a779m3", .data = &soc_rcar_m3_w },
0331 #endif
0332 #ifdef CONFIG_ARCH_R8A77965
0333     { .compatible = "renesas,r8a77965", .data = &soc_rcar_m3_n },
0334     { .compatible = "renesas,r8a779m4", .data = &soc_rcar_m3_n },
0335     { .compatible = "renesas,r8a779m5", .data = &soc_rcar_m3_n },
0336 #endif
0337 #ifdef CONFIG_ARCH_R8A77970
0338     { .compatible = "renesas,r8a77970", .data = &soc_rcar_v3m },
0339 #endif
0340 #ifdef CONFIG_ARCH_R8A77980
0341     { .compatible = "renesas,r8a77980", .data = &soc_rcar_v3h },
0342 #endif
0343 #ifdef CONFIG_ARCH_R8A77990
0344     { .compatible = "renesas,r8a77990", .data = &soc_rcar_e3 },
0345     { .compatible = "renesas,r8a779m6", .data = &soc_rcar_e3 },
0346 #endif
0347 #ifdef CONFIG_ARCH_R8A77995
0348     { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 },
0349     { .compatible = "renesas,r8a779m7", .data = &soc_rcar_d3 },
0350 #endif
0351 #ifdef CONFIG_ARCH_R8A779A0
0352     { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u },
0353 #endif
0354 #ifdef CONFIG_ARCH_R8A779F0
0355     { .compatible = "renesas,r8a779f0", .data = &soc_rcar_s4 },
0356 #endif
0357 #ifdef CONFIG_ARCH_R8A779G0
0358     { .compatible = "renesas,r8a779g0", .data = &soc_rcar_v4h },
0359 #endif
0360 #if defined(CONFIG_ARCH_R9A07G043)
0361     { .compatible = "renesas,r9a07g043",    .data = &soc_rz_g2ul },
0362 #endif
0363 #if defined(CONFIG_ARCH_R9A07G044)
0364     { .compatible = "renesas,r9a07g044",    .data = &soc_rz_g2l },
0365 #endif
0366 #if defined(CONFIG_ARCH_R9A07G054)
0367     { .compatible = "renesas,r9a07g054",    .data = &soc_rz_v2l },
0368 #endif
0369 #ifdef CONFIG_ARCH_SH73A0
0370     { .compatible = "renesas,sh73a0",   .data = &soc_shmobile_ag5 },
0371 #endif
0372     { /* sentinel */ }
0373 };
0374 
0375 struct renesas_id {
0376     unsigned int offset;
0377     u32 mask;
0378 };
0379 
0380 static const struct renesas_id id_bsid __initconst = {
0381     .offset = 0,
0382     .mask = 0xff0000,
0383     /*
0384      * TODO: Upper 4 bits of BSID are for chip version, but the format is
0385      * not known at this time so we don't know how to specify eshi and eslo
0386      */
0387 };
0388 
0389 static const struct renesas_id id_rzg2l __initconst = {
0390     .offset = 0xa04,
0391     .mask = 0xfffffff,
0392 };
0393 
0394 static const struct renesas_id id_prr __initconst = {
0395     .offset = 0,
0396     .mask = 0xff00,
0397 };
0398 
0399 static const struct of_device_id renesas_ids[] __initconst = {
0400     { .compatible = "renesas,bsid",         .data = &id_bsid },
0401     { .compatible = "renesas,r9a07g043-sysc",   .data = &id_rzg2l },
0402     { .compatible = "renesas,r9a07g044-sysc",   .data = &id_rzg2l },
0403     { .compatible = "renesas,r9a07g054-sysc",   .data = &id_rzg2l },
0404     { .compatible = "renesas,prr",          .data = &id_prr },
0405     { /* sentinel */ }
0406 };
0407 
0408 static int __init renesas_soc_init(void)
0409 {
0410     struct soc_device_attribute *soc_dev_attr;
0411     unsigned int product, eshi = 0, eslo;
0412     const struct renesas_family *family;
0413     const struct of_device_id *match;
0414     const struct renesas_soc *soc;
0415     const struct renesas_id *id;
0416     void __iomem *chipid = NULL;
0417     const char *rev_prefix = "";
0418     struct soc_device *soc_dev;
0419     struct device_node *np;
0420     const char *soc_id;
0421     int ret;
0422 
0423     match = of_match_node(renesas_socs, of_root);
0424     if (!match)
0425         return -ENODEV;
0426 
0427     soc_id = strchr(match->compatible, ',') + 1;
0428     soc = match->data;
0429     family = soc->family;
0430 
0431     np = of_find_matching_node_and_match(NULL, renesas_ids, &match);
0432     if (np) {
0433         id = match->data;
0434         chipid = of_iomap(np, 0);
0435         of_node_put(np);
0436     } else if (soc->id && family->reg) {
0437         /* Try hardcoded CCCR/PRR fallback */
0438         id = &id_prr;
0439         chipid = ioremap(family->reg, 4);
0440     }
0441 
0442     soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
0443     if (!soc_dev_attr)
0444         return -ENOMEM;
0445 
0446     np = of_find_node_by_path("/");
0447     of_property_read_string(np, "model", &soc_dev_attr->machine);
0448     of_node_put(np);
0449 
0450     soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
0451     soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
0452 
0453     if (chipid) {
0454         product = readl(chipid + id->offset);
0455         iounmap(chipid);
0456 
0457         if (id == &id_prr) {
0458             /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
0459             if ((product & 0x7fff) == 0x5210)
0460                 product ^= 0x11;
0461             /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
0462             if ((product & 0x7fff) == 0x5211)
0463                 product ^= 0x12;
0464 
0465             eshi = ((product >> 4) & 0x0f) + 1;
0466             eslo = product & 0xf;
0467             soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
0468                                eshi, eslo);
0469         }  else if (id == &id_rzg2l) {
0470             eshi =  ((product >> 28) & 0x0f);
0471             soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
0472                                eshi);
0473             rev_prefix = "Rev ";
0474         }
0475 
0476         if (soc->id &&
0477             ((product & id->mask) >> __ffs(id->mask)) != soc->id) {
0478             pr_warn("SoC mismatch (product = 0x%x)\n", product);
0479             ret = -ENODEV;
0480             goto free_soc_dev_attr;
0481         }
0482     }
0483 
0484     pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr->family,
0485         soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: "");
0486 
0487     soc_dev = soc_device_register(soc_dev_attr);
0488     if (IS_ERR(soc_dev)) {
0489         ret = PTR_ERR(soc_dev);
0490         goto free_soc_dev_attr;
0491     }
0492 
0493     return 0;
0494 
0495 free_soc_dev_attr:
0496     kfree(soc_dev_attr->revision);
0497     kfree_const(soc_dev_attr->soc_id);
0498     kfree_const(soc_dev_attr->family);
0499     kfree(soc_dev_attr);
0500     return ret;
0501 }
0502 early_initcall(renesas_soc_init);