diff options
author | Anson Huang | 2019-10-28 17:16:01 +0800 |
---|---|---|
committer | Shawn Guo | 2019-10-28 21:28:55 +0800 |
commit | 8267ff89b71317407f2c6938bd66f3a87070e45f (patch) | |
tree | d8afb4fedefaac64eea85eb45436756d9dadc5b6 /arch/arm/mach-imx | |
parent | 427fca60ee4524d7755cc7a980280e7ac6d92877 (diff) |
ARM: imx: Add serial number support for i.MX6/7 SoCs
i.MX6/7 SoCs have a 64-bit SoC unique ID stored in OCOTP,
it can be used as SoC serial number, add this support for
i.MX6Q/6DL/6SL/6SX/6SLL/6UL/6ULL/6ULZ/7D, see below example
on i.MX6Q:
root@imx6qpdlsolox:~# cat /sys/devices/soc0/serial_number
240F31D4E1FDFCA7
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
Signed-off-by: Shawn Guo <shawnguo@kernel.org>
Diffstat (limited to 'arch/arm/mach-imx')
-rw-r--r-- | arch/arm/mach-imx/cpu.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index 0b137eeffb61..d8118031c51f 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -1,15 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/err.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/regmap.h> #include <linux/slab.h> #include <linux/sys_soc.h> #include "hardware.h" #include "common.h" +#define OCOTP_UID_H 0x420 +#define OCOTP_UID_L 0x410 + unsigned int __mxc_cpu_type; static unsigned int imx_soc_revision; @@ -76,9 +81,13 @@ void __init imx_aips_allow_unprivileged_access( struct device * __init imx_soc_device_init(void) { struct soc_device_attribute *soc_dev_attr; + const char *ocotp_compat = NULL; struct soc_device *soc_dev; struct device_node *root; + struct regmap *ocotp; const char *soc_id; + u64 soc_uid = 0; + u32 val; int ret; soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); @@ -119,30 +128,39 @@ struct device * __init imx_soc_device_init(void) soc_id = "i.MX53"; break; case MXC_CPU_IMX6SL: + ocotp_compat = "fsl,imx6sl-ocotp"; soc_id = "i.MX6SL"; break; case MXC_CPU_IMX6DL: + ocotp_compat = "fsl,imx6q-ocotp"; soc_id = "i.MX6DL"; break; case MXC_CPU_IMX6SX: + ocotp_compat = "fsl,imx6sx-ocotp"; soc_id = "i.MX6SX"; break; case MXC_CPU_IMX6Q: + ocotp_compat = "fsl,imx6q-ocotp"; soc_id = "i.MX6Q"; break; case MXC_CPU_IMX6UL: + ocotp_compat = "fsl,imx6ul-ocotp"; soc_id = "i.MX6UL"; break; case MXC_CPU_IMX6ULL: + ocotp_compat = "fsl,imx6ul-ocotp"; soc_id = "i.MX6ULL"; break; case MXC_CPU_IMX6ULZ: + ocotp_compat = "fsl,imx6ul-ocotp"; soc_id = "i.MX6ULZ"; break; case MXC_CPU_IMX6SLL: + ocotp_compat = "fsl,imx6sll-ocotp"; soc_id = "i.MX6SLL"; break; case MXC_CPU_IMX7D: + ocotp_compat = "fsl,imx7d-ocotp"; soc_id = "i.MX7D"; break; case MXC_CPU_IMX7ULP: @@ -153,18 +171,36 @@ struct device * __init imx_soc_device_init(void) } soc_dev_attr->soc_id = soc_id; + if (ocotp_compat) { + ocotp = syscon_regmap_lookup_by_compatible(ocotp_compat); + if (IS_ERR(ocotp)) + pr_err("%s: failed to find %s regmap!\n", __func__, ocotp_compat); + + regmap_read(ocotp, OCOTP_UID_H, &val); + soc_uid = val; + regmap_read(ocotp, OCOTP_UID_L, &val); + soc_uid <<= 32; + soc_uid |= val; + } + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", (imx_soc_revision >> 4) & 0xf, imx_soc_revision & 0xf); if (!soc_dev_attr->revision) goto free_soc; + soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); + if (!soc_dev_attr->serial_number) + goto free_rev; + soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) - goto free_rev; + goto free_serial_number; return soc_device_to_device(soc_dev); +free_serial_number: + kfree(soc_dev_attr->serial_number); free_rev: kfree(soc_dev_attr->revision); free_soc: |