0001
0002
0003
0004
0005
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
0029 static const struct fsl_soc_die_attr fsl_soc_die[] = {
0030
0031
0032
0033
0034
0035 { .die = "T4240",
0036 .svr = 0x82400000,
0037 .mask = 0xfff00000,
0038 },
0039
0040 { .die = "T1040",
0041 .svr = 0x85200000,
0042 .mask = 0xfff00000,
0043 },
0044
0045 { .die = "T2080",
0046 .svr = 0x85300000,
0047 .mask = 0xfff00000,
0048 },
0049
0050 { .die = "T1024",
0051 .svr = 0x85400000,
0052 .mask = 0xfff00000,
0053 },
0054
0055
0056
0057
0058
0059
0060 { .die = "LS1043A",
0061 .svr = 0x87920000,
0062 .mask = 0xffff0000,
0063 },
0064
0065 { .die = "LS2080A",
0066 .svr = 0x87010000,
0067 .mask = 0xff3f0000,
0068 },
0069
0070 { .die = "LS1088A",
0071 .svr = 0x87030000,
0072 .mask = 0xff3f0000,
0073 },
0074
0075 { .die = "LS1012A",
0076 .svr = 0x87040000,
0077 .mask = 0xffff0000,
0078 },
0079
0080 { .die = "LS1046A",
0081 .svr = 0x87070000,
0082 .mask = 0xffff0000,
0083 },
0084
0085 { .die = "LS2088A",
0086 .svr = 0x87090000,
0087 .mask = 0xff3f0000,
0088 },
0089
0090 { .die = "LS1021A",
0091 .svr = 0x87000000,
0092 .mask = 0xfff70000,
0093 },
0094
0095 { .die = "LX2160A",
0096 .svr = 0x87360000,
0097 .mask = 0xff3f0000,
0098 },
0099
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
0151
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(®s->svr);
0210 else
0211 svr = ioread32be(®s->svr);
0212 iounmap(regs);
0213 of_node_put(np);
0214
0215
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);