kernel: backport nvmem changes from v6.9

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
This commit is contained in:
Rafał Miłecki 2024-09-10 13:42:55 +02:00
parent a66f6c1bfb
commit 944dfb1ed6
19 changed files with 1464 additions and 3 deletions

View File

@ -0,0 +1,69 @@
From 998f0633773b3432829fe45d2cd2ffb842f3c78e Mon Sep 17 00:00:00 2001
From: William-tw Lin <william-tw.lin@mediatek.com>
Date: Sat, 24 Feb 2024 11:45:07 +0000
Subject: [PATCH] nvmem: mtk-efuse: Register MediaTek socinfo driver from efuse
The socinfo driver reads chip information from eFuses and does not need
any devicetree node. Register it from mtk-efuse.
While at it, also add the name for this driver's nvmem_config.
Signed-off-by: William-tw Lin <william-tw.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-3-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platfo
struct nvmem_config econfig = {};
struct mtk_efuse_priv *priv;
const struct mtk_efuse_pdata *pdata;
+ struct platform_device *socinfo;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -85,11 +86,20 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
+ econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
- return PTR_ERR_OR_ZERO(nvmem);
+ socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(socinfo))
+ dev_info(dev, "MediaTek SoC Information will be unavailable\n");
+
+ platform_set_drvdata(pdev, socinfo);
+ return 0;
}
static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
@@ -108,8 +118,17 @@ static const struct of_device_id mtk_efu
};
MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
+static void mtk_efuse_remove(struct platform_device *pdev)
+{
+ struct platform_device *socinfo = platform_get_drvdata(pdev);
+
+ if (!IS_ERR_OR_NULL(socinfo))
+ platform_device_unregister(socinfo);
+}
+
static struct platform_driver mtk_efuse_driver = {
.probe = mtk_efuse_probe,
+ .remove_new = mtk_efuse_remove,
.driver = {
.name = "mediatek,efuse",
.of_match_table = mtk_efuse_of_match,

View File

@ -0,0 +1,97 @@
From 29be47fcd6a06ea2e79eeeca6e69ad1e23254a69 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:11 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: zynqmp_nvmem_probe cleanup
- Remove static nvmem_config declaration
- Remove zynqmp_nvmem_data
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-7-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 37 ++++++++++++------------------------
1 file changed, 12 insertions(+), 25 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
#include <linux/module.h>
@@ -11,36 +12,25 @@
#define SILICON_REVISION_MASK 0xF
-struct zynqmp_nvmem_data {
- struct device *dev;
- struct nvmem_device *nvmem;
-};
static int zynqmp_nvmem_read(void *context, unsigned int offset,
void *val, size_t bytes)
{
+ struct device *dev = context;
int ret;
- int idcode, version;
- struct zynqmp_nvmem_data *priv = context;
+ int idcode;
+ int version;
ret = zynqmp_pm_get_chipid(&idcode, &version);
if (ret < 0)
return ret;
- dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
*(int *)val = version & SILICON_REVISION_MASK;
return 0;
}
-static struct nvmem_config econfig = {
- .name = "zynqmp-nvmem",
- .owner = THIS_MODULE,
- .word_size = 1,
- .size = 1,
- .read_only = true,
-};
-
static const struct of_device_id zynqmp_nvmem_match[] = {
{ .compatible = "xlnx,zynqmp-nvmem-fw", },
{ /* sentinel */ },
@@ -50,21 +40,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_mat
static int zynqmp_nvmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct zynqmp_nvmem_data *priv;
+ struct nvmem_config econfig = {};
- priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->dev = dev;
+ econfig.name = "zynqmp-nvmem";
+ econfig.owner = THIS_MODULE;
+ econfig.word_size = 1;
+ econfig.size = 1;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
+ econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
- econfig.priv = priv;
-
- priv->nvmem = devm_nvmem_register(dev, &econfig);
- return PTR_ERR_OR_ZERO(priv->nvmem);
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}
static struct platform_driver zynqmp_nvmem_driver = {

View File

@ -0,0 +1,243 @@
From 737c0c8d07b5f671c0a33cec95965fcb2d2ea893 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:12 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: Add support to access efuse
Add support to read/write efuse memory map of ZynqMP.
Below are the offsets of ZynqMP efuse memory map
0 - SOC version(read only)
0xC - 0xFC -ZynqMP specific purpose efuses
0x100 - 0x17F - Physical Unclonable Function(PUF)
efuses repurposed as user efuses
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-8-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 186 +++++++++++++++++++++++++++++++++--
1 file changed, 176 insertions(+), 10 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -4,6 +4,7 @@
* Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -11,24 +12,189 @@
#include <linux/firmware/xlnx-zynqmp.h>
#define SILICON_REVISION_MASK 0xF
+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
+#define WORD_INBYTES 4
+#define SOC_VER_SIZE 0x4
+#define EFUSE_MEMORY_SIZE 0x177
+#define UNUSED_SPACE 0x8
+#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
+ EFUSE_MEMORY_SIZE)
+#define SOC_VERSION_OFFSET 0x0
+#define EFUSE_START_OFFSET 0xC
+#define EFUSE_END_OFFSET 0xFC
+#define EFUSE_PUF_START_OFFSET 0x100
+#define EFUSE_PUF_MID_OFFSET 0x140
+#define EFUSE_PUF_END_OFFSET 0x17F
+#define EFUSE_NOT_ENABLED 29
+/*
+ * efuse access type
+ */
+enum efuse_access {
+ EFUSE_READ = 0,
+ EFUSE_WRITE
+};
+
+/**
+ * struct xilinx_efuse - the basic structure
+ * @src: address of the buffer to store the data to be write/read
+ * @size: read/write word count
+ * @offset: read/write offset
+ * @flag: 0 - represents efuse read and 1- represents efuse write
+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
+ * 1 - represents puf user fuse row number.
+ *
+ * this structure stores all the required details to
+ * read/write efuse memory.
+ */
+struct xilinx_efuse {
+ u64 src;
+ u32 size;
+ u32 offset;
+ enum efuse_access flag;
+ u32 pufuserfuse;
+};
+
+static int zynqmp_efuse_access(void *context, unsigned int offset,
+ void *val, size_t bytes, enum efuse_access flag,
+ unsigned int pufflag)
+{
+ struct device *dev = context;
+ struct xilinx_efuse *efuse;
+ dma_addr_t dma_addr;
+ dma_addr_t dma_buf;
+ size_t words = bytes / WORD_INBYTES;
+ int ret;
+ int value;
+ char *data;
-static int zynqmp_nvmem_read(void *context, unsigned int offset,
- void *val, size_t bytes)
+ if (bytes % WORD_INBYTES != 0) {
+ dev_err(dev, "Bytes requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 0 && offset % WORD_INBYTES) {
+ dev_err(dev, "Offset requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 1 && flag == EFUSE_WRITE) {
+ memcpy(&value, val, bytes);
+ if ((offset == EFUSE_PUF_START_OFFSET ||
+ offset == EFUSE_PUF_MID_OFFSET) &&
+ value & P_USER_0_64_UPPER_MASK) {
+ dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (offset == EFUSE_PUF_END_OFFSET &&
+ (value & P_USER_127_LOWER_4_BIT_MASK)) {
+ dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
+ &dma_addr, GFP_KERNEL);
+ if (!efuse)
+ return -ENOMEM;
+
+ data = dma_alloc_coherent(dev, sizeof(bytes),
+ &dma_buf, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto efuse_data_fail;
+ }
+
+ if (flag == EFUSE_WRITE) {
+ memcpy(data, val, bytes);
+ efuse->flag = EFUSE_WRITE;
+ } else {
+ efuse->flag = EFUSE_READ;
+ }
+
+ efuse->src = dma_buf;
+ efuse->size = words;
+ efuse->offset = offset;
+ efuse->pufuserfuse = pufflag;
+
+ zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+ if (ret != 0) {
+ if (ret == EFUSE_NOT_ENABLED) {
+ dev_err(dev, "efuse access is not enabled\n");
+ ret = -EOPNOTSUPP;
+ } else {
+ dev_err(dev, "Error in efuse read %x\n", ret);
+ ret = -EPERM;
+ }
+ goto efuse_access_err;
+ }
+
+ if (flag == EFUSE_READ)
+ memcpy(val, data, bytes);
+efuse_access_err:
+ dma_free_coherent(dev, sizeof(bytes),
+ data, dma_buf);
+efuse_data_fail:
+ dma_free_coherent(dev, sizeof(struct xilinx_efuse),
+ efuse, dma_addr);
+
+ return ret;
+}
+
+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
{
struct device *dev = context;
int ret;
+ int pufflag = 0;
int idcode;
int version;
- ret = zynqmp_pm_get_chipid(&idcode, &version);
- if (ret < 0)
- return ret;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
+
+ switch (offset) {
+ /* Soc version offset is zero */
+ case SOC_VERSION_OFFSET:
+ if (bytes != SOC_VER_SIZE)
+ return -EOPNOTSUPP;
+
+ ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
+ *(int *)val = version & SILICON_REVISION_MASK;
+ break;
+ /* Efuse offset starts from 0xc */
+ case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
+ case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
+ ret = zynqmp_efuse_access(context, offset, val,
+ bytes, EFUSE_READ, pufflag);
+ break;
+ default:
+ *(u32 *)val = 0xDEADBEEF;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int zynqmp_nvmem_write(void *context,
+ unsigned int offset, void *val, size_t bytes)
+{
+ int pufflag = 0;
+
+ if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
+ return -EOPNOTSUPP;
- dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
- *(int *)val = version & SILICON_REVISION_MASK;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
- return 0;
+ return zynqmp_efuse_access(context, offset,
+ val, bytes, EFUSE_WRITE, pufflag);
}
static const struct of_device_id zynqmp_nvmem_match[] = {
@@ -45,11 +211,11 @@ static int zynqmp_nvmem_probe(struct pla
econfig.name = "zynqmp-nvmem";
econfig.owner = THIS_MODULE;
econfig.word_size = 1;
- econfig.size = 1;
+ econfig.size = ZYNQMP_NVMEM_SIZE;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
- econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
+ econfig.reg_write = zynqmp_nvmem_write;
return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}

View File

@ -0,0 +1,35 @@
From 76c345edef754b16cab81ad9452cc49c09e67066 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wenst@chromium.org>
Date: Sat, 24 Feb 2024 11:45:14 +0000
Subject: [PATCH] nvmem: mtk-efuse: Drop NVMEM device name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The MT8183 has not one but two efuse devices. The static name and ID
causes the second efuse device to fail to probe, due to duplicate sysfs
entries.
With the rework of the mtk-socinfo driver, lookup by name is no longer
necessary. The custom name can simply be dropped.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: "Nícolas F. R. A. Prado" <nfraprado@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-10-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 1 -
1 file changed, 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -86,7 +86,6 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
- econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);

View File

@ -0,0 +1,32 @@
From def3173d4f17b37cecbd74d7c269a080b0b01598 Mon Sep 17 00:00:00 2001
From: Markus Schneider-Pargmann <msp@baylibre.com>
Date: Sat, 24 Feb 2024 11:45:16 +0000
Subject: [PATCH] nvmem: core: Print error on wrong bits DT property
The algorithms in nvmem core are built with the constraint that
bit_offset < 8. If bit_offset is greater the results are wrong. Print an
error if the devicetree 'bits' property is outside of the valid range
and abort parsing.
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-12-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/core.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -807,6 +807,11 @@ static int nvmem_add_cells_from_dt(struc
if (addr && len == (2 * sizeof(u32))) {
info.bit_offset = be32_to_cpup(addr++);
info.nbits = be32_to_cpup(addr);
+ if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
}
info.np = of_node_get(child);

View File

@ -0,0 +1,69 @@
From 998f0633773b3432829fe45d2cd2ffb842f3c78e Mon Sep 17 00:00:00 2001
From: William-tw Lin <william-tw.lin@mediatek.com>
Date: Sat, 24 Feb 2024 11:45:07 +0000
Subject: [PATCH] nvmem: mtk-efuse: Register MediaTek socinfo driver from efuse
The socinfo driver reads chip information from eFuses and does not need
any devicetree node. Register it from mtk-efuse.
While at it, also add the name for this driver's nvmem_config.
Signed-off-by: William-tw Lin <william-tw.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-3-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platfo
struct nvmem_config econfig = {};
struct mtk_efuse_priv *priv;
const struct mtk_efuse_pdata *pdata;
+ struct platform_device *socinfo;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -85,11 +86,20 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
+ econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
- return PTR_ERR_OR_ZERO(nvmem);
+ socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(socinfo))
+ dev_info(dev, "MediaTek SoC Information will be unavailable\n");
+
+ platform_set_drvdata(pdev, socinfo);
+ return 0;
}
static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
@@ -108,8 +118,17 @@ static const struct of_device_id mtk_efu
};
MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
+static void mtk_efuse_remove(struct platform_device *pdev)
+{
+ struct platform_device *socinfo = platform_get_drvdata(pdev);
+
+ if (!IS_ERR_OR_NULL(socinfo))
+ platform_device_unregister(socinfo);
+}
+
static struct platform_driver mtk_efuse_driver = {
.probe = mtk_efuse_probe,
+ .remove_new = mtk_efuse_remove,
.driver = {
.name = "mediatek,efuse",
.of_match_table = mtk_efuse_of_match,

View File

@ -0,0 +1,97 @@
From 29be47fcd6a06ea2e79eeeca6e69ad1e23254a69 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:11 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: zynqmp_nvmem_probe cleanup
- Remove static nvmem_config declaration
- Remove zynqmp_nvmem_data
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-7-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 37 ++++++++++++------------------------
1 file changed, 12 insertions(+), 25 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
#include <linux/module.h>
@@ -11,36 +12,25 @@
#define SILICON_REVISION_MASK 0xF
-struct zynqmp_nvmem_data {
- struct device *dev;
- struct nvmem_device *nvmem;
-};
static int zynqmp_nvmem_read(void *context, unsigned int offset,
void *val, size_t bytes)
{
+ struct device *dev = context;
int ret;
- int idcode, version;
- struct zynqmp_nvmem_data *priv = context;
+ int idcode;
+ int version;
ret = zynqmp_pm_get_chipid(&idcode, &version);
if (ret < 0)
return ret;
- dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
*(int *)val = version & SILICON_REVISION_MASK;
return 0;
}
-static struct nvmem_config econfig = {
- .name = "zynqmp-nvmem",
- .owner = THIS_MODULE,
- .word_size = 1,
- .size = 1,
- .read_only = true,
-};
-
static const struct of_device_id zynqmp_nvmem_match[] = {
{ .compatible = "xlnx,zynqmp-nvmem-fw", },
{ /* sentinel */ },
@@ -50,21 +40,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_mat
static int zynqmp_nvmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct zynqmp_nvmem_data *priv;
+ struct nvmem_config econfig = {};
- priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->dev = dev;
+ econfig.name = "zynqmp-nvmem";
+ econfig.owner = THIS_MODULE;
+ econfig.word_size = 1;
+ econfig.size = 1;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
+ econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
- econfig.priv = priv;
-
- priv->nvmem = devm_nvmem_register(dev, &econfig);
- return PTR_ERR_OR_ZERO(priv->nvmem);
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}
static struct platform_driver zynqmp_nvmem_driver = {

View File

@ -0,0 +1,243 @@
From 737c0c8d07b5f671c0a33cec95965fcb2d2ea893 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:12 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: Add support to access efuse
Add support to read/write efuse memory map of ZynqMP.
Below are the offsets of ZynqMP efuse memory map
0 - SOC version(read only)
0xC - 0xFC -ZynqMP specific purpose efuses
0x100 - 0x17F - Physical Unclonable Function(PUF)
efuses repurposed as user efuses
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-8-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 186 +++++++++++++++++++++++++++++++++--
1 file changed, 176 insertions(+), 10 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -4,6 +4,7 @@
* Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -11,24 +12,189 @@
#include <linux/firmware/xlnx-zynqmp.h>
#define SILICON_REVISION_MASK 0xF
+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
+#define WORD_INBYTES 4
+#define SOC_VER_SIZE 0x4
+#define EFUSE_MEMORY_SIZE 0x177
+#define UNUSED_SPACE 0x8
+#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
+ EFUSE_MEMORY_SIZE)
+#define SOC_VERSION_OFFSET 0x0
+#define EFUSE_START_OFFSET 0xC
+#define EFUSE_END_OFFSET 0xFC
+#define EFUSE_PUF_START_OFFSET 0x100
+#define EFUSE_PUF_MID_OFFSET 0x140
+#define EFUSE_PUF_END_OFFSET 0x17F
+#define EFUSE_NOT_ENABLED 29
+/*
+ * efuse access type
+ */
+enum efuse_access {
+ EFUSE_READ = 0,
+ EFUSE_WRITE
+};
+
+/**
+ * struct xilinx_efuse - the basic structure
+ * @src: address of the buffer to store the data to be write/read
+ * @size: read/write word count
+ * @offset: read/write offset
+ * @flag: 0 - represents efuse read and 1- represents efuse write
+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
+ * 1 - represents puf user fuse row number.
+ *
+ * this structure stores all the required details to
+ * read/write efuse memory.
+ */
+struct xilinx_efuse {
+ u64 src;
+ u32 size;
+ u32 offset;
+ enum efuse_access flag;
+ u32 pufuserfuse;
+};
+
+static int zynqmp_efuse_access(void *context, unsigned int offset,
+ void *val, size_t bytes, enum efuse_access flag,
+ unsigned int pufflag)
+{
+ struct device *dev = context;
+ struct xilinx_efuse *efuse;
+ dma_addr_t dma_addr;
+ dma_addr_t dma_buf;
+ size_t words = bytes / WORD_INBYTES;
+ int ret;
+ int value;
+ char *data;
-static int zynqmp_nvmem_read(void *context, unsigned int offset,
- void *val, size_t bytes)
+ if (bytes % WORD_INBYTES != 0) {
+ dev_err(dev, "Bytes requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 0 && offset % WORD_INBYTES) {
+ dev_err(dev, "Offset requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 1 && flag == EFUSE_WRITE) {
+ memcpy(&value, val, bytes);
+ if ((offset == EFUSE_PUF_START_OFFSET ||
+ offset == EFUSE_PUF_MID_OFFSET) &&
+ value & P_USER_0_64_UPPER_MASK) {
+ dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (offset == EFUSE_PUF_END_OFFSET &&
+ (value & P_USER_127_LOWER_4_BIT_MASK)) {
+ dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
+ &dma_addr, GFP_KERNEL);
+ if (!efuse)
+ return -ENOMEM;
+
+ data = dma_alloc_coherent(dev, sizeof(bytes),
+ &dma_buf, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto efuse_data_fail;
+ }
+
+ if (flag == EFUSE_WRITE) {
+ memcpy(data, val, bytes);
+ efuse->flag = EFUSE_WRITE;
+ } else {
+ efuse->flag = EFUSE_READ;
+ }
+
+ efuse->src = dma_buf;
+ efuse->size = words;
+ efuse->offset = offset;
+ efuse->pufuserfuse = pufflag;
+
+ zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+ if (ret != 0) {
+ if (ret == EFUSE_NOT_ENABLED) {
+ dev_err(dev, "efuse access is not enabled\n");
+ ret = -EOPNOTSUPP;
+ } else {
+ dev_err(dev, "Error in efuse read %x\n", ret);
+ ret = -EPERM;
+ }
+ goto efuse_access_err;
+ }
+
+ if (flag == EFUSE_READ)
+ memcpy(val, data, bytes);
+efuse_access_err:
+ dma_free_coherent(dev, sizeof(bytes),
+ data, dma_buf);
+efuse_data_fail:
+ dma_free_coherent(dev, sizeof(struct xilinx_efuse),
+ efuse, dma_addr);
+
+ return ret;
+}
+
+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
{
struct device *dev = context;
int ret;
+ int pufflag = 0;
int idcode;
int version;
- ret = zynqmp_pm_get_chipid(&idcode, &version);
- if (ret < 0)
- return ret;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
+
+ switch (offset) {
+ /* Soc version offset is zero */
+ case SOC_VERSION_OFFSET:
+ if (bytes != SOC_VER_SIZE)
+ return -EOPNOTSUPP;
+
+ ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
+ *(int *)val = version & SILICON_REVISION_MASK;
+ break;
+ /* Efuse offset starts from 0xc */
+ case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
+ case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
+ ret = zynqmp_efuse_access(context, offset, val,
+ bytes, EFUSE_READ, pufflag);
+ break;
+ default:
+ *(u32 *)val = 0xDEADBEEF;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int zynqmp_nvmem_write(void *context,
+ unsigned int offset, void *val, size_t bytes)
+{
+ int pufflag = 0;
+
+ if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
+ return -EOPNOTSUPP;
- dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
- *(int *)val = version & SILICON_REVISION_MASK;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
- return 0;
+ return zynqmp_efuse_access(context, offset,
+ val, bytes, EFUSE_WRITE, pufflag);
}
static const struct of_device_id zynqmp_nvmem_match[] = {
@@ -45,11 +211,11 @@ static int zynqmp_nvmem_probe(struct pla
econfig.name = "zynqmp-nvmem";
econfig.owner = THIS_MODULE;
econfig.word_size = 1;
- econfig.size = 1;
+ econfig.size = ZYNQMP_NVMEM_SIZE;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
- econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
+ econfig.reg_write = zynqmp_nvmem_write;
return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}

View File

@ -0,0 +1,35 @@
From 76c345edef754b16cab81ad9452cc49c09e67066 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wenst@chromium.org>
Date: Sat, 24 Feb 2024 11:45:14 +0000
Subject: [PATCH] nvmem: mtk-efuse: Drop NVMEM device name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The MT8183 has not one but two efuse devices. The static name and ID
causes the second efuse device to fail to probe, due to duplicate sysfs
entries.
With the rework of the mtk-socinfo driver, lookup by name is no longer
necessary. The custom name can simply be dropped.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: "Nícolas F. R. A. Prado" <nfraprado@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-10-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 1 -
1 file changed, 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -86,7 +86,6 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
- econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);

View File

@ -0,0 +1,32 @@
From def3173d4f17b37cecbd74d7c269a080b0b01598 Mon Sep 17 00:00:00 2001
From: Markus Schneider-Pargmann <msp@baylibre.com>
Date: Sat, 24 Feb 2024 11:45:16 +0000
Subject: [PATCH] nvmem: core: Print error on wrong bits DT property
The algorithms in nvmem core are built with the constraint that
bit_offset < 8. If bit_offset is greater the results are wrong. Print an
error if the devicetree 'bits' property is outside of the valid range
and abort parsing.
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-12-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/core.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -806,6 +806,11 @@ static int nvmem_add_cells_from_dt(struc
if (addr && len == (2 * sizeof(u32))) {
info.bit_offset = be32_to_cpup(addr++);
info.nbits = be32_to_cpup(addr);
+ if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
}
info.np = of_node_get(child);

View File

@ -0,0 +1,69 @@
From 998f0633773b3432829fe45d2cd2ffb842f3c78e Mon Sep 17 00:00:00 2001
From: William-tw Lin <william-tw.lin@mediatek.com>
Date: Sat, 24 Feb 2024 11:45:07 +0000
Subject: [PATCH] nvmem: mtk-efuse: Register MediaTek socinfo driver from efuse
The socinfo driver reads chip information from eFuses and does not need
any devicetree node. Register it from mtk-efuse.
While at it, also add the name for this driver's nvmem_config.
Signed-off-by: William-tw Lin <william-tw.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-3-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platfo
struct nvmem_config econfig = {};
struct mtk_efuse_priv *priv;
const struct mtk_efuse_pdata *pdata;
+ struct platform_device *socinfo;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -85,11 +86,20 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
+ econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
- return PTR_ERR_OR_ZERO(nvmem);
+ socinfo = platform_device_register_data(&pdev->dev, "mtk-socinfo",
+ PLATFORM_DEVID_AUTO, NULL, 0);
+ if (IS_ERR(socinfo))
+ dev_info(dev, "MediaTek SoC Information will be unavailable\n");
+
+ platform_set_drvdata(pdev, socinfo);
+ return 0;
}
static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = {
@@ -108,8 +118,17 @@ static const struct of_device_id mtk_efu
};
MODULE_DEVICE_TABLE(of, mtk_efuse_of_match);
+static void mtk_efuse_remove(struct platform_device *pdev)
+{
+ struct platform_device *socinfo = platform_get_drvdata(pdev);
+
+ if (!IS_ERR_OR_NULL(socinfo))
+ platform_device_unregister(socinfo);
+}
+
static struct platform_driver mtk_efuse_driver = {
.probe = mtk_efuse_probe,
+ .remove_new = mtk_efuse_remove,
.driver = {
.name = "mediatek,efuse",
.of_match_table = mtk_efuse_of_match,

View File

@ -0,0 +1,97 @@
From 29be47fcd6a06ea2e79eeeca6e69ad1e23254a69 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:11 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: zynqmp_nvmem_probe cleanup
- Remove static nvmem_config declaration
- Remove zynqmp_nvmem_data
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-7-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 37 ++++++++++++------------------------
1 file changed, 12 insertions(+), 25 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
#include <linux/module.h>
@@ -11,36 +12,25 @@
#define SILICON_REVISION_MASK 0xF
-struct zynqmp_nvmem_data {
- struct device *dev;
- struct nvmem_device *nvmem;
-};
static int zynqmp_nvmem_read(void *context, unsigned int offset,
void *val, size_t bytes)
{
+ struct device *dev = context;
int ret;
- int idcode, version;
- struct zynqmp_nvmem_data *priv = context;
+ int idcode;
+ int version;
ret = zynqmp_pm_get_chipid(&idcode, &version);
if (ret < 0)
return ret;
- dev_dbg(priv->dev, "Read chipid val %x %x\n", idcode, version);
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
*(int *)val = version & SILICON_REVISION_MASK;
return 0;
}
-static struct nvmem_config econfig = {
- .name = "zynqmp-nvmem",
- .owner = THIS_MODULE,
- .word_size = 1,
- .size = 1,
- .read_only = true,
-};
-
static const struct of_device_id zynqmp_nvmem_match[] = {
{ .compatible = "xlnx,zynqmp-nvmem-fw", },
{ /* sentinel */ },
@@ -50,21 +40,18 @@ MODULE_DEVICE_TABLE(of, zynqmp_nvmem_mat
static int zynqmp_nvmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct zynqmp_nvmem_data *priv;
+ struct nvmem_config econfig = {};
- priv = devm_kzalloc(dev, sizeof(struct zynqmp_nvmem_data), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->dev = dev;
+ econfig.name = "zynqmp-nvmem";
+ econfig.owner = THIS_MODULE;
+ econfig.word_size = 1;
+ econfig.size = 1;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
+ econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
- econfig.priv = priv;
-
- priv->nvmem = devm_nvmem_register(dev, &econfig);
- return PTR_ERR_OR_ZERO(priv->nvmem);
+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}
static struct platform_driver zynqmp_nvmem_driver = {

View File

@ -0,0 +1,243 @@
From 737c0c8d07b5f671c0a33cec95965fcb2d2ea893 Mon Sep 17 00:00:00 2001
From: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Date: Sat, 24 Feb 2024 11:45:12 +0000
Subject: [PATCH] nvmem: zynqmp_nvmem: Add support to access efuse
Add support to read/write efuse memory map of ZynqMP.
Below are the offsets of ZynqMP efuse memory map
0 - SOC version(read only)
0xC - 0xFC -ZynqMP specific purpose efuses
0x100 - 0x17F - Physical Unclonable Function(PUF)
efuses repurposed as user efuses
Signed-off-by: Praveen Teja Kundanala <praveen.teja.kundanala@amd.com>
Acked-by: Kalyani Akula <Kalyani.akula@amd.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-8-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/zynqmp_nvmem.c | 186 +++++++++++++++++++++++++++++++++--
1 file changed, 176 insertions(+), 10 deletions(-)
--- a/drivers/nvmem/zynqmp_nvmem.c
+++ b/drivers/nvmem/zynqmp_nvmem.c
@@ -4,6 +4,7 @@
* Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
*/
+#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/of.h>
@@ -11,24 +12,189 @@
#include <linux/firmware/xlnx-zynqmp.h>
#define SILICON_REVISION_MASK 0xF
+#define P_USER_0_64_UPPER_MASK GENMASK(31, 16)
+#define P_USER_127_LOWER_4_BIT_MASK GENMASK(3, 0)
+#define WORD_INBYTES 4
+#define SOC_VER_SIZE 0x4
+#define EFUSE_MEMORY_SIZE 0x177
+#define UNUSED_SPACE 0x8
+#define ZYNQMP_NVMEM_SIZE (SOC_VER_SIZE + UNUSED_SPACE + \
+ EFUSE_MEMORY_SIZE)
+#define SOC_VERSION_OFFSET 0x0
+#define EFUSE_START_OFFSET 0xC
+#define EFUSE_END_OFFSET 0xFC
+#define EFUSE_PUF_START_OFFSET 0x100
+#define EFUSE_PUF_MID_OFFSET 0x140
+#define EFUSE_PUF_END_OFFSET 0x17F
+#define EFUSE_NOT_ENABLED 29
+/*
+ * efuse access type
+ */
+enum efuse_access {
+ EFUSE_READ = 0,
+ EFUSE_WRITE
+};
+
+/**
+ * struct xilinx_efuse - the basic structure
+ * @src: address of the buffer to store the data to be write/read
+ * @size: read/write word count
+ * @offset: read/write offset
+ * @flag: 0 - represents efuse read and 1- represents efuse write
+ * @pufuserfuse:0 - represents non-puf efuses, offset is used for read/write
+ * 1 - represents puf user fuse row number.
+ *
+ * this structure stores all the required details to
+ * read/write efuse memory.
+ */
+struct xilinx_efuse {
+ u64 src;
+ u32 size;
+ u32 offset;
+ enum efuse_access flag;
+ u32 pufuserfuse;
+};
+
+static int zynqmp_efuse_access(void *context, unsigned int offset,
+ void *val, size_t bytes, enum efuse_access flag,
+ unsigned int pufflag)
+{
+ struct device *dev = context;
+ struct xilinx_efuse *efuse;
+ dma_addr_t dma_addr;
+ dma_addr_t dma_buf;
+ size_t words = bytes / WORD_INBYTES;
+ int ret;
+ int value;
+ char *data;
-static int zynqmp_nvmem_read(void *context, unsigned int offset,
- void *val, size_t bytes)
+ if (bytes % WORD_INBYTES != 0) {
+ dev_err(dev, "Bytes requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 0 && offset % WORD_INBYTES) {
+ dev_err(dev, "Offset requested should be word aligned\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pufflag == 1 && flag == EFUSE_WRITE) {
+ memcpy(&value, val, bytes);
+ if ((offset == EFUSE_PUF_START_OFFSET ||
+ offset == EFUSE_PUF_MID_OFFSET) &&
+ value & P_USER_0_64_UPPER_MASK) {
+ dev_err(dev, "Only lower 4 bytes are allowed to be programmed in P_USER_0 & P_USER_64\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (offset == EFUSE_PUF_END_OFFSET &&
+ (value & P_USER_127_LOWER_4_BIT_MASK)) {
+ dev_err(dev, "Only MSB 28 bits are allowed to be programmed for P_USER_127\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efuse = dma_alloc_coherent(dev, sizeof(struct xilinx_efuse),
+ &dma_addr, GFP_KERNEL);
+ if (!efuse)
+ return -ENOMEM;
+
+ data = dma_alloc_coherent(dev, sizeof(bytes),
+ &dma_buf, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto efuse_data_fail;
+ }
+
+ if (flag == EFUSE_WRITE) {
+ memcpy(data, val, bytes);
+ efuse->flag = EFUSE_WRITE;
+ } else {
+ efuse->flag = EFUSE_READ;
+ }
+
+ efuse->src = dma_buf;
+ efuse->size = words;
+ efuse->offset = offset;
+ efuse->pufuserfuse = pufflag;
+
+ zynqmp_pm_efuse_access(dma_addr, (u32 *)&ret);
+ if (ret != 0) {
+ if (ret == EFUSE_NOT_ENABLED) {
+ dev_err(dev, "efuse access is not enabled\n");
+ ret = -EOPNOTSUPP;
+ } else {
+ dev_err(dev, "Error in efuse read %x\n", ret);
+ ret = -EPERM;
+ }
+ goto efuse_access_err;
+ }
+
+ if (flag == EFUSE_READ)
+ memcpy(val, data, bytes);
+efuse_access_err:
+ dma_free_coherent(dev, sizeof(bytes),
+ data, dma_buf);
+efuse_data_fail:
+ dma_free_coherent(dev, sizeof(struct xilinx_efuse),
+ efuse, dma_addr);
+
+ return ret;
+}
+
+static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes)
{
struct device *dev = context;
int ret;
+ int pufflag = 0;
int idcode;
int version;
- ret = zynqmp_pm_get_chipid(&idcode, &version);
- if (ret < 0)
- return ret;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
+
+ switch (offset) {
+ /* Soc version offset is zero */
+ case SOC_VERSION_OFFSET:
+ if (bytes != SOC_VER_SIZE)
+ return -EOPNOTSUPP;
+
+ ret = zynqmp_pm_get_chipid((u32 *)&idcode, (u32 *)&version);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
+ *(int *)val = version & SILICON_REVISION_MASK;
+ break;
+ /* Efuse offset starts from 0xc */
+ case EFUSE_START_OFFSET ... EFUSE_END_OFFSET:
+ case EFUSE_PUF_START_OFFSET ... EFUSE_PUF_END_OFFSET:
+ ret = zynqmp_efuse_access(context, offset, val,
+ bytes, EFUSE_READ, pufflag);
+ break;
+ default:
+ *(u32 *)val = 0xDEADBEEF;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int zynqmp_nvmem_write(void *context,
+ unsigned int offset, void *val, size_t bytes)
+{
+ int pufflag = 0;
+
+ if (offset < EFUSE_START_OFFSET || offset > EFUSE_PUF_END_OFFSET)
+ return -EOPNOTSUPP;
- dev_dbg(dev, "Read chipid val %x %x\n", idcode, version);
- *(int *)val = version & SILICON_REVISION_MASK;
+ if (offset >= EFUSE_PUF_START_OFFSET && offset <= EFUSE_PUF_END_OFFSET)
+ pufflag = 1;
- return 0;
+ return zynqmp_efuse_access(context, offset,
+ val, bytes, EFUSE_WRITE, pufflag);
}
static const struct of_device_id zynqmp_nvmem_match[] = {
@@ -45,11 +211,11 @@ static int zynqmp_nvmem_probe(struct pla
econfig.name = "zynqmp-nvmem";
econfig.owner = THIS_MODULE;
econfig.word_size = 1;
- econfig.size = 1;
+ econfig.size = ZYNQMP_NVMEM_SIZE;
econfig.dev = dev;
econfig.add_legacy_fixed_of_cells = true;
- econfig.read_only = true;
econfig.reg_read = zynqmp_nvmem_read;
+ econfig.reg_write = zynqmp_nvmem_write;
return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &econfig));
}

View File

@ -0,0 +1,35 @@
From 76c345edef754b16cab81ad9452cc49c09e67066 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wenst@chromium.org>
Date: Sat, 24 Feb 2024 11:45:14 +0000
Subject: [PATCH] nvmem: mtk-efuse: Drop NVMEM device name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The MT8183 has not one but two efuse devices. The static name and ID
causes the second efuse device to fail to probe, due to duplicate sysfs
entries.
With the rework of the mtk-socinfo driver, lookup by name is no longer
necessary. The custom name can simply be dropped.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: "Nícolas F. R. A. Prado" <nfraprado@collabora.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-10-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/mtk-efuse.c | 1 -
1 file changed, 1 deletion(-)
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -86,7 +86,6 @@ static int mtk_efuse_probe(struct platfo
econfig.size = resource_size(res);
econfig.priv = priv;
econfig.dev = dev;
- econfig.name = "mtk-efuse";
if (pdata->uses_post_processing)
econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);

View File

@ -0,0 +1,33 @@
From 8ec0faf2572216b4e25d6829cd41cf3ee2dab979 Mon Sep 17 00:00:00 2001
From: "Ricardo B. Marliere" <ricardo@marliere.net>
Date: Sat, 24 Feb 2024 11:45:15 +0000
Subject: [PATCH] nvmem: core: make nvmem_layout_bus_type const
Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type
a const *"), the driver core can properly handle constant struct
bus_type, move the nvmem_layout_bus_type variable to be a constant
structure as well, placing it into read-only memory which can not be
modified at runtime.
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: "Ricardo B. Marliere" <ricardo@marliere.net>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-11-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/layouts.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/nvmem/layouts.c
+++ b/drivers/nvmem/layouts.c
@@ -45,7 +45,7 @@ static void nvmem_layout_bus_remove(stru
return drv->remove(layout);
}
-static struct bus_type nvmem_layout_bus_type = {
+static const struct bus_type nvmem_layout_bus_type = {
.name = "nvmem-layout",
.match = nvmem_layout_bus_match,
.probe = nvmem_layout_bus_probe,

View File

@ -0,0 +1,32 @@
From def3173d4f17b37cecbd74d7c269a080b0b01598 Mon Sep 17 00:00:00 2001
From: Markus Schneider-Pargmann <msp@baylibre.com>
Date: Sat, 24 Feb 2024 11:45:16 +0000
Subject: [PATCH] nvmem: core: Print error on wrong bits DT property
The algorithms in nvmem core are built with the constraint that
bit_offset < 8. If bit_offset is greater the results are wrong. Print an
error if the devicetree 'bits' property is outside of the valid range
and abort parsing.
Signed-off-by: Markus Schneider-Pargmann <msp@baylibre.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/20240224114516.86365-12-srinivas.kandagatla@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/nvmem/core.c | 5 +++++
1 file changed, 5 insertions(+)
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -805,6 +805,11 @@ static int nvmem_add_cells_from_dt(struc
if (addr && len == (2 * sizeof(u32))) {
info.bit_offset = be32_to_cpup(addr++);
info.nbits = be32_to_cpup(addr);
+ if (info.bit_offset >= BITS_PER_BYTE || info.nbits < 1) {
+ dev_err(dev, "nvmem: invalid bits on %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
}
info.np = of_node_get(child);

View File

@ -96,7 +96,7 @@ string.
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
struct device *dev = &nvmem->dev;
@@ -814,6 +873,25 @@ static int nvmem_add_cells_from_dt(struc
@@ -819,6 +878,25 @@ static int nvmem_add_cells_from_dt(struc
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);

View File

@ -96,7 +96,7 @@ string.
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
struct device *dev = &nvmem->dev;
@@ -813,6 +872,25 @@ static int nvmem_add_cells_from_dt(struc
@@ -818,6 +877,25 @@ static int nvmem_add_cells_from_dt(struc
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);

View File

@ -96,7 +96,7 @@ string.
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
struct device *dev = &nvmem->dev;
@@ -812,6 +871,25 @@ static int nvmem_add_cells_from_dt(struc
@@ -817,6 +876,25 @@ static int nvmem_add_cells_from_dt(struc
if (nvmem->fixup_dt_cell_info)
nvmem->fixup_dt_cell_info(nvmem, &info);