Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Freescale QorIQ Platforms GUTS Driver
0004  *
0005  * Copyright (C) 2016 Freescale Semiconductor, Inc.
0006  */
0007 
0008 #include <linux/io.h>
0009 #include <linux/slab.h>
0010 #include <linux/module.h>
0011 #include <linux/of_fdt.h>
0012 #include <linux/sys_soc.h>
0013 #include <linux/of_address.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/fsl/guts.h>
0016 
0017 struct fsl_soc_die_attr {
0018     char    *die;
0019     u32 svr;
0020     u32 mask;
0021 };
0022 
0023 struct fsl_soc_data {
0024     const char *sfp_compat;
0025     u32 uid_offset;
0026 };
0027 
0028 /* SoC die attribute definition for QorIQ platform */
0029 static const struct fsl_soc_die_attr fsl_soc_die[] = {
0030     /*
0031      * Power Architecture-based SoCs T Series
0032      */
0033 
0034     /* Die: T4240, SoC: T4240/T4160/T4080 */
0035     { .die      = "T4240",
0036       .svr      = 0x82400000,
0037       .mask     = 0xfff00000,
0038     },
0039     /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */
0040     { .die      = "T1040",
0041       .svr      = 0x85200000,
0042       .mask     = 0xfff00000,
0043     },
0044     /* Die: T2080, SoC: T2080/T2081 */
0045     { .die      = "T2080",
0046       .svr      = 0x85300000,
0047       .mask     = 0xfff00000,
0048     },
0049     /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */
0050     { .die      = "T1024",
0051       .svr      = 0x85400000,
0052       .mask     = 0xfff00000,
0053     },
0054 
0055     /*
0056      * ARM-based SoCs LS Series
0057      */
0058 
0059     /* Die: LS1043A, SoC: LS1043A/LS1023A */
0060     { .die      = "LS1043A",
0061       .svr      = 0x87920000,
0062       .mask     = 0xffff0000,
0063     },
0064     /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */
0065     { .die      = "LS2080A",
0066       .svr      = 0x87010000,
0067       .mask     = 0xff3f0000,
0068     },
0069     /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */
0070     { .die      = "LS1088A",
0071       .svr      = 0x87030000,
0072       .mask     = 0xff3f0000,
0073     },
0074     /* Die: LS1012A, SoC: LS1012A */
0075     { .die      = "LS1012A",
0076       .svr      = 0x87040000,
0077       .mask     = 0xffff0000,
0078     },
0079     /* Die: LS1046A, SoC: LS1046A/LS1026A */
0080     { .die      = "LS1046A",
0081       .svr      = 0x87070000,
0082       .mask     = 0xffff0000,
0083     },
0084     /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */
0085     { .die      = "LS2088A",
0086       .svr      = 0x87090000,
0087       .mask     = 0xff3f0000,
0088     },
0089     /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */
0090     { .die      = "LS1021A",
0091       .svr      = 0x87000000,
0092       .mask     = 0xfff70000,
0093     },
0094     /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */
0095     { .die          = "LX2160A",
0096       .svr          = 0x87360000,
0097       .mask         = 0xff3f0000,
0098     },
0099     /* Die: LS1028A, SoC: LS1028A */
0100     { .die          = "LS1028A",
0101       .svr          = 0x870b0000,
0102       .mask         = 0xff3f0000,
0103     },
0104     { },
0105 };
0106 
0107 static const struct fsl_soc_die_attr *fsl_soc_die_match(
0108     u32 svr, const struct fsl_soc_die_attr *matches)
0109 {
0110     while (matches->svr) {
0111         if (matches->svr == (svr & matches->mask))
0112             return matches;
0113         matches++;
0114     }
0115     return NULL;
0116 }
0117 
0118 static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
0119 {
0120     struct device_node *np;
0121     void __iomem *sfp_base;
0122     u64 uid;
0123 
0124     np = of_find_compatible_node(NULL, NULL, compat);
0125     if (!np)
0126         return 0;
0127 
0128     sfp_base = of_iomap(np, 0);
0129     if (!sfp_base) {
0130         of_node_put(np);
0131         return 0;
0132     }
0133 
0134     uid = ioread32(sfp_base + offset);
0135     uid <<= 32;
0136     uid |= ioread32(sfp_base + offset + 4);
0137 
0138     iounmap(sfp_base);
0139     of_node_put(np);
0140 
0141     return uid;
0142 }
0143 
0144 static const struct fsl_soc_data ls1028a_data = {
0145     .sfp_compat = "fsl,ls1028a-sfp",
0146     .uid_offset = 0x21c,
0147 };
0148 
0149 /*
0150  * Table for matching compatible strings, for device tree
0151  * guts node, for Freescale QorIQ SOCs.
0152  */
0153 static const struct of_device_id fsl_guts_of_match[] = {
0154     { .compatible = "fsl,qoriq-device-config-1.0", },
0155     { .compatible = "fsl,qoriq-device-config-2.0", },
0156     { .compatible = "fsl,p1010-guts", },
0157     { .compatible = "fsl,p1020-guts", },
0158     { .compatible = "fsl,p1021-guts", },
0159     { .compatible = "fsl,p1022-guts", },
0160     { .compatible = "fsl,p1023-guts", },
0161     { .compatible = "fsl,p2020-guts", },
0162     { .compatible = "fsl,bsc9131-guts", },
0163     { .compatible = "fsl,bsc9132-guts", },
0164     { .compatible = "fsl,mpc8536-guts", },
0165     { .compatible = "fsl,mpc8544-guts", },
0166     { .compatible = "fsl,mpc8548-guts", },
0167     { .compatible = "fsl,mpc8568-guts", },
0168     { .compatible = "fsl,mpc8569-guts", },
0169     { .compatible = "fsl,mpc8572-guts", },
0170     { .compatible = "fsl,ls1021a-dcfg", },
0171     { .compatible = "fsl,ls1043a-dcfg", },
0172     { .compatible = "fsl,ls2080a-dcfg", },
0173     { .compatible = "fsl,ls1088a-dcfg", },
0174     { .compatible = "fsl,ls1012a-dcfg", },
0175     { .compatible = "fsl,ls1046a-dcfg", },
0176     { .compatible = "fsl,lx2160a-dcfg", },
0177     { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
0178     {}
0179 };
0180 
0181 static int __init fsl_guts_init(void)
0182 {
0183     struct soc_device_attribute *soc_dev_attr;
0184     static struct soc_device *soc_dev;
0185     const struct fsl_soc_die_attr *soc_die;
0186     const struct fsl_soc_data *soc_data;
0187     const struct of_device_id *match;
0188     struct ccsr_guts __iomem *regs;
0189     const char *machine = NULL;
0190     struct device_node *np;
0191     bool little_endian;
0192     u64 soc_uid = 0;
0193     u32 svr;
0194     int ret;
0195 
0196     np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
0197     if (!np)
0198         return 0;
0199     soc_data = match->data;
0200 
0201     regs = of_iomap(np, 0);
0202     if (!regs) {
0203         of_node_put(np);
0204         return -ENOMEM;
0205     }
0206 
0207     little_endian = of_property_read_bool(np, "little-endian");
0208     if (little_endian)
0209         svr = ioread32(&regs->svr);
0210     else
0211         svr = ioread32be(&regs->svr);
0212     iounmap(regs);
0213     of_node_put(np);
0214 
0215     /* Register soc device */
0216     soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
0217     if (!soc_dev_attr)
0218         return -ENOMEM;
0219 
0220     if (of_property_read_string(of_root, "model", &machine))
0221         of_property_read_string_index(of_root, "compatible", 0, &machine);
0222     if (machine) {
0223         soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL);
0224         if (!soc_dev_attr->machine)
0225             goto err_nomem;
0226     }
0227 
0228     soc_die = fsl_soc_die_match(svr, fsl_soc_die);
0229     if (soc_die) {
0230         soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
0231                          soc_die->die);
0232     } else {
0233         soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
0234     }
0235     if (!soc_dev_attr->family)
0236         goto err_nomem;
0237 
0238     soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
0239     if (!soc_dev_attr->soc_id)
0240         goto err_nomem;
0241 
0242     soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
0243                        (svr >>  4) & 0xf, svr & 0xf);
0244     if (!soc_dev_attr->revision)
0245         goto err_nomem;
0246 
0247     if (soc_data)
0248         soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
0249                            soc_data->uid_offset);
0250     if (soc_uid)
0251         soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
0252                             soc_uid);
0253 
0254     soc_dev = soc_device_register(soc_dev_attr);
0255     if (IS_ERR(soc_dev)) {
0256         ret = PTR_ERR(soc_dev);
0257         goto err;
0258     }
0259 
0260     pr_info("Machine: %s\n", soc_dev_attr->machine);
0261     pr_info("SoC family: %s\n", soc_dev_attr->family);
0262     pr_info("SoC ID: %s, Revision: %s\n",
0263         soc_dev_attr->soc_id, soc_dev_attr->revision);
0264 
0265     return 0;
0266 
0267 err_nomem:
0268     ret = -ENOMEM;
0269 err:
0270     kfree(soc_dev_attr->machine);
0271     kfree(soc_dev_attr->family);
0272     kfree(soc_dev_attr->soc_id);
0273     kfree(soc_dev_attr->revision);
0274     kfree(soc_dev_attr->serial_number);
0275     kfree(soc_dev_attr);
0276 
0277     return ret;
0278 }
0279 core_initcall(fsl_guts_init);