18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2020 NXP 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/of_address.h> 98c2ecf20Sopenharmony_ci#include <linux/regmap.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <soc/imx/cpu.h> 148c2ecf20Sopenharmony_ci#include <soc/imx/revision.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define OCOTP_UID_H 0x420 178c2ecf20Sopenharmony_ci#define OCOTP_UID_L 0x410 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define OCOTP_ULP_UID_1 0x4b0 208c2ecf20Sopenharmony_ci#define OCOTP_ULP_UID_2 0x4c0 218c2ecf20Sopenharmony_ci#define OCOTP_ULP_UID_3 0x4d0 228c2ecf20Sopenharmony_ci#define OCOTP_ULP_UID_4 0x4e0 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int __init imx_soc_device_init(void) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 278c2ecf20Sopenharmony_ci const char *ocotp_compat = NULL; 288c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 298c2ecf20Sopenharmony_ci struct device_node *root; 308c2ecf20Sopenharmony_ci struct regmap *ocotp = NULL; 318c2ecf20Sopenharmony_ci const char *soc_id; 328c2ecf20Sopenharmony_ci u64 soc_uid = 0; 338c2ecf20Sopenharmony_ci u32 val; 348c2ecf20Sopenharmony_ci int ret; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* Return early if this is running on devices with different SoCs */ 378c2ecf20Sopenharmony_ci if (!__mxc_cpu_type) 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (of_machine_is_compatible("fsl,ls1021a")) 418c2ecf20Sopenharmony_ci return 0; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 448c2ecf20Sopenharmony_ci if (!soc_dev_attr) 458c2ecf20Sopenharmony_ci return -ENOMEM; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci soc_dev_attr->family = "Freescale i.MX"; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci root = of_find_node_by_path("/"); 508c2ecf20Sopenharmony_ci ret = of_property_read_string(root, "model", &soc_dev_attr->machine); 518c2ecf20Sopenharmony_ci of_node_put(root); 528c2ecf20Sopenharmony_ci if (ret) 538c2ecf20Sopenharmony_ci goto free_soc; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci switch (__mxc_cpu_type) { 568c2ecf20Sopenharmony_ci case MXC_CPU_MX1: 578c2ecf20Sopenharmony_ci soc_id = "i.MX1"; 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci case MXC_CPU_MX21: 608c2ecf20Sopenharmony_ci soc_id = "i.MX21"; 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case MXC_CPU_MX25: 638c2ecf20Sopenharmony_ci soc_id = "i.MX25"; 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case MXC_CPU_MX27: 668c2ecf20Sopenharmony_ci soc_id = "i.MX27"; 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case MXC_CPU_MX31: 698c2ecf20Sopenharmony_ci soc_id = "i.MX31"; 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case MXC_CPU_MX35: 728c2ecf20Sopenharmony_ci soc_id = "i.MX35"; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci case MXC_CPU_MX51: 758c2ecf20Sopenharmony_ci soc_id = "i.MX51"; 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci case MXC_CPU_MX53: 788c2ecf20Sopenharmony_ci soc_id = "i.MX53"; 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case MXC_CPU_IMX6SL: 818c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6sl-ocotp"; 828c2ecf20Sopenharmony_ci soc_id = "i.MX6SL"; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case MXC_CPU_IMX6DL: 858c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6q-ocotp"; 868c2ecf20Sopenharmony_ci soc_id = "i.MX6DL"; 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case MXC_CPU_IMX6SX: 898c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6sx-ocotp"; 908c2ecf20Sopenharmony_ci soc_id = "i.MX6SX"; 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci case MXC_CPU_IMX6Q: 938c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6q-ocotp"; 948c2ecf20Sopenharmony_ci soc_id = "i.MX6Q"; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci case MXC_CPU_IMX6UL: 978c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6ul-ocotp"; 988c2ecf20Sopenharmony_ci soc_id = "i.MX6UL"; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case MXC_CPU_IMX6ULL: 1018c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6ull-ocotp"; 1028c2ecf20Sopenharmony_ci soc_id = "i.MX6ULL"; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci case MXC_CPU_IMX6ULZ: 1058c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6ull-ocotp"; 1068c2ecf20Sopenharmony_ci soc_id = "i.MX6ULZ"; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case MXC_CPU_IMX6SLL: 1098c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx6sll-ocotp"; 1108c2ecf20Sopenharmony_ci soc_id = "i.MX6SLL"; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case MXC_CPU_IMX7D: 1138c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx7d-ocotp"; 1148c2ecf20Sopenharmony_ci soc_id = "i.MX7D"; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case MXC_CPU_IMX7ULP: 1178c2ecf20Sopenharmony_ci ocotp_compat = "fsl,imx7ulp-ocotp"; 1188c2ecf20Sopenharmony_ci soc_id = "i.MX7ULP"; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case MXC_CPU_VF500: 1218c2ecf20Sopenharmony_ci ocotp_compat = "fsl,vf610-ocotp"; 1228c2ecf20Sopenharmony_ci soc_id = "VF500"; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci case MXC_CPU_VF510: 1258c2ecf20Sopenharmony_ci ocotp_compat = "fsl,vf610-ocotp"; 1268c2ecf20Sopenharmony_ci soc_id = "VF510"; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case MXC_CPU_VF600: 1298c2ecf20Sopenharmony_ci ocotp_compat = "fsl,vf610-ocotp"; 1308c2ecf20Sopenharmony_ci soc_id = "VF600"; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case MXC_CPU_VF610: 1338c2ecf20Sopenharmony_ci ocotp_compat = "fsl,vf610-ocotp"; 1348c2ecf20Sopenharmony_ci soc_id = "VF610"; 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci default: 1378c2ecf20Sopenharmony_ci soc_id = "Unknown"; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci soc_dev_attr->soc_id = soc_id; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (ocotp_compat) { 1428c2ecf20Sopenharmony_ci ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat); 1438c2ecf20Sopenharmony_ci if (IS_ERR(ocotp)) 1448c2ecf20Sopenharmony_ci pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(ocotp)) { 1488c2ecf20Sopenharmony_ci if (__mxc_cpu_type == MXC_CPU_IMX7ULP) { 1498c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_ULP_UID_4, &val); 1508c2ecf20Sopenharmony_ci soc_uid = val & 0xffff; 1518c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_ULP_UID_3, &val); 1528c2ecf20Sopenharmony_ci soc_uid <<= 16; 1538c2ecf20Sopenharmony_ci soc_uid |= val & 0xffff; 1548c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_ULP_UID_2, &val); 1558c2ecf20Sopenharmony_ci soc_uid <<= 16; 1568c2ecf20Sopenharmony_ci soc_uid |= val & 0xffff; 1578c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_ULP_UID_1, &val); 1588c2ecf20Sopenharmony_ci soc_uid <<= 16; 1598c2ecf20Sopenharmony_ci soc_uid |= val & 0xffff; 1608c2ecf20Sopenharmony_ci } else { 1618c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_UID_H, &val); 1628c2ecf20Sopenharmony_ci soc_uid = val; 1638c2ecf20Sopenharmony_ci regmap_read(ocotp, OCOTP_UID_L, &val); 1648c2ecf20Sopenharmony_ci soc_uid <<= 32; 1658c2ecf20Sopenharmony_ci soc_uid |= val; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", 1708c2ecf20Sopenharmony_ci (imx_get_soc_revision() >> 4) & 0xf, 1718c2ecf20Sopenharmony_ci imx_get_soc_revision() & 0xf); 1728c2ecf20Sopenharmony_ci if (!soc_dev_attr->revision) { 1738c2ecf20Sopenharmony_ci ret = -ENOMEM; 1748c2ecf20Sopenharmony_ci goto free_soc; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); 1788c2ecf20Sopenharmony_ci if (!soc_dev_attr->serial_number) { 1798c2ecf20Sopenharmony_ci ret = -ENOMEM; 1808c2ecf20Sopenharmony_ci goto free_rev; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 1848c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 1858c2ecf20Sopenharmony_ci ret = PTR_ERR(soc_dev); 1868c2ecf20Sopenharmony_ci goto free_serial_number; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cifree_serial_number: 1928c2ecf20Sopenharmony_ci kfree(soc_dev_attr->serial_number); 1938c2ecf20Sopenharmony_cifree_rev: 1948c2ecf20Sopenharmony_ci kfree(soc_dev_attr->revision); 1958c2ecf20Sopenharmony_cifree_soc: 1968c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 1978c2ecf20Sopenharmony_ci return ret; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_cidevice_initcall(imx_soc_device_init); 200