0001
0002
0003
0004
0005
0006 #include <linux/mfd/syscon.h>
0007 #include <linux/of.h>
0008 #include <linux/of_address.h>
0009 #include <linux/regmap.h>
0010 #include <linux/slab.h>
0011 #include <linux/sys_soc.h>
0012
0013 #include <soc/imx/cpu.h>
0014 #include <soc/imx/revision.h>
0015
0016 #define IIM_UID 0x820
0017
0018 #define OCOTP_UID_H 0x420
0019 #define OCOTP_UID_L 0x410
0020
0021 #define OCOTP_ULP_UID_1 0x4b0
0022 #define OCOTP_ULP_UID_2 0x4c0
0023 #define OCOTP_ULP_UID_3 0x4d0
0024 #define OCOTP_ULP_UID_4 0x4e0
0025
0026 static int __init imx_soc_device_init(void)
0027 {
0028 struct soc_device_attribute *soc_dev_attr;
0029 const char *ocotp_compat = NULL;
0030 struct soc_device *soc_dev;
0031 struct device_node *root;
0032 struct regmap *ocotp = NULL;
0033 const char *soc_id;
0034 u64 soc_uid = 0;
0035 u32 val;
0036 int ret;
0037 int i;
0038
0039
0040 if (!__mxc_cpu_type)
0041 return 0;
0042
0043 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
0044 if (!soc_dev_attr)
0045 return -ENOMEM;
0046
0047 soc_dev_attr->family = "Freescale i.MX";
0048
0049 root = of_find_node_by_path("/");
0050 ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
0051 of_node_put(root);
0052 if (ret)
0053 goto free_soc;
0054
0055 switch (__mxc_cpu_type) {
0056 case MXC_CPU_MX1:
0057 soc_id = "i.MX1";
0058 break;
0059 case MXC_CPU_MX21:
0060 soc_id = "i.MX21";
0061 break;
0062 case MXC_CPU_MX25:
0063 soc_id = "i.MX25";
0064 break;
0065 case MXC_CPU_MX27:
0066 soc_id = "i.MX27";
0067 break;
0068 case MXC_CPU_MX31:
0069 soc_id = "i.MX31";
0070 break;
0071 case MXC_CPU_MX35:
0072 soc_id = "i.MX35";
0073 break;
0074 case MXC_CPU_MX50:
0075 soc_id = "i.MX50";
0076 break;
0077 case MXC_CPU_MX51:
0078 ocotp_compat = "fsl,imx51-iim";
0079 soc_id = "i.MX51";
0080 break;
0081 case MXC_CPU_MX53:
0082 ocotp_compat = "fsl,imx53-iim";
0083 soc_id = "i.MX53";
0084 break;
0085 case MXC_CPU_IMX6SL:
0086 ocotp_compat = "fsl,imx6sl-ocotp";
0087 soc_id = "i.MX6SL";
0088 break;
0089 case MXC_CPU_IMX6DL:
0090 ocotp_compat = "fsl,imx6q-ocotp";
0091 soc_id = "i.MX6DL";
0092 break;
0093 case MXC_CPU_IMX6SX:
0094 ocotp_compat = "fsl,imx6sx-ocotp";
0095 soc_id = "i.MX6SX";
0096 break;
0097 case MXC_CPU_IMX6Q:
0098 ocotp_compat = "fsl,imx6q-ocotp";
0099 soc_id = "i.MX6Q";
0100 break;
0101 case MXC_CPU_IMX6UL:
0102 ocotp_compat = "fsl,imx6ul-ocotp";
0103 soc_id = "i.MX6UL";
0104 break;
0105 case MXC_CPU_IMX6ULL:
0106 ocotp_compat = "fsl,imx6ull-ocotp";
0107 soc_id = "i.MX6ULL";
0108 break;
0109 case MXC_CPU_IMX6ULZ:
0110 ocotp_compat = "fsl,imx6ull-ocotp";
0111 soc_id = "i.MX6ULZ";
0112 break;
0113 case MXC_CPU_IMX6SLL:
0114 ocotp_compat = "fsl,imx6sll-ocotp";
0115 soc_id = "i.MX6SLL";
0116 break;
0117 case MXC_CPU_IMX7D:
0118 ocotp_compat = "fsl,imx7d-ocotp";
0119 soc_id = "i.MX7D";
0120 break;
0121 case MXC_CPU_IMX7ULP:
0122 ocotp_compat = "fsl,imx7ulp-ocotp";
0123 soc_id = "i.MX7ULP";
0124 break;
0125 case MXC_CPU_VF500:
0126 ocotp_compat = "fsl,vf610-ocotp";
0127 soc_id = "VF500";
0128 break;
0129 case MXC_CPU_VF510:
0130 ocotp_compat = "fsl,vf610-ocotp";
0131 soc_id = "VF510";
0132 break;
0133 case MXC_CPU_VF600:
0134 ocotp_compat = "fsl,vf610-ocotp";
0135 soc_id = "VF600";
0136 break;
0137 case MXC_CPU_VF610:
0138 ocotp_compat = "fsl,vf610-ocotp";
0139 soc_id = "VF610";
0140 break;
0141 default:
0142 soc_id = "Unknown";
0143 }
0144 soc_dev_attr->soc_id = soc_id;
0145
0146 if (ocotp_compat) {
0147 ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat);
0148 if (IS_ERR(ocotp))
0149 pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat);
0150 }
0151
0152 if (!IS_ERR_OR_NULL(ocotp)) {
0153 if (__mxc_cpu_type == MXC_CPU_IMX7ULP) {
0154 regmap_read(ocotp, OCOTP_ULP_UID_4, &val);
0155 soc_uid = val & 0xffff;
0156 regmap_read(ocotp, OCOTP_ULP_UID_3, &val);
0157 soc_uid <<= 16;
0158 soc_uid |= val & 0xffff;
0159 regmap_read(ocotp, OCOTP_ULP_UID_2, &val);
0160 soc_uid <<= 16;
0161 soc_uid |= val & 0xffff;
0162 regmap_read(ocotp, OCOTP_ULP_UID_1, &val);
0163 soc_uid <<= 16;
0164 soc_uid |= val & 0xffff;
0165 } else if (__mxc_cpu_type == MXC_CPU_MX51 ||
0166 __mxc_cpu_type == MXC_CPU_MX53) {
0167 for (i=0; i < 8; i++) {
0168 regmap_read(ocotp, IIM_UID + i*4, &val);
0169 soc_uid <<= 8;
0170 soc_uid |= (val & 0xff);
0171 }
0172 } else {
0173 regmap_read(ocotp, OCOTP_UID_H, &val);
0174 soc_uid = val;
0175 regmap_read(ocotp, OCOTP_UID_L, &val);
0176 soc_uid <<= 32;
0177 soc_uid |= val;
0178 }
0179 }
0180
0181 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
0182 (imx_get_soc_revision() >> 4) & 0xf,
0183 imx_get_soc_revision() & 0xf);
0184 if (!soc_dev_attr->revision) {
0185 ret = -ENOMEM;
0186 goto free_soc;
0187 }
0188
0189 soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);
0190 if (!soc_dev_attr->serial_number) {
0191 ret = -ENOMEM;
0192 goto free_rev;
0193 }
0194
0195 soc_dev = soc_device_register(soc_dev_attr);
0196 if (IS_ERR(soc_dev)) {
0197 ret = PTR_ERR(soc_dev);
0198 goto free_serial_number;
0199 }
0200
0201 return 0;
0202
0203 free_serial_number:
0204 kfree(soc_dev_attr->serial_number);
0205 free_rev:
0206 kfree(soc_dev_attr->revision);
0207 free_soc:
0208 kfree(soc_dev_attr);
0209 return ret;
0210 }
0211 device_initcall(imx_soc_device_init);