From cbd38332c140829ab752ba4e727f98be5c257f18 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Sat, 24 Feb 2024 11:40:23 +0000 Subject: nvmem: meson-efuse: fix function pointer type mismatch clang-16 warns about casting functions to incompatible types, as is done here to call clk_disable_unprepare: drivers/nvmem/meson-efuse.c:78:12: error: cast from 'void (*)(struct clk *)' to 'void (*)(void *)' converts to incompatible function type [-Werror,-Wcast-function-type-strict] 78 | (void(*)(void *))clk_disable_unprepare, The pattern of getting, enabling and setting a disable callback for a clock can be replaced with devm_clk_get_enabled(), which also fixes this warning. Fixes: 611fbca1c861 ("nvmem: meson-efuse: add peripheral clock") Cc: Stable@vger.kernel.org Reported-by: Arnd Bergmann Signed-off-by: Jerome Brunet Reviewed-by: Martin Blumenstingl Acked-by: Arnd Bergmann Reviewed-by: Justin Stitt Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114023.85535-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/meson-efuse.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/meson-efuse.c b/drivers/nvmem/meson-efuse.c index b922df99f9bc..33678d0af2c2 100644 --- a/drivers/nvmem/meson-efuse.c +++ b/drivers/nvmem/meson-efuse.c @@ -47,7 +47,6 @@ static int meson_efuse_probe(struct platform_device *pdev) struct nvmem_config *econfig; struct clk *clk; unsigned int size; - int ret; sm_np = of_parse_phandle(pdev->dev.of_node, "secure-monitor", 0); if (!sm_np) { @@ -60,27 +59,9 @@ static int meson_efuse_probe(struct platform_device *pdev) if (!fw) return -EPROBE_DEFER; - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to get efuse gate"); - return ret; - } - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(dev, "failed to enable gate"); - return ret; - } - - ret = devm_add_action_or_reset(dev, - (void(*)(void *))clk_disable_unprepare, - clk); - if (ret) { - dev_err(dev, "failed to add disable callback"); - return ret; - } + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get efuse gate"); if (meson_sm_call(fw, SM_EFUSE_USER_MAX, &size, 0, 0, 0, 0, 0) < 0) { dev_err(dev, "failed to get max user"); -- cgit v1.2.3 From 998f0633773b3432829fe45d2cd2ffb842f3c78e Mon Sep 17 00:00:00 2001 From: William-tw Lin Date: Sat, 24 Feb 2024 11:45:07 +0000 Subject: 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 Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/mtk-efuse.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index 84f05b40a411..f5bebcecf9bd 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -68,6 +68,7 @@ static int mtk_efuse_probe(struct platform_device *pdev) 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 platform_device *pdev) 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_efuse_of_match[] = { }; 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, -- cgit v1.2.3 From 29be47fcd6a06ea2e79eeeca6e69ad1e23254a69 Mon Sep 17 00:00:00 2001 From: Praveen Teja Kundanala Date: Sat, 24 Feb 2024 11:45:11 +0000 Subject: nvmem: zynqmp_nvmem: zynqmp_nvmem_probe cleanup - Remove static nvmem_config declaration - Remove zynqmp_nvmem_data Signed-off-by: Praveen Teja Kundanala Acked-by: Kalyani Akula Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/zynqmp_nvmem.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 7f15aa89a9d0..391d8e88b270 100644 --- 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 @@ -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_match); 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 = { -- cgit v1.2.3 From 737c0c8d07b5f671c0a33cec95965fcb2d2ea893 Mon Sep 17 00:00:00 2001 From: Praveen Teja Kundanala Date: Sat, 24 Feb 2024 11:45:12 +0000 Subject: 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 Acked-by: Kalyani Akula Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-8-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/zynqmp_nvmem.c | 186 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 176 insertions(+), 10 deletions(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 391d8e88b270..8682adaacd69 100644 --- 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 #include #include #include @@ -11,24 +12,189 @@ #include #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; + + 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; -static int zynqmp_nvmem_read(void *context, unsigned int offset, - void *val, size_t bytes) + 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 platform_device *pdev) 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)); } -- cgit v1.2.3 From 76c345edef754b16cab81ad9452cc49c09e67066 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 24 Feb 2024 11:45:14 +0000 Subject: 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 Reviewed-by: AngeloGioacchino Del Regno Tested-by: "NĂ­colas F. R. A. Prado" Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/mtk-efuse.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index f5bebcecf9bd..9caf04667341 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -86,7 +86,6 @@ static int mtk_efuse_probe(struct platform_device *pdev) 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); -- cgit v1.2.3 From 8ec0faf2572216b4e25d6829cd41cf3ee2dab979 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Sat, 24 Feb 2024 11:45:15 +0000 Subject: 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 Suggested-by: Greg Kroah-Hartman Signed-off-by: "Ricardo B. Marliere" Reviewed-by: Greg Kroah-Hartman Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-11-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/layouts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c index 6a6aa58369ff..8b5e2de138eb 100644 --- a/drivers/nvmem/layouts.c +++ b/drivers/nvmem/layouts.c @@ -45,7 +45,7 @@ static void nvmem_layout_bus_remove(struct device *dev) 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, -- cgit v1.2.3 From def3173d4f17b37cecbd74d7c269a080b0b01598 Mon Sep 17 00:00:00 2001 From: Markus Schneider-Pargmann Date: Sat, 24 Feb 2024 11:45:16 +0000 Subject: 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 Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20240224114516.86365-12-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/nvmem') diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index eb357ac2e54a..2c6b99402df8 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -807,6 +807,11 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod 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); -- cgit v1.2.3