Commit 786dde1e authored by Michael Walle's avatar Michael Walle Committed by Shawn Guo

soc: fsl: guts: add serial_number support

Most layerscapes provide a security fuse processor where the vendor
will store a unique id per part. Unfortunately, we cannot use the
corresponding efuse driver because this driver needs to be ready
early during the boot phase. To get the unique identifier, we just
need to access two registers. Thus we just search the device tree
for the corresponding device, map its memory to read the id and then
unmap it again.

Because it is likely that the offset within the fuses is dependent
on the SoC, we need a per SoC data. Also, the compatible string is
different among the SoCs. For now, this add support for the LS1028A
SoC.
Signed-off-by: default avatarMichael Walle <michael@walle.cc>
Acked-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarShawn Guo <shawnguo@kernel.org>
parent 55488c90
...@@ -20,6 +20,11 @@ struct fsl_soc_die_attr { ...@@ -20,6 +20,11 @@ struct fsl_soc_die_attr {
u32 mask; u32 mask;
}; };
struct fsl_soc_data {
const char *sfp_compat;
u32 uid_offset;
};
/* SoC die attribute definition for QorIQ platform */ /* SoC die attribute definition for QorIQ platform */
static const struct fsl_soc_die_attr fsl_soc_die[] = { static const struct fsl_soc_die_attr fsl_soc_die[] = {
/* /*
...@@ -110,6 +115,33 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match( ...@@ -110,6 +115,33 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
return NULL; return NULL;
} }
static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
{
struct device_node *np;
void __iomem *sfp_base;
u64 uid;
np = of_find_compatible_node(NULL, NULL, compat);
if (!np)
return 0;
sfp_base = of_iomap(np, 0);
uid = ioread32(sfp_base + offset);
uid <<= 32;
uid |= ioread32(sfp_base + offset + 4);
iounmap(sfp_base);
of_node_put(np);
return uid;
}
static const struct fsl_soc_data ls1028a_data = {
.sfp_compat = "fsl,ls1028a-sfp",
.uid_offset = 0x21c,
};
/* /*
* Table for matching compatible strings, for device tree * Table for matching compatible strings, for device tree
* guts node, for Freescale QorIQ SOCs. * guts node, for Freescale QorIQ SOCs.
...@@ -138,7 +170,7 @@ static const struct of_device_id fsl_guts_of_match[] = { ...@@ -138,7 +170,7 @@ static const struct of_device_id fsl_guts_of_match[] = {
{ .compatible = "fsl,ls1012a-dcfg", }, { .compatible = "fsl,ls1012a-dcfg", },
{ .compatible = "fsl,ls1046a-dcfg", }, { .compatible = "fsl,ls1046a-dcfg", },
{ .compatible = "fsl,lx2160a-dcfg", }, { .compatible = "fsl,lx2160a-dcfg", },
{ .compatible = "fsl,ls1028a-dcfg", }, { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
{} {}
}; };
...@@ -147,16 +179,20 @@ static int __init fsl_guts_init(void) ...@@ -147,16 +179,20 @@ static int __init fsl_guts_init(void)
struct soc_device_attribute *soc_dev_attr; struct soc_device_attribute *soc_dev_attr;
static struct soc_device *soc_dev; static struct soc_device *soc_dev;
const struct fsl_soc_die_attr *soc_die; const struct fsl_soc_die_attr *soc_die;
const struct fsl_soc_data *soc_data;
const struct of_device_id *match;
struct ccsr_guts __iomem *regs; struct ccsr_guts __iomem *regs;
const char *machine = NULL; const char *machine = NULL;
struct device_node *np; struct device_node *np;
bool little_endian; bool little_endian;
u64 soc_uid = 0;
u32 svr; u32 svr;
int ret; int ret;
np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, NULL); np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
if (!np) if (!np)
return 0; return 0;
soc_data = match->data;
regs = of_iomap(np, 0); regs = of_iomap(np, 0);
if (IS_ERR(regs)) { if (IS_ERR(regs)) {
...@@ -204,6 +240,13 @@ static int __init fsl_guts_init(void) ...@@ -204,6 +240,13 @@ static int __init fsl_guts_init(void)
if (!soc_dev_attr->revision) if (!soc_dev_attr->revision)
goto err_nomem; goto err_nomem;
if (soc_data)
soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
soc_data->uid_offset);
if (soc_uid)
soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
soc_uid);
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)) {
ret = PTR_ERR(soc_dev); ret = PTR_ERR(soc_dev);
...@@ -224,6 +267,7 @@ static int __init fsl_guts_init(void) ...@@ -224,6 +267,7 @@ static int __init fsl_guts_init(void)
kfree(soc_dev_attr->family); kfree(soc_dev_attr->family);
kfree(soc_dev_attr->soc_id); kfree(soc_dev_attr->soc_id);
kfree(soc_dev_attr->revision); kfree(soc_dev_attr->revision);
kfree(soc_dev_attr->serial_number);
kfree(soc_dev_attr); kfree(soc_dev_attr);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment