mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 04:09:55 -04:00
nvmem: airoha: Add support for SMC eFUSE
Add support for SMC eFUSE on AN7581 SoC. The SoC have 2 set of 2048 bits of eFUSE that are used to read calibration value for PCIe, Thermal, USB and other specific info of the SoC like revision and HW device present. eFuse value are taken by sending SMC command. ATF is responsible of validaing the data and rejecting reading protected data (like Private Key). In such case the SMC command will return non-zero value on a0 register. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com> Signed-off-by: Srinivas Kandagatla <srini@kernel.org> Link: https://patch.msgid.link/20260530205333.117458-12-srini@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2956111189
commit
b7846af2e6
@@ -28,6 +28,19 @@ source "drivers/nvmem/layouts/Kconfig"
|
||||
|
||||
# Devices
|
||||
|
||||
config NVMEM_AIROHA_SMC_EFUSES
|
||||
tristate "Airoha SMC eFuse support"
|
||||
depends on ARCH_AIROHA || COMPILE_TEST
|
||||
depends on HAVE_ARM_SMCCC
|
||||
default ARCH_AIROHA
|
||||
help
|
||||
Say y here to enable support for reading eFuses on Airoha AN7581
|
||||
SoCs. These are e.g. used to store factory programmed
|
||||
calibration data required for the PCIe or the USB-C PHY or Thermal.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called nvmem-airoha-smc-efuses.
|
||||
|
||||
config NVMEM_AN8855_EFUSE
|
||||
tristate "Airoha AN8855 eFuse support"
|
||||
depends on COMPILE_TEST
|
||||
|
||||
@@ -10,6 +10,8 @@ nvmem_layouts-y := layouts.o
|
||||
obj-y += layouts/
|
||||
|
||||
# Devices
|
||||
obj-$(CONFIG_NVMEM_AIROHA_SMC_EFUSES) += nvmem-airoha-smc-efuses.o
|
||||
nvmem-airoha-smc-efuses-y := airoha-smc-efuses.o
|
||||
obj-$(CONFIG_NVMEM_AN8855_EFUSE) += nvmem-an8855-efuse.o
|
||||
nvmem-an8855-efuse-y := an8855-efuse.o
|
||||
obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o
|
||||
|
||||
125
drivers/nvmem/airoha-smc-efuses.c
Normal file
125
drivers/nvmem/airoha-smc-efuses.c
Normal file
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Author: Christian Marangi <ansuelsmth@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define AIROHA_SMC_EFUSE_FID 0x82000001
|
||||
#define AIROHA_SMC_EFUSE_SUB_ID_READ 0x44414552
|
||||
|
||||
#define AIROHA_EFUSE_CELLS 64
|
||||
|
||||
struct airoha_efuse_bank_priv {
|
||||
u32 bank_index;
|
||||
};
|
||||
|
||||
static int airoha_efuse_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
struct regmap *regmap = context;
|
||||
|
||||
return regmap_bulk_read(regmap, offset,
|
||||
val, bytes / sizeof(u32));
|
||||
}
|
||||
|
||||
static int airoha_efuse_reg_read(void *context, unsigned int offset,
|
||||
unsigned int *val)
|
||||
{
|
||||
struct airoha_efuse_bank_priv *priv = context;
|
||||
struct arm_smccc_res res;
|
||||
|
||||
arm_smccc_1_1_invoke(AIROHA_SMC_EFUSE_FID,
|
||||
AIROHA_SMC_EFUSE_SUB_ID_READ,
|
||||
priv->bank_index, offset, 0, 0, 0, 0, &res);
|
||||
|
||||
/* check if SMC reported an error */
|
||||
if (res.a0)
|
||||
return -EIO;
|
||||
|
||||
*val = res.a1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_efuse_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
for_each_child_of_node_scoped(dev->of_node, child) {
|
||||
struct nvmem_config nvmem_config = {
|
||||
.size = AIROHA_EFUSE_CELLS * sizeof(u32),
|
||||
.stride = sizeof(u32),
|
||||
.word_size = sizeof(u32),
|
||||
.reg_read = airoha_efuse_read,
|
||||
};
|
||||
struct regmap_config regmap_config = {
|
||||
.reg_read = airoha_efuse_reg_read,
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
struct airoha_efuse_bank_priv *priv;
|
||||
struct nvmem_device *nvmem;
|
||||
struct regmap *regmap;
|
||||
const char *name;
|
||||
u32 bank;
|
||||
|
||||
ret = of_property_read_u32(child, "reg", &bank);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "airoha-efuse-%u",
|
||||
bank);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->bank_index = bank;
|
||||
|
||||
regmap_config.name = name;
|
||||
regmap = devm_regmap_init(dev, NULL, priv,
|
||||
®map_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
nvmem_config.name = name;
|
||||
nvmem_config.priv = regmap;
|
||||
nvmem_config.dev = dev;
|
||||
nvmem_config.id = bank;
|
||||
nvmem_config.of_node = child;
|
||||
nvmem = devm_nvmem_register(dev, &nvmem_config);
|
||||
if (IS_ERR(nvmem))
|
||||
return PTR_ERR(nvmem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id airoha_efuse_of_match[] = {
|
||||
{ .compatible = "airoha,an7581-efuses", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, airoha_efuse_of_match);
|
||||
|
||||
static struct platform_driver airoha_efuse_driver = {
|
||||
.probe = airoha_efuse_probe,
|
||||
.driver = {
|
||||
.name = "airoha-efuse",
|
||||
.of_match_table = airoha_efuse_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(airoha_efuse_driver);
|
||||
|
||||
MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver for Airoha SMC eFUSEs");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user