Skip to content

Commit

Permalink
nvmem: sec-qfprom: Add Qualcomm secure QFPROM support
Browse files Browse the repository at this point in the history
For some of the Qualcomm SoC's, it is possible that
some of the fuse regions or entire qfprom region is
protected from non-secure access. In such situations,
the OS will have to use secure calls to read the region.
With that motivation, add secure qfprom driver.

Signed-off-by: Komal Bajaj <quic_kbajaj@quicinc.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20230823132744.350618-18-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Komal Bajaj authored and Greg Kroah-Hartman committed Aug 23, 2023
1 parent fcdc6d7 commit c471245
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
13 changes: 13 additions & 0 deletions drivers/nvmem/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,19 @@ config NVMEM_QCOM_QFPROM
This driver can also be built as a module. If so, the module
will be called nvmem_qfprom.

config NVMEM_QCOM_SEC_QFPROM
tristate "QCOM SECURE QFPROM Support"
depends on ARCH_QCOM || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
select QCOM_SCM
help
Say y here to enable secure QFPROM support. The secure QFPROM provides access
functions for QFPROM data to rest of the drivers via nvmem interface.

This driver can also be built as a module. If so, the module will be called
nvmem_sec_qfprom.

config NVMEM_RAVE_SP_EEPROM
tristate "Rave SP EEPROM Support"
depends on RAVE_SP_CORE
Expand Down
2 changes: 2 additions & 0 deletions drivers/nvmem/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o
nvmem-nintendo-otp-y := nintendo-otp.o
obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o
nvmem_qfprom-y := qfprom.o
obj-$(CONFIG_NVMEM_QCOM_SEC_QFPROM) += nvmem_sec_qfprom.o
nvmem_sec_qfprom-y := sec-qfprom.o
obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o
nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o
obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o
Expand Down
96 changes: 96 additions & 0 deletions drivers/nvmem/sec-qfprom.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/

#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/mod_devicetable.h>
#include <linux/nvmem-provider.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>

/**
* struct sec_qfprom - structure holding secure qfprom attributes
*
* @base: starting physical address for secure qfprom corrected address space.
* @dev: qfprom device structure.
*/
struct sec_qfprom {
phys_addr_t base;
struct device *dev;
};

static int sec_qfprom_reg_read(void *context, unsigned int reg, void *_val, size_t bytes)
{
struct sec_qfprom *priv = context;
unsigned int i;
u8 *val = _val;
u32 read_val;
u8 *tmp;

for (i = 0; i < bytes; i++, reg++) {
if (i == 0 || reg % 4 == 0) {
if (qcom_scm_io_readl(priv->base + (reg & ~3), &read_val)) {
dev_err(priv->dev, "Couldn't access fuse register\n");
return -EINVAL;
}
tmp = (u8 *)&read_val;
}

val[i] = tmp[reg & 3];
}

return 0;
}

static int sec_qfprom_probe(struct platform_device *pdev)
{
struct nvmem_config econfig = {
.name = "sec-qfprom",
.stride = 1,
.word_size = 1,
.id = NVMEM_DEVID_AUTO,
.reg_read = sec_qfprom_reg_read,
};
struct device *dev = &pdev->dev;
struct nvmem_device *nvmem;
struct sec_qfprom *priv;
struct resource *res;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;

priv->base = res->start;

econfig.size = resource_size(res);
econfig.dev = dev;
econfig.priv = priv;

priv->dev = dev;

nvmem = devm_nvmem_register(dev, &econfig);

return PTR_ERR_OR_ZERO(nvmem);
}

static const struct of_device_id sec_qfprom_of_match[] = {
{ .compatible = "qcom,sec-qfprom" },
{/* sentinel */},
};
MODULE_DEVICE_TABLE(of, sec_qfprom_of_match);

static struct platform_driver qfprom_driver = {
.probe = sec_qfprom_probe,
.driver = {
.name = "qcom_sec_qfprom",
.of_match_table = sec_qfprom_of_match,
},
};
module_platform_driver(qfprom_driver);
MODULE_DESCRIPTION("Qualcomm Secure QFPROM driver");
MODULE_LICENSE("GPL");

0 comments on commit c471245

Please sign in to comment.