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>
This commit is contained in:
Anson Huang 2019-10-28 17:16:01 +08:00 committed by Shawn Guo
parent 427fca60ee
commit 8267ff89b7

View file

@ -1,15 +1,20 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/err.h> #include <linux/err.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include "hardware.h" #include "hardware.h"
#include "common.h" #include "common.h"
#define OCOTP_UID_H 0x420
#define OCOTP_UID_L 0x410
unsigned int __mxc_cpu_type; unsigned int __mxc_cpu_type;
static unsigned int imx_soc_revision; 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 device * __init imx_soc_device_init(void)
{ {
struct soc_device_attribute *soc_dev_attr; struct soc_device_attribute *soc_dev_attr;
const char *ocotp_compat = NULL;
struct soc_device *soc_dev; struct soc_device *soc_dev;
struct device_node *root; struct device_node *root;
struct regmap *ocotp;
const char *soc_id; const char *soc_id;
u64 soc_uid = 0;
u32 val;
int ret; int ret;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 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"; soc_id = "i.MX53";
break; break;
case MXC_CPU_IMX6SL: case MXC_CPU_IMX6SL:
ocotp_compat = "fsl,imx6sl-ocotp";
soc_id = "i.MX6SL"; soc_id = "i.MX6SL";
break; break;
case MXC_CPU_IMX6DL: case MXC_CPU_IMX6DL:
ocotp_compat = "fsl,imx6q-ocotp";
soc_id = "i.MX6DL"; soc_id = "i.MX6DL";
break; break;
case MXC_CPU_IMX6SX: case MXC_CPU_IMX6SX:
ocotp_compat = "fsl,imx6sx-ocotp";
soc_id = "i.MX6SX"; soc_id = "i.MX6SX";
break; break;
case MXC_CPU_IMX6Q: case MXC_CPU_IMX6Q:
ocotp_compat = "fsl,imx6q-ocotp";
soc_id = "i.MX6Q"; soc_id = "i.MX6Q";
break; break;
case MXC_CPU_IMX6UL: case MXC_CPU_IMX6UL:
ocotp_compat = "fsl,imx6ul-ocotp";
soc_id = "i.MX6UL"; soc_id = "i.MX6UL";
break; break;
case MXC_CPU_IMX6ULL: case MXC_CPU_IMX6ULL:
ocotp_compat = "fsl,imx6ul-ocotp";
soc_id = "i.MX6ULL"; soc_id = "i.MX6ULL";
break; break;
case MXC_CPU_IMX6ULZ: case MXC_CPU_IMX6ULZ:
ocotp_compat = "fsl,imx6ul-ocotp";
soc_id = "i.MX6ULZ"; soc_id = "i.MX6ULZ";
break; break;
case MXC_CPU_IMX6SLL: case MXC_CPU_IMX6SLL:
ocotp_compat = "fsl,imx6sll-ocotp";
soc_id = "i.MX6SLL"; soc_id = "i.MX6SLL";
break; break;
case MXC_CPU_IMX7D: case MXC_CPU_IMX7D:
ocotp_compat = "fsl,imx7d-ocotp";
soc_id = "i.MX7D"; soc_id = "i.MX7D";
break; break;
case MXC_CPU_IMX7ULP: case MXC_CPU_IMX7ULP:
@ -153,18 +171,36 @@ struct device * __init imx_soc_device_init(void)
} }
soc_dev_attr->soc_id = soc_id; 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", soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
(imx_soc_revision >> 4) & 0xf, (imx_soc_revision >> 4) & 0xf,
imx_soc_revision & 0xf); imx_soc_revision & 0xf);
if (!soc_dev_attr->revision) if (!soc_dev_attr->revision)
goto free_soc; 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); soc_dev = soc_device_register(soc_dev_attr);
if (IS_ERR(soc_dev)) if (IS_ERR(soc_dev))
goto free_rev; goto free_serial_number;
return soc_device_to_device(soc_dev); return soc_device_to_device(soc_dev);
free_serial_number:
kfree(soc_dev_attr->serial_number);
free_rev: free_rev:
kfree(soc_dev_attr->revision); kfree(soc_dev_attr->revision);
free_soc: free_soc: