diff options
Diffstat (limited to 'target/linux/generic/backport-5.10/810-v6.0-0001-nvmem-microchip-otpc-add-support.patch')
-rw-r--r-- | target/linux/generic/backport-5.10/810-v6.0-0001-nvmem-microchip-otpc-add-support.patch | 389 |
1 files changed, 0 insertions, 389 deletions
diff --git a/target/linux/generic/backport-5.10/810-v6.0-0001-nvmem-microchip-otpc-add-support.patch b/target/linux/generic/backport-5.10/810-v6.0-0001-nvmem-microchip-otpc-add-support.patch deleted file mode 100644 index eb99ec190c..0000000000 --- a/target/linux/generic/backport-5.10/810-v6.0-0001-nvmem-microchip-otpc-add-support.patch +++ /dev/null @@ -1,389 +0,0 @@ -From 98830350d3fc824c1ff5c338140fe20f041a5916 Mon Sep 17 00:00:00 2001 -From: Claudiu Beznea <claudiu.beznea@microchip.com> -Date: Wed, 6 Jul 2022 11:06:22 +0100 -Subject: [PATCH] nvmem: microchip-otpc: add support - -Add support for Microchip OTP controller available on SAMA7G5. The OTPC -controls the access to a non-volatile memory. The memory behind OTPC is -organized into packets, packets are composed by a fixed length header -(4 bytes long) and a variable length payload (payload length is available -in the header). When software request the data at an offset in memory -the OTPC will return (via header + data registers) the whole packet that -has a word at that offset. For the OTP memory layout like below: - -offset OTP Memory layout - - . . - . ... . - . . -0x0E +-----------+ <--- packet X - | header X | -0x12 +-----------+ - | payload X | -0x16 | | - | | -0x1A | | - +-----------+ - . . - . ... . - . . - -if user requests data at address 0x16 the data started at 0x0E will be -returned by controller. User will be able to fetch the whole packet -starting at 0x0E (or parts of the packet) via proper registers. The same -packet will be returned if software request the data at offset 0x0E or -0x12 or 0x1A. - -The OTP will be populated by Microchip with at least 2 packets first one -being boot configuration packet and the 2nd one being temperature -calibration packet. The packet order will be preserved b/w different chip -revisions but the packet sizes may change. - -For the above reasons and to keep the same software able to work on all -chip variants the read function of the driver is working with a packet -id instead of an offset in OTP memory. - -Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com> -Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> -Link: https://lore.kernel.org/r/20220706100627.6534-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - MAINTAINERS | 8 + - drivers/nvmem/Kconfig | 7 + - drivers/nvmem/Makefile | 2 + - drivers/nvmem/microchip-otpc.c | 288 +++++++++++++++++++++++++++++++++ - 4 files changed, 305 insertions(+) - create mode 100644 drivers/nvmem/microchip-otpc.c - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -11565,6 +11565,14 @@ S: Supported - F: Documentation/devicetree/bindings/mtd/atmel-nand.txt - F: drivers/mtd/nand/raw/atmel/* - -+MICROCHIP OTPC DRIVER -+M: Claudiu Beznea <claudiu.beznea@microchip.com> -+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -+S: Supported -+F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml -+F: drivers/nvmem/microchip-otpc.c -+F: dt-bindings/nvmem/microchip,sama7g5-otpc.h -+ - MICROCHIP PWM DRIVER - M: Claudiu Beznea <claudiu.beznea@microchip.com> - L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -107,6 +107,13 @@ config MTK_EFUSE - This driver can also be built as a module. If so, the module - will be called efuse-mtk. - -+config MICROCHIP_OTPC -+ tristate "Microchip OTPC support" -+ depends on ARCH_AT91 || COMPILE_TEST -+ help -+ This driver enable the OTP controller available on Microchip SAMA7G5 -+ SoCs. It controlls the access to the OTP memory connected to it. -+ - config NVMEM_NINTENDO_OTP - tristate "Nintendo Wii and Wii U OTP Support" - depends on WII || COMPILE_TEST ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -67,3 +67,5 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvm - nvmem_sunplus_ocotp-y := sunplus-ocotp.o - obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o - nvmem-apple-efuses-y := apple-efuses.o -+obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o -+nvmem-microchip-otpc-y := microchip-otpc.o ---- /dev/null -+++ b/drivers/nvmem/microchip-otpc.c -@@ -0,0 +1,288 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * OTP Memory controller -+ * -+ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries -+ * -+ * Author: Claudiu Beznea <claudiu.beznea@microchip.com> -+ */ -+ -+#include <linux/bitfield.h> -+#include <linux/iopoll.h> -+#include <linux/module.h> -+#include <linux/nvmem-provider.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+ -+#define MCHP_OTPC_CR (0x0) -+#define MCHP_OTPC_CR_READ BIT(6) -+#define MCHP_OTPC_MR (0x4) -+#define MCHP_OTPC_MR_ADDR GENMASK(31, 16) -+#define MCHP_OTPC_AR (0x8) -+#define MCHP_OTPC_SR (0xc) -+#define MCHP_OTPC_SR_READ BIT(6) -+#define MCHP_OTPC_HR (0x20) -+#define MCHP_OTPC_HR_SIZE GENMASK(15, 8) -+#define MCHP_OTPC_DR (0x24) -+ -+#define MCHP_OTPC_NAME "mchp-otpc" -+#define MCHP_OTPC_SIZE (11 * 1024) -+ -+/** -+ * struct mchp_otpc - OTPC private data structure -+ * @base: base address -+ * @dev: struct device pointer -+ * @packets: list of packets in OTP memory -+ * @npackets: number of packets in OTP memory -+ */ -+struct mchp_otpc { -+ void __iomem *base; -+ struct device *dev; -+ struct list_head packets; -+ u32 npackets; -+}; -+ -+/** -+ * struct mchp_otpc_packet - OTPC packet data structure -+ * @list: list head -+ * @id: packet ID -+ * @offset: packet offset (in words) in OTP memory -+ */ -+struct mchp_otpc_packet { -+ struct list_head list; -+ u32 id; -+ u32 offset; -+}; -+ -+static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc, -+ u32 id) -+{ -+ struct mchp_otpc_packet *packet; -+ -+ if (id >= otpc->npackets) -+ return NULL; -+ -+ list_for_each_entry(packet, &otpc->packets, list) { -+ if (packet->id == id) -+ return packet; -+ } -+ -+ return NULL; -+} -+ -+static int mchp_otpc_prepare_read(struct mchp_otpc *otpc, -+ unsigned int offset) -+{ -+ u32 tmp; -+ -+ /* Set address. */ -+ tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR); -+ tmp &= ~MCHP_OTPC_MR_ADDR; -+ tmp |= FIELD_PREP(MCHP_OTPC_MR_ADDR, offset); -+ writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR); -+ -+ /* Set read. */ -+ tmp = readl_relaxed(otpc->base + MCHP_OTPC_CR); -+ tmp |= MCHP_OTPC_CR_READ; -+ writel_relaxed(tmp, otpc->base + MCHP_OTPC_CR); -+ -+ /* Wait for packet to be transferred into temporary buffers. */ -+ return read_poll_timeout(readl_relaxed, tmp, !(tmp & MCHP_OTPC_SR_READ), -+ 10000, 2000, false, otpc->base + MCHP_OTPC_SR); -+} -+ -+/* -+ * OTPC memory is organized into packets. Each packets contains a header and -+ * a payload. Header is 4 bytes long and contains the size of the payload. -+ * Payload size varies. The memory footprint is something as follows: -+ * -+ * Memory offset Memory footprint Packet ID -+ * ------------- ---------------- --------- -+ * -+ * 0x0 +------------+ <-- packet 0 -+ * | header 0 | -+ * 0x4 +------------+ -+ * | payload 0 | -+ * . . -+ * . ... . -+ * . . -+ * offset1 +------------+ <-- packet 1 -+ * | header 1 | -+ * offset1 + 0x4 +------------+ -+ * | payload 1 | -+ * . . -+ * . ... . -+ * . . -+ * offset2 +------------+ <-- packet 2 -+ * . . -+ * . ... . -+ * . . -+ * offsetN +------------+ <-- packet N -+ * | header N | -+ * offsetN + 0x4 +------------+ -+ * | payload N | -+ * . . -+ * . ... . -+ * . . -+ * +------------+ -+ * -+ * where offset1, offset2, offsetN depends on the size of payload 0, payload 1, -+ * payload N-1. -+ * -+ * The access to memory is done on a per packet basis: the control registers -+ * need to be updated with an offset address (within a packet range) and the -+ * data registers will be update by controller with information contained by -+ * that packet. E.g. if control registers are updated with any address within -+ * the range [offset1, offset2) the data registers are updated by controller -+ * with packet 1. Header data is accessible though MCHP_OTPC_HR register. -+ * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers. -+ * There is no direct mapping b/w the offset requested by software and the -+ * offset returned by hardware. -+ * -+ * For this, the read function will return the first requested bytes in the -+ * packet. The user will have to be aware of the memory footprint before doing -+ * the read request. -+ */ -+static int mchp_otpc_read(void *priv, unsigned int off, void *val, -+ size_t bytes) -+{ -+ struct mchp_otpc *otpc = priv; -+ struct mchp_otpc_packet *packet; -+ u32 *buf = val; -+ u32 offset; -+ size_t len = 0; -+ int ret, payload_size; -+ -+ /* -+ * We reach this point with off being multiple of stride = 4 to -+ * be able to cross the subsystem. Inside the driver we use continuous -+ * unsigned integer numbers for packet id, thus devide off by 4 -+ * before passing it to mchp_otpc_id_to_packet(). -+ */ -+ packet = mchp_otpc_id_to_packet(otpc, off / 4); -+ if (!packet) -+ return -EINVAL; -+ offset = packet->offset; -+ -+ while (len < bytes) { -+ ret = mchp_otpc_prepare_read(otpc, offset); -+ if (ret) -+ return ret; -+ -+ /* Read and save header content. */ -+ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR); -+ len += sizeof(*buf); -+ offset++; -+ if (len >= bytes) -+ break; -+ -+ /* Read and save payload content. */ -+ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1)); -+ writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); -+ do { -+ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR); -+ len += sizeof(*buf); -+ offset++; -+ payload_size--; -+ } while (payload_size >= 0 && len < bytes); -+ } -+ -+ return 0; -+} -+ -+static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size) -+{ -+ struct mchp_otpc_packet *packet; -+ u32 word, word_pos = 0, id = 0, npackets = 0, payload_size; -+ int ret; -+ -+ INIT_LIST_HEAD(&otpc->packets); -+ *size = 0; -+ -+ while (*size < MCHP_OTPC_SIZE) { -+ ret = mchp_otpc_prepare_read(otpc, word_pos); -+ if (ret) -+ return ret; -+ -+ word = readl_relaxed(otpc->base + MCHP_OTPC_HR); -+ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, word); -+ if (!payload_size) -+ break; -+ -+ packet = devm_kzalloc(otpc->dev, sizeof(*packet), GFP_KERNEL); -+ if (!packet) -+ return -ENOMEM; -+ -+ packet->id = id++; -+ packet->offset = word_pos; -+ INIT_LIST_HEAD(&packet->list); -+ list_add_tail(&packet->list, &otpc->packets); -+ -+ /* Count size by adding header and paload sizes. */ -+ *size += 4 * (payload_size + 1); -+ /* Next word: this packet (header, payload) position + 1. */ -+ word_pos += payload_size + 2; -+ -+ npackets++; -+ } -+ -+ otpc->npackets = npackets; -+ -+ return 0; -+} -+ -+static struct nvmem_config mchp_nvmem_config = { -+ .name = MCHP_OTPC_NAME, -+ .type = NVMEM_TYPE_OTP, -+ .read_only = true, -+ .word_size = 4, -+ .stride = 4, -+ .reg_read = mchp_otpc_read, -+}; -+ -+static int mchp_otpc_probe(struct platform_device *pdev) -+{ -+ struct nvmem_device *nvmem; -+ struct mchp_otpc *otpc; -+ u32 size; -+ int ret; -+ -+ otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL); -+ if (!otpc) -+ return -ENOMEM; -+ -+ otpc->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(otpc->base)) -+ return PTR_ERR(otpc->base); -+ -+ otpc->dev = &pdev->dev; -+ ret = mchp_otpc_init_packets_list(otpc, &size); -+ if (ret) -+ return ret; -+ -+ mchp_nvmem_config.dev = otpc->dev; -+ mchp_nvmem_config.size = size; -+ mchp_nvmem_config.priv = otpc; -+ nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config); -+ -+ return PTR_ERR_OR_ZERO(nvmem); -+} -+ -+static const struct of_device_id __maybe_unused mchp_otpc_ids[] = { -+ { .compatible = "microchip,sama7g5-otpc", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, mchp_otpc_ids); -+ -+static struct platform_driver mchp_otpc_driver = { -+ .probe = mchp_otpc_probe, -+ .driver = { -+ .name = MCHP_OTPC_NAME, -+ .of_match_table = of_match_ptr(mchp_otpc_ids), -+ }, -+}; -+module_platform_driver(mchp_otpc_driver); -+ -+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea@microchip.com>"); -+MODULE_DESCRIPTION("Microchip SAMA7G5 OTPC driver"); -+MODULE_LICENSE("GPL"); |