1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Freescale QorIQ Platforms GUTS Driver 4 * 5 * Copyright (C) 2016 Freescale Semiconductor, Inc. 6 */ 7 8 #include <linux/io.h> 9 #include <linux/slab.h> 10 #include <linux/module.h> 11 #include <linux/of_fdt.h> 12 #include <linux/sys_soc.h> 13 #include <linux/of_address.h> 14 #include <linux/platform_device.h> 15 #include <linux/fsl/guts.h> 16 17 struct fsl_soc_die_attr { 18 char *die; 19 u32 svr; 20 u32 mask; 21 }; 22 23 struct fsl_soc_data { 24 const char *sfp_compat; 25 u32 uid_offset; 26 }; 27 28 /* SoC die attribute definition for QorIQ platform */ 29 static const struct fsl_soc_die_attr fsl_soc_die[] = { 30 /* 31 * Power Architecture-based SoCs T Series 32 */ 33 34 /* Die: T4240, SoC: T4240/T4160/T4080 */ 35 { .die = "T4240", 36 .svr = 0x82400000, 37 .mask = 0xfff00000, 38 }, 39 /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */ 40 { .die = "T1040", 41 .svr = 0x85200000, 42 .mask = 0xfff00000, 43 }, 44 /* Die: T2080, SoC: T2080/T2081 */ 45 { .die = "T2080", 46 .svr = 0x85300000, 47 .mask = 0xfff00000, 48 }, 49 /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */ 50 { .die = "T1024", 51 .svr = 0x85400000, 52 .mask = 0xfff00000, 53 }, 54 55 /* 56 * ARM-based SoCs LS Series 57 */ 58 59 /* Die: LS1043A, SoC: LS1043A/LS1023A */ 60 { .die = "LS1043A", 61 .svr = 0x87920000, 62 .mask = 0xffff0000, 63 }, 64 /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */ 65 { .die = "LS2080A", 66 .svr = 0x87010000, 67 .mask = 0xff3f0000, 68 }, 69 /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */ 70 { .die = "LS1088A", 71 .svr = 0x87030000, 72 .mask = 0xff3f0000, 73 }, 74 /* Die: LS1012A, SoC: LS1012A */ 75 { .die = "LS1012A", 76 .svr = 0x87040000, 77 .mask = 0xffff0000, 78 }, 79 /* Die: LS1046A, SoC: LS1046A/LS1026A */ 80 { .die = "LS1046A", 81 .svr = 0x87070000, 82 .mask = 0xffff0000, 83 }, 84 /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */ 85 { .die = "LS2088A", 86 .svr = 0x87090000, 87 .mask = 0xff3f0000, 88 }, 89 /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */ 90 { .die = "LS1021A", 91 .svr = 0x87000000, 92 .mask = 0xfff70000, 93 }, 94 /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */ 95 { .die = "LX2160A", 96 .svr = 0x87360000, 97 .mask = 0xff3f0000, 98 }, 99 /* Die: LS1028A, SoC: LS1028A */ 100 { .die = "LS1028A", 101 .svr = 0x870b0000, 102 .mask = 0xff3f0000, 103 }, 104 { }, 105 }; 106 107 static const struct fsl_soc_die_attr *fsl_soc_die_match( 108 u32 svr, const struct fsl_soc_die_attr *matches) 109 { 110 while (matches->svr) { 111 if (matches->svr == (svr & matches->mask)) 112 return matches; 113 matches++; 114 } 115 return NULL; 116 } 117 118 static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset) 119 { 120 struct device_node *np; 121 void __iomem *sfp_base; 122 u64 uid; 123 124 np = of_find_compatible_node(NULL, NULL, compat); 125 if (!np) 126 return 0; 127 128 sfp_base = of_iomap(np, 0); 129 130 uid = ioread32(sfp_base + offset); 131 uid <<= 32; 132 uid |= ioread32(sfp_base + offset + 4); 133 134 iounmap(sfp_base); 135 of_node_put(np); 136 137 return uid; 138 } 139 140 static const struct fsl_soc_data ls1028a_data = { 141 .sfp_compat = "fsl,ls1028a-sfp", 142 .uid_offset = 0x21c, 143 }; 144 145 /* 146 * Table for matching compatible strings, for device tree 147 * guts node, for Freescale QorIQ SOCs. 148 */ 149 static const struct of_device_id fsl_guts_of_match[] = { 150 { .compatible = "fsl,qoriq-device-config-1.0", }, 151 { .compatible = "fsl,qoriq-device-config-2.0", }, 152 { .compatible = "fsl,p1010-guts", }, 153 { .compatible = "fsl,p1020-guts", }, 154 { .compatible = "fsl,p1021-guts", }, 155 { .compatible = "fsl,p1022-guts", }, 156 { .compatible = "fsl,p1023-guts", }, 157 { .compatible = "fsl,p2020-guts", }, 158 { .compatible = "fsl,bsc9131-guts", }, 159 { .compatible = "fsl,bsc9132-guts", }, 160 { .compatible = "fsl,mpc8536-guts", }, 161 { .compatible = "fsl,mpc8544-guts", }, 162 { .compatible = "fsl,mpc8548-guts", }, 163 { .compatible = "fsl,mpc8568-guts", }, 164 { .compatible = "fsl,mpc8569-guts", }, 165 { .compatible = "fsl,mpc8572-guts", }, 166 { .compatible = "fsl,ls1021a-dcfg", }, 167 { .compatible = "fsl,ls1043a-dcfg", }, 168 { .compatible = "fsl,ls2080a-dcfg", }, 169 { .compatible = "fsl,ls1088a-dcfg", }, 170 { .compatible = "fsl,ls1012a-dcfg", }, 171 { .compatible = "fsl,ls1046a-dcfg", }, 172 { .compatible = "fsl,lx2160a-dcfg", }, 173 { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data}, 174 {} 175 }; 176 177 static int __init fsl_guts_init(void) 178 { 179 struct soc_device_attribute *soc_dev_attr; 180 static struct soc_device *soc_dev; 181 const struct fsl_soc_die_attr *soc_die; 182 const struct fsl_soc_data *soc_data; 183 const struct of_device_id *match; 184 struct ccsr_guts __iomem *regs; 185 const char *machine = NULL; 186 struct device_node *np; 187 bool little_endian; 188 u64 soc_uid = 0; 189 u32 svr; 190 int ret; 191 192 np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match); 193 if (!np) 194 return 0; 195 soc_data = match->data; 196 197 regs = of_iomap(np, 0); 198 if (!regs) { 199 of_node_put(np); 200 return -ENOMEM; 201 } 202 203 little_endian = of_property_read_bool(np, "little-endian"); 204 if (little_endian) 205 svr = ioread32(®s->svr); 206 else 207 svr = ioread32be(®s->svr); 208 iounmap(regs); 209 of_node_put(np); 210 211 /* Register soc device */ 212 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 213 if (!soc_dev_attr) 214 return -ENOMEM; 215 216 if (of_property_read_string(of_root, "model", &machine)) 217 of_property_read_string_index(of_root, "compatible", 0, &machine); 218 if (machine) { 219 soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL); 220 if (!soc_dev_attr->machine) 221 goto err_nomem; 222 } 223 224 soc_die = fsl_soc_die_match(svr, fsl_soc_die); 225 if (soc_die) { 226 soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s", 227 soc_die->die); 228 } else { 229 soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ"); 230 } 231 if (!soc_dev_attr->family) 232 goto err_nomem; 233 234 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr); 235 if (!soc_dev_attr->soc_id) 236 goto err_nomem; 237 238 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", 239 (svr >> 4) & 0xf, svr & 0xf); 240 if (!soc_dev_attr->revision) 241 goto err_nomem; 242 243 if (soc_data) 244 soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat, 245 soc_data->uid_offset); 246 if (soc_uid) 247 soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", 248 soc_uid); 249 250 soc_dev = soc_device_register(soc_dev_attr); 251 if (IS_ERR(soc_dev)) { 252 ret = PTR_ERR(soc_dev); 253 goto err; 254 } 255 256 pr_info("Machine: %s\n", soc_dev_attr->machine); 257 pr_info("SoC family: %s\n", soc_dev_attr->family); 258 pr_info("SoC ID: %s, Revision: %s\n", 259 soc_dev_attr->soc_id, soc_dev_attr->revision); 260 261 return 0; 262 263 err_nomem: 264 ret = -ENOMEM; 265 err: 266 kfree(soc_dev_attr->machine); 267 kfree(soc_dev_attr->family); 268 kfree(soc_dev_attr->soc_id); 269 kfree(soc_dev_attr->revision); 270 kfree(soc_dev_attr->serial_number); 271 kfree(soc_dev_attr); 272 273 return ret; 274 } 275 core_initcall(fsl_guts_init); 276