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:
parent
427fca60ee
commit
8267ff89b7
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue