152102a3bSPeng Fan // SPDX-License-Identifier: GPL-2.0 252102a3bSPeng Fan /* 352102a3bSPeng Fan * Copyright 2020 NXP 452102a3bSPeng Fan */ 552102a3bSPeng Fan 652102a3bSPeng Fan #include <linux/mfd/syscon.h> 752102a3bSPeng Fan #include <linux/of.h> 852102a3bSPeng Fan #include <linux/of_address.h> 952102a3bSPeng Fan #include <linux/regmap.h> 1052102a3bSPeng Fan #include <linux/slab.h> 1152102a3bSPeng Fan #include <linux/sys_soc.h> 1252102a3bSPeng Fan 1352102a3bSPeng Fan #include <soc/imx/cpu.h> 1452102a3bSPeng Fan #include <soc/imx/revision.h> 1552102a3bSPeng Fan 161168935bSSebastian Reichel #define IIM_UID 0x820 171168935bSSebastian Reichel 1852102a3bSPeng Fan #define OCOTP_UID_H 0x420 1952102a3bSPeng Fan #define OCOTP_UID_L 0x410 2052102a3bSPeng Fan 2152102a3bSPeng Fan #define OCOTP_ULP_UID_1 0x4b0 2252102a3bSPeng Fan #define OCOTP_ULP_UID_2 0x4c0 2352102a3bSPeng Fan #define OCOTP_ULP_UID_3 0x4d0 2452102a3bSPeng Fan #define OCOTP_ULP_UID_4 0x4e0 2552102a3bSPeng Fan 2652102a3bSPeng Fan static int __init imx_soc_device_init(void) 2752102a3bSPeng Fan { 2852102a3bSPeng Fan struct soc_device_attribute *soc_dev_attr; 2952102a3bSPeng Fan const char *ocotp_compat = NULL; 3052102a3bSPeng Fan struct soc_device *soc_dev; 3152102a3bSPeng Fan struct device_node *root; 3252102a3bSPeng Fan struct regmap *ocotp = NULL; 3352102a3bSPeng Fan const char *soc_id; 3452102a3bSPeng Fan u64 soc_uid = 0; 3552102a3bSPeng Fan u32 val; 3652102a3bSPeng Fan int ret; 371168935bSSebastian Reichel int i; 3852102a3bSPeng Fan 397f6e8dffSPeng Fan if (of_machine_is_compatible("fsl,ls1021a")) 407f6e8dffSPeng Fan return 0; 417f6e8dffSPeng Fan 4252102a3bSPeng Fan soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 4352102a3bSPeng Fan if (!soc_dev_attr) 4452102a3bSPeng Fan return -ENOMEM; 4552102a3bSPeng Fan 4652102a3bSPeng Fan soc_dev_attr->family = "Freescale i.MX"; 4752102a3bSPeng Fan 4852102a3bSPeng Fan root = of_find_node_by_path("/"); 4952102a3bSPeng Fan ret = of_property_read_string(root, "model", &soc_dev_attr->machine); 5052102a3bSPeng Fan of_node_put(root); 5152102a3bSPeng Fan if (ret) 5252102a3bSPeng Fan goto free_soc; 5352102a3bSPeng Fan 5452102a3bSPeng Fan switch (__mxc_cpu_type) { 5552102a3bSPeng Fan case MXC_CPU_MX1: 5652102a3bSPeng Fan soc_id = "i.MX1"; 5752102a3bSPeng Fan break; 5852102a3bSPeng Fan case MXC_CPU_MX21: 5952102a3bSPeng Fan soc_id = "i.MX21"; 6052102a3bSPeng Fan break; 6152102a3bSPeng Fan case MXC_CPU_MX25: 6252102a3bSPeng Fan soc_id = "i.MX25"; 6352102a3bSPeng Fan break; 6452102a3bSPeng Fan case MXC_CPU_MX27: 6552102a3bSPeng Fan soc_id = "i.MX27"; 6652102a3bSPeng Fan break; 6752102a3bSPeng Fan case MXC_CPU_MX31: 6852102a3bSPeng Fan soc_id = "i.MX31"; 6952102a3bSPeng Fan break; 7052102a3bSPeng Fan case MXC_CPU_MX35: 7152102a3bSPeng Fan soc_id = "i.MX35"; 7252102a3bSPeng Fan break; 73*22b5059bSJonathan Neuschäfer case MXC_CPU_MX50: 74*22b5059bSJonathan Neuschäfer soc_id = "i.MX50"; 75*22b5059bSJonathan Neuschäfer break; 7652102a3bSPeng Fan case MXC_CPU_MX51: 771168935bSSebastian Reichel ocotp_compat = "fsl,imx51-iim"; 7852102a3bSPeng Fan soc_id = "i.MX51"; 7952102a3bSPeng Fan break; 8052102a3bSPeng Fan case MXC_CPU_MX53: 811168935bSSebastian Reichel ocotp_compat = "fsl,imx53-iim"; 8252102a3bSPeng Fan soc_id = "i.MX53"; 8352102a3bSPeng Fan break; 8452102a3bSPeng Fan case MXC_CPU_IMX6SL: 8552102a3bSPeng Fan ocotp_compat = "fsl,imx6sl-ocotp"; 8652102a3bSPeng Fan soc_id = "i.MX6SL"; 8752102a3bSPeng Fan break; 8852102a3bSPeng Fan case MXC_CPU_IMX6DL: 8952102a3bSPeng Fan ocotp_compat = "fsl,imx6q-ocotp"; 9052102a3bSPeng Fan soc_id = "i.MX6DL"; 9152102a3bSPeng Fan break; 9252102a3bSPeng Fan case MXC_CPU_IMX6SX: 9352102a3bSPeng Fan ocotp_compat = "fsl,imx6sx-ocotp"; 9452102a3bSPeng Fan soc_id = "i.MX6SX"; 9552102a3bSPeng Fan break; 9652102a3bSPeng Fan case MXC_CPU_IMX6Q: 9752102a3bSPeng Fan ocotp_compat = "fsl,imx6q-ocotp"; 9852102a3bSPeng Fan soc_id = "i.MX6Q"; 9952102a3bSPeng Fan break; 10052102a3bSPeng Fan case MXC_CPU_IMX6UL: 10152102a3bSPeng Fan ocotp_compat = "fsl,imx6ul-ocotp"; 10252102a3bSPeng Fan soc_id = "i.MX6UL"; 10352102a3bSPeng Fan break; 10452102a3bSPeng Fan case MXC_CPU_IMX6ULL: 10552102a3bSPeng Fan ocotp_compat = "fsl,imx6ull-ocotp"; 10652102a3bSPeng Fan soc_id = "i.MX6ULL"; 10752102a3bSPeng Fan break; 10852102a3bSPeng Fan case MXC_CPU_IMX6ULZ: 10952102a3bSPeng Fan ocotp_compat = "fsl,imx6ull-ocotp"; 11052102a3bSPeng Fan soc_id = "i.MX6ULZ"; 11152102a3bSPeng Fan break; 11252102a3bSPeng Fan case MXC_CPU_IMX6SLL: 11352102a3bSPeng Fan ocotp_compat = "fsl,imx6sll-ocotp"; 11452102a3bSPeng Fan soc_id = "i.MX6SLL"; 11552102a3bSPeng Fan break; 11652102a3bSPeng Fan case MXC_CPU_IMX7D: 11752102a3bSPeng Fan ocotp_compat = "fsl,imx7d-ocotp"; 11852102a3bSPeng Fan soc_id = "i.MX7D"; 11952102a3bSPeng Fan break; 12052102a3bSPeng Fan case MXC_CPU_IMX7ULP: 12152102a3bSPeng Fan ocotp_compat = "fsl,imx7ulp-ocotp"; 12252102a3bSPeng Fan soc_id = "i.MX7ULP"; 12352102a3bSPeng Fan break; 12452102a3bSPeng Fan case MXC_CPU_VF500: 12552102a3bSPeng Fan ocotp_compat = "fsl,vf610-ocotp"; 12652102a3bSPeng Fan soc_id = "VF500"; 12752102a3bSPeng Fan break; 12852102a3bSPeng Fan case MXC_CPU_VF510: 12952102a3bSPeng Fan ocotp_compat = "fsl,vf610-ocotp"; 13052102a3bSPeng Fan soc_id = "VF510"; 13152102a3bSPeng Fan break; 13252102a3bSPeng Fan case MXC_CPU_VF600: 13352102a3bSPeng Fan ocotp_compat = "fsl,vf610-ocotp"; 13452102a3bSPeng Fan soc_id = "VF600"; 13552102a3bSPeng Fan break; 13652102a3bSPeng Fan case MXC_CPU_VF610: 13752102a3bSPeng Fan ocotp_compat = "fsl,vf610-ocotp"; 13852102a3bSPeng Fan soc_id = "VF610"; 13952102a3bSPeng Fan break; 14052102a3bSPeng Fan default: 14152102a3bSPeng Fan soc_id = "Unknown"; 14252102a3bSPeng Fan } 14352102a3bSPeng Fan soc_dev_attr->soc_id = soc_id; 14452102a3bSPeng Fan 14552102a3bSPeng Fan if (ocotp_compat) { 14652102a3bSPeng Fan ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat); 14752102a3bSPeng Fan if (IS_ERR(ocotp)) 14852102a3bSPeng Fan pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat); 14952102a3bSPeng Fan } 15052102a3bSPeng Fan 15152102a3bSPeng Fan if (!IS_ERR_OR_NULL(ocotp)) { 15252102a3bSPeng Fan if (__mxc_cpu_type == MXC_CPU_IMX7ULP) { 15352102a3bSPeng Fan regmap_read(ocotp, OCOTP_ULP_UID_4, &val); 15452102a3bSPeng Fan soc_uid = val & 0xffff; 15552102a3bSPeng Fan regmap_read(ocotp, OCOTP_ULP_UID_3, &val); 15652102a3bSPeng Fan soc_uid <<= 16; 15752102a3bSPeng Fan soc_uid |= val & 0xffff; 15852102a3bSPeng Fan regmap_read(ocotp, OCOTP_ULP_UID_2, &val); 15952102a3bSPeng Fan soc_uid <<= 16; 16052102a3bSPeng Fan soc_uid |= val & 0xffff; 16152102a3bSPeng Fan regmap_read(ocotp, OCOTP_ULP_UID_1, &val); 16252102a3bSPeng Fan soc_uid <<= 16; 16352102a3bSPeng Fan soc_uid |= val & 0xffff; 1641168935bSSebastian Reichel } else if (__mxc_cpu_type == MXC_CPU_MX51 || 1651168935bSSebastian Reichel __mxc_cpu_type == MXC_CPU_MX53) { 1661168935bSSebastian Reichel for (i=0; i < 8; i++) { 1671168935bSSebastian Reichel regmap_read(ocotp, IIM_UID + i*4, &val); 1681168935bSSebastian Reichel soc_uid <<= 8; 1691168935bSSebastian Reichel soc_uid |= (val & 0xff); 1701168935bSSebastian Reichel } 17152102a3bSPeng Fan } else { 17252102a3bSPeng Fan regmap_read(ocotp, OCOTP_UID_H, &val); 17352102a3bSPeng Fan soc_uid = val; 17452102a3bSPeng Fan regmap_read(ocotp, OCOTP_UID_L, &val); 17552102a3bSPeng Fan soc_uid <<= 32; 17652102a3bSPeng Fan soc_uid |= val; 17752102a3bSPeng Fan } 17852102a3bSPeng Fan } 17952102a3bSPeng Fan 18052102a3bSPeng Fan soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", 18152102a3bSPeng Fan (imx_get_soc_revision() >> 4) & 0xf, 18252102a3bSPeng Fan imx_get_soc_revision() & 0xf); 18352102a3bSPeng Fan if (!soc_dev_attr->revision) { 18452102a3bSPeng Fan ret = -ENOMEM; 18552102a3bSPeng Fan goto free_soc; 18652102a3bSPeng Fan } 18752102a3bSPeng Fan 18852102a3bSPeng Fan soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); 18952102a3bSPeng Fan if (!soc_dev_attr->serial_number) { 19052102a3bSPeng Fan ret = -ENOMEM; 19152102a3bSPeng Fan goto free_rev; 19252102a3bSPeng Fan } 19352102a3bSPeng Fan 19452102a3bSPeng Fan soc_dev = soc_device_register(soc_dev_attr); 19552102a3bSPeng Fan if (IS_ERR(soc_dev)) { 19652102a3bSPeng Fan ret = PTR_ERR(soc_dev); 19752102a3bSPeng Fan goto free_serial_number; 19852102a3bSPeng Fan } 19952102a3bSPeng Fan 20052102a3bSPeng Fan return 0; 20152102a3bSPeng Fan 20252102a3bSPeng Fan free_serial_number: 20352102a3bSPeng Fan kfree(soc_dev_attr->serial_number); 20452102a3bSPeng Fan free_rev: 20552102a3bSPeng Fan kfree(soc_dev_attr->revision); 20652102a3bSPeng Fan free_soc: 20752102a3bSPeng Fan kfree(soc_dev_attr); 20852102a3bSPeng Fan return ret; 20952102a3bSPeng Fan } 21052102a3bSPeng Fan device_initcall(imx_soc_device_init); 211