212 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2020 NXP4 */5 6#include <linux/mfd/syscon.h>7#include <linux/of.h>8#include <linux/of_address.h>9#include <linux/regmap.h>10#include <linux/slab.h>11#include <linux/sys_soc.h>12 13#include <soc/imx/cpu.h>14#include <soc/imx/revision.h>15 16#define IIM_UID 0x82017 18#define OCOTP_UID_H 0x42019#define OCOTP_UID_L 0x41020 21#define OCOTP_ULP_UID_1 0x4b022#define OCOTP_ULP_UID_2 0x4c023#define OCOTP_ULP_UID_3 0x4d024#define OCOTP_ULP_UID_4 0x4e025 26static int __init imx_soc_device_init(void)27{28 struct soc_device_attribute *soc_dev_attr;29 const char *ocotp_compat = NULL;30 struct soc_device *soc_dev;31 struct device_node *root;32 struct regmap *ocotp = NULL;33 const char *soc_id;34 u64 soc_uid = 0;35 u32 val;36 int ret;37 int i;38 39 /* Return early if this is running on devices with different SoCs */40 if (!__mxc_cpu_type)41 return 0;42 43 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);44 if (!soc_dev_attr)45 return -ENOMEM;46 47 soc_dev_attr->family = "Freescale i.MX";48 49 root = of_find_node_by_path("/");50 ret = of_property_read_string(root, "model", &soc_dev_attr->machine);51 of_node_put(root);52 if (ret)53 goto free_soc;54 55 switch (__mxc_cpu_type) {56 case MXC_CPU_MX1:57 soc_id = "i.MX1";58 break;59 case MXC_CPU_MX21:60 soc_id = "i.MX21";61 break;62 case MXC_CPU_MX25:63 soc_id = "i.MX25";64 break;65 case MXC_CPU_MX27:66 soc_id = "i.MX27";67 break;68 case MXC_CPU_MX31:69 soc_id = "i.MX31";70 break;71 case MXC_CPU_MX35:72 soc_id = "i.MX35";73 break;74 case MXC_CPU_MX50:75 soc_id = "i.MX50";76 break;77 case MXC_CPU_MX51:78 ocotp_compat = "fsl,imx51-iim";79 soc_id = "i.MX51";80 break;81 case MXC_CPU_MX53:82 ocotp_compat = "fsl,imx53-iim";83 soc_id = "i.MX53";84 break;85 case MXC_CPU_IMX6SL:86 ocotp_compat = "fsl,imx6sl-ocotp";87 soc_id = "i.MX6SL";88 break;89 case MXC_CPU_IMX6DL:90 ocotp_compat = "fsl,imx6q-ocotp";91 soc_id = "i.MX6DL";92 break;93 case MXC_CPU_IMX6SX:94 ocotp_compat = "fsl,imx6sx-ocotp";95 soc_id = "i.MX6SX";96 break;97 case MXC_CPU_IMX6Q:98 ocotp_compat = "fsl,imx6q-ocotp";99 soc_id = "i.MX6Q";100 break;101 case MXC_CPU_IMX6UL:102 ocotp_compat = "fsl,imx6ul-ocotp";103 soc_id = "i.MX6UL";104 break;105 case MXC_CPU_IMX6ULL:106 ocotp_compat = "fsl,imx6ull-ocotp";107 soc_id = "i.MX6ULL";108 break;109 case MXC_CPU_IMX6ULZ:110 ocotp_compat = "fsl,imx6ull-ocotp";111 soc_id = "i.MX6ULZ";112 break;113 case MXC_CPU_IMX6SLL:114 ocotp_compat = "fsl,imx6sll-ocotp";115 soc_id = "i.MX6SLL";116 break;117 case MXC_CPU_IMX7D:118 ocotp_compat = "fsl,imx7d-ocotp";119 soc_id = "i.MX7D";120 break;121 case MXC_CPU_IMX7ULP:122 ocotp_compat = "fsl,imx7ulp-ocotp";123 soc_id = "i.MX7ULP";124 break;125 case MXC_CPU_VF500:126 ocotp_compat = "fsl,vf610-ocotp";127 soc_id = "VF500";128 break;129 case MXC_CPU_VF510:130 ocotp_compat = "fsl,vf610-ocotp";131 soc_id = "VF510";132 break;133 case MXC_CPU_VF600:134 ocotp_compat = "fsl,vf610-ocotp";135 soc_id = "VF600";136 break;137 case MXC_CPU_VF610:138 ocotp_compat = "fsl,vf610-ocotp";139 soc_id = "VF610";140 break;141 default:142 soc_id = "Unknown";143 }144 soc_dev_attr->soc_id = soc_id;145 146 if (ocotp_compat) {147 ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat);148 if (IS_ERR(ocotp))149 pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat);150 }151 152 if (!IS_ERR_OR_NULL(ocotp)) {153 if (__mxc_cpu_type == MXC_CPU_IMX7ULP) {154 regmap_read(ocotp, OCOTP_ULP_UID_4, &val);155 soc_uid = val & 0xffff;156 regmap_read(ocotp, OCOTP_ULP_UID_3, &val);157 soc_uid <<= 16;158 soc_uid |= val & 0xffff;159 regmap_read(ocotp, OCOTP_ULP_UID_2, &val);160 soc_uid <<= 16;161 soc_uid |= val & 0xffff;162 regmap_read(ocotp, OCOTP_ULP_UID_1, &val);163 soc_uid <<= 16;164 soc_uid |= val & 0xffff;165 } else if (__mxc_cpu_type == MXC_CPU_MX51 ||166 __mxc_cpu_type == MXC_CPU_MX53) {167 for (i=0; i < 8; i++) {168 regmap_read(ocotp, IIM_UID + i*4, &val);169 soc_uid <<= 8;170 soc_uid |= (val & 0xff);171 }172 } else {173 regmap_read(ocotp, OCOTP_UID_H, &val);174 soc_uid = val;175 regmap_read(ocotp, OCOTP_UID_L, &val);176 soc_uid <<= 32;177 soc_uid |= val;178 }179 }180 181 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",182 (imx_get_soc_revision() >> 4) & 0xf,183 imx_get_soc_revision() & 0xf);184 if (!soc_dev_attr->revision) {185 ret = -ENOMEM;186 goto free_soc;187 }188 189 soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid);190 if (!soc_dev_attr->serial_number) {191 ret = -ENOMEM;192 goto free_rev;193 }194 195 soc_dev = soc_device_register(soc_dev_attr);196 if (IS_ERR(soc_dev)) {197 ret = PTR_ERR(soc_dev);198 goto free_serial_number;199 }200 201 return 0;202 203free_serial_number:204 kfree(soc_dev_attr->serial_number);205free_rev:206 kfree(soc_dev_attr->revision);207free_soc:208 kfree(soc_dev_attr);209 return ret;210}211device_initcall(imx_soc_device_init);212