From: Jonas Jelonek Date: Wed, 21 Jan 2026 23:17:04 +0000 (+0000) Subject: realtek: 6.18: remove obsolete patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3d998f147703e9342bf1eff245822afb41968c4;p=thirdparty%2Fopenwrt.git realtek: 6.18: remove obsolete patches Remove patches which are accepted upstream and were backported to pre-6.18. Those are obsolete now. Signed-off-by: Jonas Jelonek Link: https://github.com/openwrt/openwrt/pull/21181 Signed-off-by: Robert Marko --- diff --git a/target/linux/realtek/patches-6.18/001-v6.13-spi-mem-add-realtek-nand-controller.patch b/target/linux/realtek/patches-6.18/001-v6.13-spi-mem-add-realtek-nand-controller.patch deleted file mode 100644 index 1828e776f96..00000000000 --- a/target/linux/realtek/patches-6.18/001-v6.13-spi-mem-add-realtek-nand-controller.patch +++ /dev/null @@ -1,481 +0,0 @@ -From 42d20a6a61b8fccbb57d80df1ccde7dd82d5bbd6 Mon Sep 17 00:00:00 2001 -From: Chris Packham -Date: Wed, 16 Oct 2024 11:54:34 +1300 -Subject: [PATCH] spi: spi-mem: Add Realtek SPI-NAND controller - -Add a driver for the SPI-NAND controller on the RTL9300 family of -devices. - -The controller supports -* Serial/Dual/Quad data with -* PIO and DMA data read/write operation -* Configurable flash access timing - -There is a separate ECC controller on the RTL9300 which isn't currently -supported (instead we rely on the on-die ECC supported by most SPI-NAND -chips). - -Signed-off-by: Chris Packham -Link: https://patch.msgid.link/20241015225434.3970360-4-chris.packham@alliedtelesis.co.nz -Signed-off-by: Mark Brown ---- - MAINTAINERS | 6 + - drivers/spi/Kconfig | 11 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-realtek-rtl-snand.c | 405 ++++++++++++++++++++++++++++ - 4 files changed, 423 insertions(+) - create mode 100644 drivers/spi/spi-realtek-rtl-snand.c - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -19507,6 +19507,12 @@ S: Maintained - F: Documentation/devicetree/bindings/net/dsa/realtek.yaml - F: drivers/net/dsa/realtek/* - -+REALTEK SPI-NAND -+M: Chris Packham -+S: Maintained -+F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml -+F: drivers/spi/spi-realtek-rtl-snand.c -+ - REALTEK WIRELESS DRIVER (rtlwifi family) - M: Ping-Ke Shih - L: linux-wireless@vger.kernel.org ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -843,6 +843,17 @@ config SPI_PXA2XX - config SPI_PXA2XX_PCI - def_tristate SPI_PXA2XX && PCI && COMMON_CLK - -+config SPI_REALTEK_SNAND -+ tristate "Realtek SPI-NAND Flash Controller" -+ depends on MACH_REALTEK_RTL || COMPILE_TEST -+ select REGMAP -+ help -+ This enables support for the SPI-NAND Flash controller on -+ Realtek SoCs. -+ -+ This driver does not support generic SPI. The implementation -+ only supports the spi-mem interface. -+ - config SPI_ROCKCHIP - tristate "Rockchip SPI controller driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -120,6 +120,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockc - obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o - obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o - obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o -+obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o - obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o - obj-$(CONFIG_SPI_RSPI) += spi-rspi.o - obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o ---- /dev/null -+++ b/drivers/spi/spi-realtek-rtl-snand.c -@@ -0,0 +1,405 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SNAFCFR 0x00 -+#define SNAFCFR_DMA_IE BIT(20) -+#define SNAFCCR 0x04 -+#define SNAFWCMR 0x08 -+#define SNAFRCMR 0x0c -+#define SNAFRDR 0x10 -+#define SNAFWDR 0x14 -+#define SNAFDTR 0x18 -+#define SNAFDRSAR 0x1c -+#define SNAFDIR 0x20 -+#define SNAFDIR_DMA_IP BIT(0) -+#define SNAFDLR 0x24 -+#define SNAFSR 0x40 -+#define SNAFSR_NFCOS BIT(3) -+#define SNAFSR_NFDRS BIT(2) -+#define SNAFSR_NFDWS BIT(1) -+ -+#define CMR_LEN(len) ((len) - 1) -+#define CMR_WID(width) (((width) >> 1) << 28) -+ -+struct rtl_snand { -+ struct device *dev; -+ struct regmap *regmap; -+ struct completion comp; -+}; -+ -+static irqreturn_t rtl_snand_irq(int irq, void *data) -+{ -+ struct rtl_snand *snand = data; -+ u32 val = 0; -+ -+ regmap_read(snand->regmap, SNAFSR, &val); -+ if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS)) -+ return IRQ_NONE; -+ -+ regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); -+ complete(&snand->comp); -+ -+ return IRQ_HANDLED; -+} -+ -+static bool rtl_snand_supports_op(struct spi_mem *mem, -+ const struct spi_mem_op *op) -+{ -+ if (!spi_mem_default_supports_op(mem, op)) -+ return false; -+ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1) -+ return false; -+ return true; -+} -+ -+static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active) -+{ -+ u32 val; -+ -+ if (active) -+ val = ~(1 << (4 * cs)); -+ else -+ val = ~0; -+ -+ regmap_write(snand->regmap, SNAFCCR, val); -+} -+ -+static int rtl_snand_wait_ready(struct rtl_snand *snand) -+{ -+ u32 val; -+ -+ return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS), -+ 0, 2 * USEC_PER_MSEC); -+} -+ -+static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) -+{ -+ int ret; -+ u32 val, len = 0; -+ -+ rtl_snand_set_cs(snand, cs, true); -+ -+ val = op->cmd.opcode << 24; -+ len = 1; -+ if (op->addr.nbytes && op->addr.buswidth == 1) { -+ val |= op->addr.val << ((3 - op->addr.nbytes) * 8); -+ len += op->addr.nbytes; -+ } -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(snand->regmap, SNAFWDR, val); -+ if (ret) -+ return ret; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ return ret; -+ -+ if (op->addr.buswidth > 1) { -+ val = op->addr.val << ((3 - op->addr.nbytes) * 8); -+ len = op->addr.nbytes; -+ -+ ret = regmap_write(snand->regmap, SNAFWCMR, -+ CMR_WID(op->addr.buswidth) | CMR_LEN(len)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(snand->regmap, SNAFWDR, val); -+ if (ret) -+ return ret; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ return ret; -+ } -+ -+ if (op->dummy.nbytes) { -+ val = 0; -+ -+ ret = regmap_write(snand->regmap, SNAFWCMR, -+ CMR_WID(op->dummy.buswidth) | CMR_LEN(op->dummy.nbytes)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(snand->regmap, SNAFWDR, val); -+ if (ret) -+ return ret; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void rtl_snand_xfer_tail(struct rtl_snand *snand, int cs) -+{ -+ rtl_snand_set_cs(snand, cs, false); -+} -+ -+static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) -+{ -+ unsigned int pos, nbytes; -+ int ret; -+ u32 val, len = 0; -+ -+ ret = rtl_snand_xfer_head(snand, cs, op); -+ if (ret) -+ goto out_deselect; -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ pos = 0; -+ len = op->data.nbytes; -+ -+ while (pos < len) { -+ nbytes = len - pos; -+ if (nbytes > 4) -+ nbytes = 4; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ goto out_deselect; -+ -+ ret = regmap_write(snand->regmap, SNAFRCMR, -+ CMR_WID(op->data.buswidth) | CMR_LEN(nbytes)); -+ if (ret) -+ goto out_deselect; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ goto out_deselect; -+ -+ ret = regmap_read(snand->regmap, SNAFRDR, &val); -+ if (ret) -+ goto out_deselect; -+ -+ memcpy(op->data.buf.in + pos, &val, nbytes); -+ -+ pos += nbytes; -+ } -+ } else if (op->data.dir == SPI_MEM_DATA_OUT) { -+ pos = 0; -+ len = op->data.nbytes; -+ -+ while (pos < len) { -+ nbytes = len - pos; -+ if (nbytes > 4) -+ nbytes = 4; -+ -+ memcpy(&val, op->data.buf.out + pos, nbytes); -+ -+ pos += nbytes; -+ -+ ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(nbytes)); -+ if (ret) -+ goto out_deselect; -+ -+ ret = regmap_write(snand->regmap, SNAFWDR, val); -+ if (ret) -+ goto out_deselect; -+ -+ ret = rtl_snand_wait_ready(snand); -+ if (ret) -+ goto out_deselect; -+ } -+ } -+ -+out_deselect: -+ rtl_snand_xfer_tail(snand, cs); -+ -+ if (ret) -+ dev_err(snand->dev, "transfer failed %d\n", ret); -+ -+ return ret; -+} -+ -+static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) -+{ -+ int ret; -+ dma_addr_t buf_dma; -+ enum dma_data_direction dir; -+ u32 trig; -+ -+ ret = rtl_snand_xfer_head(snand, cs, op); -+ if (ret) -+ goto out_deselect; -+ -+ if (op->data.dir == SPI_MEM_DATA_IN) { -+ dir = DMA_FROM_DEVICE; -+ trig = 0; -+ } else if (op->data.dir == SPI_MEM_DATA_OUT) { -+ dir = DMA_TO_DEVICE; -+ trig = 1; -+ } else { -+ ret = -EOPNOTSUPP; -+ goto out_deselect; -+ } -+ -+ buf_dma = dma_map_single(snand->dev, op->data.buf.in, op->data.nbytes, dir); -+ ret = dma_mapping_error(snand->dev, buf_dma); -+ if (ret) -+ goto out_deselect; -+ -+ ret = regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP); -+ if (ret) -+ goto out_unmap; -+ -+ ret = regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, SNAFCFR_DMA_IE); -+ if (ret) -+ goto out_unmap; -+ -+ reinit_completion(&snand->comp); -+ -+ ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma); -+ if (ret) -+ goto out_disable_int; -+ -+ ret = regmap_write(snand->regmap, SNAFDLR, -+ CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff)); -+ if (ret) -+ goto out_disable_int; -+ -+ ret = regmap_write(snand->regmap, SNAFDTR, trig); -+ if (ret) -+ goto out_disable_int; -+ -+ if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) -+ ret = -ETIMEDOUT; -+ -+ if (ret) -+ goto out_disable_int; -+ -+out_disable_int: -+ regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); -+out_unmap: -+ dma_unmap_single(snand->dev, buf_dma, op->data.nbytes, dir); -+out_deselect: -+ rtl_snand_xfer_tail(snand, cs); -+ -+ if (ret) -+ dev_err(snand->dev, "transfer failed %d\n", ret); -+ -+ return ret; -+} -+ -+static bool rtl_snand_dma_op(const struct spi_mem_op *op) -+{ -+ switch (op->data.dir) { -+ case SPI_MEM_DATA_IN: -+ case SPI_MEM_DATA_OUT: -+ return op->data.nbytes > 32; -+ default: -+ return false; -+ } -+} -+ -+static int rtl_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) -+{ -+ struct rtl_snand *snand = spi_controller_get_devdata(mem->spi->controller); -+ int cs = spi_get_chipselect(mem->spi, 0); -+ -+ dev_dbg(snand->dev, "cs %d op cmd %02x %d:%d, dummy %d:%d, addr %08llx@%d:%d, data %d:%d\n", -+ cs, op->cmd.opcode, -+ op->cmd.buswidth, op->cmd.nbytes, op->dummy.buswidth, -+ op->dummy.nbytes, op->addr.val, op->addr.buswidth, -+ op->addr.nbytes, op->data.buswidth, op->data.nbytes); -+ -+ if (rtl_snand_dma_op(op)) -+ return rtl_snand_dma_xfer(snand, cs, op); -+ else -+ return rtl_snand_xfer(snand, cs, op); -+} -+ -+static const struct spi_controller_mem_ops rtl_snand_mem_ops = { -+ .supports_op = rtl_snand_supports_op, -+ .exec_op = rtl_snand_exec_op, -+}; -+ -+static const struct of_device_id rtl_snand_match[] = { -+ { .compatible = "realtek,rtl9301-snand" }, -+ { .compatible = "realtek,rtl9302b-snand" }, -+ { .compatible = "realtek,rtl9302c-snand" }, -+ { .compatible = "realtek,rtl9303-snand" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, rtl_snand_match); -+ -+static int rtl_snand_probe(struct platform_device *pdev) -+{ -+ struct rtl_snand *snand; -+ struct device *dev = &pdev->dev; -+ struct spi_controller *ctrl; -+ void __iomem *base; -+ const struct regmap_config rc = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .cache_type = REGCACHE_NONE, -+ }; -+ int irq, ret; -+ -+ ctrl = devm_spi_alloc_host(dev, sizeof(*snand)); -+ if (!ctrl) -+ return -ENOMEM; -+ -+ snand = spi_controller_get_devdata(ctrl); -+ snand->dev = dev; -+ -+ base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ snand->regmap = devm_regmap_init_mmio(dev, base, &rc); -+ if (IS_ERR(snand->regmap)) -+ return PTR_ERR(snand->regmap); -+ -+ init_completion(&snand->comp); -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ ret = dma_set_mask(snand->dev, DMA_BIT_MASK(32)); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to set DMA mask\n"); -+ -+ ret = devm_request_irq(dev, irq, rtl_snand_irq, 0, "rtl-snand", snand); -+ if (ret) -+ return dev_err_probe(dev, ret, "failed to request irq\n"); -+ -+ ctrl->num_chipselect = 2; -+ ctrl->mem_ops = &rtl_snand_mem_ops; -+ ctrl->bits_per_word_mask = SPI_BPW_MASK(8); -+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD; -+ device_set_node(&ctrl->dev, dev_fwnode(dev)); -+ -+ return devm_spi_register_controller(dev, ctrl); -+} -+ -+static struct platform_driver rtl_snand_driver = { -+ .driver = { -+ .name = "realtek-rtl-snand", -+ .of_match_table = rtl_snand_match, -+ }, -+ .probe = rtl_snand_probe, -+}; -+module_platform_driver(rtl_snand_driver); -+ -+MODULE_DESCRIPTION("Realtek SPI-NAND Flash Controller Driver"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/realtek/patches-6.18/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch b/target/linux/realtek/patches-6.18/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch deleted file mode 100644 index a929c670974..00000000000 --- a/target/linux/realtek/patches-6.18/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 25d284715845a465a1a3693a09cf8b6ab8bd9caf Mon Sep 17 00:00:00 2001 -From: Chris Packham -Date: Thu, 31 Oct 2024 08:49:20 +1300 -Subject: [PATCH] spi: spi-mem: rtl-snand: Correctly handle DMA transfers - -The RTL9300 has some limitations on the maximum DMA transfers possible. -For reads this is 2080 bytes (520*4) for writes this is 520 bytes. Deal -with this by splitting transfers into appropriately sized parts. - -Fixes: 42d20a6a61b8 ("spi: spi-mem: Add Realtek SPI-NAND controller") -Signed-off-by: Chris Packham -Link: https://patch.msgid.link/20241030194920.3202282-1-chris.packham@alliedtelesis.co.nz -Signed-off-by: Mark Brown ---- - drivers/spi/spi-realtek-rtl-snand.c | 46 +++++++++++++++++++---------- - 1 file changed, 30 insertions(+), 16 deletions(-) - ---- a/drivers/spi/spi-realtek-rtl-snand.c -+++ b/drivers/spi/spi-realtek-rtl-snand.c -@@ -231,19 +231,22 @@ out_deselect: - - static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op) - { -+ unsigned int pos, nbytes; - int ret; - dma_addr_t buf_dma; - enum dma_data_direction dir; -- u32 trig; -+ u32 trig, len, maxlen; - - ret = rtl_snand_xfer_head(snand, cs, op); - if (ret) - goto out_deselect; - - if (op->data.dir == SPI_MEM_DATA_IN) { -+ maxlen = 2080; - dir = DMA_FROM_DEVICE; - trig = 0; - } else if (op->data.dir == SPI_MEM_DATA_OUT) { -+ maxlen = 520; - dir = DMA_TO_DEVICE; - trig = 1; - } else { -@@ -264,26 +267,37 @@ static int rtl_snand_dma_xfer(struct rtl - if (ret) - goto out_unmap; - -- reinit_completion(&snand->comp); -+ pos = 0; -+ len = op->data.nbytes; - -- ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma); -- if (ret) -- goto out_disable_int; -+ while (pos < len) { -+ nbytes = len - pos; -+ if (nbytes > maxlen) -+ nbytes = maxlen; - -- ret = regmap_write(snand->regmap, SNAFDLR, -- CMR_WID(op->data.buswidth) | (op->data.nbytes & 0xffff)); -- if (ret) -- goto out_disable_int; -+ reinit_completion(&snand->comp); - -- ret = regmap_write(snand->regmap, SNAFDTR, trig); -- if (ret) -- goto out_disable_int; -+ ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos); -+ if (ret) -+ goto out_disable_int; - -- if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) -- ret = -ETIMEDOUT; -+ pos += nbytes; - -- if (ret) -- goto out_disable_int; -+ ret = regmap_write(snand->regmap, SNAFDLR, -+ CMR_WID(op->data.buswidth) | nbytes); -+ if (ret) -+ goto out_disable_int; -+ -+ ret = regmap_write(snand->regmap, SNAFDTR, trig); -+ if (ret) -+ goto out_disable_int; -+ -+ if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000))) -+ ret = -ETIMEDOUT; -+ -+ if (ret) -+ goto out_disable_int; -+ } - - out_disable_int: - regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0); diff --git a/target/linux/realtek/patches-6.18/003-v6.13-01-dt-bindings-i2c-Add-Realtek-RTL-I2C-Controller.patch b/target/linux/realtek/patches-6.18/003-v6.13-01-dt-bindings-i2c-Add-Realtek-RTL-I2C-Controller.patch deleted file mode 100644 index 8ec0d041273..00000000000 --- a/target/linux/realtek/patches-6.18/003-v6.13-01-dt-bindings-i2c-Add-Realtek-RTL-I2C-Controller.patch +++ /dev/null @@ -1,84 +0,0 @@ -From c5eda0333076e031197816454998a918f1de0831 Mon Sep 17 00:00:00 2001 -From: Chris Packham -Date: Fri, 1 Nov 2024 09:03:46 +1300 -Subject: [PATCH] dt-bindings: i2c: Add Realtek RTL I2C Controller - -Add dt-schema for the I2C controller on the RTL9300 Ethernet switch -with integrated SoC. - -Signed-off-by: Chris Packham -Reviewed-by: Krzysztof Kozlowski -Signed-off-by: Andi Shyti - ---- /dev/null -+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -@@ -0,0 +1,69 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/i2c/realtek,rtl9301-i2c.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Realtek RTL I2C Controller -+ -+maintainers: -+ - Chris Packham -+ -+description: -+ The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which -+ if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be -+ assigned to either I2C controller. -+ -+properties: -+ compatible: -+ oneOf: -+ - items: -+ - enum: -+ - realtek,rtl9302b-i2c -+ - realtek,rtl9302c-i2c -+ - realtek,rtl9303-i2c -+ - const: realtek,rtl9301-i2c -+ - const: realtek,rtl9301-i2c -+ -+ reg: -+ description: Register offset and size this I2C controller. -+ -+ "#address-cells": -+ const: 1 -+ -+ "#size-cells": -+ const: 0 -+ -+patternProperties: -+ '^i2c@[0-7]$': -+ $ref: /schemas/i2c/i2c-controller.yaml -+ unevaluatedProperties: false -+ -+ properties: -+ reg: -+ description: The SDA pin associated with the I2C bus. -+ maxItems: 1 -+ -+ required: -+ - reg -+ -+required: -+ - compatible -+ - reg -+ -+additionalProperties: false -+ -+examples: -+ - | -+ i2c@36c { -+ compatible = "realtek,rtl9301-i2c"; -+ reg = <0x36c 0x14>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ i2c@2 { -+ reg = <2>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ }; -+ }; diff --git a/target/linux/realtek/patches-6.18/003-v6.13-02-i2c-Add-driver-for-the-RTL9300-I2C-controller.patch b/target/linux/realtek/patches-6.18/003-v6.13-02-i2c-Add-driver-for-the-RTL9300-I2C-controller.patch deleted file mode 100644 index d5229284a02..00000000000 --- a/target/linux/realtek/patches-6.18/003-v6.13-02-i2c-Add-driver-for-the-RTL9300-I2C-controller.patch +++ /dev/null @@ -1,493 +0,0 @@ -From c366be720235301fdadf67e6f1ea6ff32669c074 Mon Sep 17 00:00:00 2001 -From: Chris Packham -Date: Wed, 6 Nov 2024 13:18:35 +1300 -Subject: [PATCH] i2c: Add driver for the RTL9300 I2C controller - -Add support for the I2C controller on the RTL9300 SoC. There are two I2C -controllers in the RTL9300 that are part of the Ethernet switch register -block. Each of these controllers owns a SCL pin (GPIO8 for the fiorst -I2C controller, GPIO17 for the second). There are 8 possible SDA pins -(GPIO9-16) that can be assigned to either I2C controller. This -relationship is represented in the device tree with a child node for -each SDA line in use. - -This is based on the openwrt implementation[1] but has been -significantly modified - -[1] - https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob;f=target/linux/realtek/files-5.15/drivers/i2c/busses/i2c-rtl9300.c - -Signed-off-by: Chris Packham -Reviewed-by: Andi Shyti -Signed-off-by: Andi Shyti - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -20164,6 +20164,13 @@ S: Maintained - T: git https://github.com/pkshih/rtw.git - F: drivers/net/wireless/realtek/rtl8xxxu/ - -+RTL9300 I2C DRIVER (rtl9300-i2c) -+M: Chris Packham -+L: linux-i2c@vger.kernel.org -+S: Maintained -+F: Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -+F: drivers/i2c/busses/i2c-rtl9300.c -+ - RTRS TRANSPORT DRIVERS - M: Md. Haris Iqbal - M: Jack Wang ---- a/drivers/i2c/busses/Kconfig -+++ b/drivers/i2c/busses/Kconfig -@@ -1062,6 +1062,16 @@ config I2C_RK3X - This driver can also be built as a module. If so, the module will - be called i2c-rk3x. - -+config I2C_RTL9300 -+ tristate "Realtek RTL9300 I2C controller" -+ depends on MACH_REALTEK_RTL || COMPILE_TEST -+ help -+ Say Y here to include support for the I2C controller in Realtek -+ RTL9300 SoCs. -+ -+ This driver can also be built as a module. If so, the module will -+ be called i2c-rtl9300. -+ - config I2C_RZV2M - tristate "Renesas RZ/V2M adapter" - depends on ARCH_RENESAS || COMPILE_TEST ---- a/drivers/i2c/busses/Makefile -+++ b/drivers/i2c/busses/Makefile -@@ -103,6 +103,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom- - obj-$(CONFIG_I2C_QUP) += i2c-qup.o - obj-$(CONFIG_I2C_RIIC) += i2c-riic.o - obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o -+obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o - obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o - obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o - obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o ---- /dev/null -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -0,0 +1,423 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+enum rtl9300_bus_freq { -+ RTL9300_I2C_STD_FREQ, -+ RTL9300_I2C_FAST_FREQ, -+}; -+ -+struct rtl9300_i2c; -+ -+struct rtl9300_i2c_chan { -+ struct i2c_adapter adap; -+ struct rtl9300_i2c *i2c; -+ enum rtl9300_bus_freq bus_freq; -+ u8 sda_pin; -+}; -+ -+#define RTL9300_I2C_MUX_NCHAN 8 -+ -+struct rtl9300_i2c { -+ struct regmap *regmap; -+ struct device *dev; -+ struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN]; -+ u32 reg_base; -+ u8 sda_pin; -+ struct mutex lock; -+}; -+ -+#define RTL9300_I2C_MST_CTRL1 0x0 -+#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8 -+#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8) -+#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4 -+#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4) -+#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3) -+#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2) -+#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1) -+#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0) -+#define RTL9300_I2C_MST_CTRL2 0x4 -+#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15) -+#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8 -+#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8) -+#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4 -+#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4) -+#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2 -+#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2) -+#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0 -+#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0) -+#define RTL9300_I2C_MST_DATA_WORD0 0x8 -+#define RTL9300_I2C_MST_DATA_WORD1 0xc -+#define RTL9300_I2C_MST_DATA_WORD2 0x10 -+#define RTL9300_I2C_MST_DATA_WORD3 0x14 -+ -+#define RTL9300_I2C_MST_GLB_CTRL 0x384 -+ -+static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len) -+{ -+ u32 val, mask; -+ int ret; -+ -+ val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS; -+ mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK; -+ -+ ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); -+ if (ret) -+ return ret; -+ -+ val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS; -+ mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK; -+ -+ return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+} -+ -+static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin) -+{ -+ int ret; -+ u32 val, mask; -+ -+ ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin)); -+ if (ret) -+ return ret; -+ -+ val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) | -+ RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; -+ mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; -+ -+ return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+} -+ -+static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan, -+ u16 addr, u16 len) -+{ -+ u32 val, mask; -+ -+ val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; -+ mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; -+ -+ val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS; -+ mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK; -+ -+ val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS; -+ mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK; -+ -+ mask |= RTL9300_I2C_MST_CTRL2_RD_MODE; -+ -+ return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); -+} -+ -+static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) -+{ -+ u32 vals[4] = {}; -+ int i, ret; -+ -+ if (len > 16) -+ return -EIO; -+ -+ ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, -+ vals, ARRAY_SIZE(vals)); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < len; i++) { -+ buf[i] = vals[i/4] & 0xff; -+ vals[i/4] >>= 8; -+ } -+ -+ return 0; -+} -+ -+static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len) -+{ -+ u32 vals[4] = {}; -+ int i; -+ -+ if (len > 16) -+ return -EIO; -+ -+ for (i = 0; i < len; i++) { -+ if (i % 4 == 0) -+ vals[i/4] = 0; -+ vals[i/4] <<= 8; -+ vals[i/4] |= buf[i]; -+ } -+ -+ return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, -+ vals, ARRAY_SIZE(vals)); -+} -+ -+static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data) -+{ -+ return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data); -+} -+ -+static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, -+ int size, union i2c_smbus_data *data, int len) -+{ -+ u32 val, mask; -+ int ret; -+ -+ val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0; -+ mask = RTL9300_I2C_MST_CTRL1_RWOP; -+ -+ val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; -+ mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; -+ -+ ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+ if (ret) -+ return ret; -+ -+ ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, -+ val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 2000); -+ if (ret) -+ return ret; -+ -+ if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL) -+ return -EIO; -+ -+ if (read_write == I2C_SMBUS_READ) { -+ if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) { -+ ret = regmap_read(i2c->regmap, -+ i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); -+ if (ret) -+ return ret; -+ data->byte = val & 0xff; -+ } else if (size == I2C_SMBUS_WORD_DATA) { -+ ret = regmap_read(i2c->regmap, -+ i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); -+ if (ret) -+ return ret; -+ data->word = val & 0xffff; -+ } else { -+ ret = rtl9300_i2c_read(i2c, &data->block[0], len); -+ if (ret) -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, -+ char read_write, u8 command, int size, -+ union i2c_smbus_data *data) -+{ -+ struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap); -+ struct rtl9300_i2c *i2c = chan->i2c; -+ int len = 0, ret; -+ -+ mutex_lock(&i2c->lock); -+ if (chan->sda_pin != i2c->sda_pin) { -+ ret = rtl9300_i2c_config_io(i2c, chan->sda_pin); -+ if (ret) -+ goto out_unlock; -+ i2c->sda_pin = chan->sda_pin; -+ } -+ -+ switch (size) { -+ case I2C_SMBUS_QUICK: -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); -+ if (ret) -+ goto out_unlock; -+ break; -+ -+ case I2C_SMBUS_BYTE: -+ if (read_write == I2C_SMBUS_WRITE) { -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -+ if (ret) -+ goto out_unlock; -+ } else { -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); -+ if (ret) -+ goto out_unlock; -+ } -+ break; -+ -+ case I2C_SMBUS_BYTE_DATA: -+ ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); -+ if (ret) -+ goto out_unlock; -+ if (read_write == I2C_SMBUS_WRITE) { -+ ret = rtl9300_i2c_writel(i2c, data->byte); -+ if (ret) -+ goto out_unlock; -+ } -+ break; -+ -+ case I2C_SMBUS_WORD_DATA: -+ ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2); -+ if (ret) -+ goto out_unlock; -+ if (read_write == I2C_SMBUS_WRITE) { -+ ret = rtl9300_i2c_writel(i2c, data->word); -+ if (ret) -+ goto out_unlock; -+ } -+ break; -+ -+ case I2C_SMBUS_BLOCK_DATA: -+ ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -+ if (ret) -+ goto out_unlock; -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); -+ if (ret) -+ goto out_unlock; -+ if (read_write == I2C_SMBUS_WRITE) { -+ ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); -+ if (ret) -+ goto out_unlock; -+ } -+ len = data->block[0]; -+ break; -+ -+ default: -+ dev_err(&adap->dev, "Unsupported transaction %d\n", size); -+ ret = -EOPNOTSUPP; -+ goto out_unlock; -+ } -+ -+ ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len); -+ -+out_unlock: -+ mutex_unlock(&i2c->lock); -+ -+ return ret; -+} -+ -+static u32 rtl9300_i2c_func(struct i2c_adapter *a) -+{ -+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | -+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | -+ I2C_FUNC_SMBUS_BLOCK_DATA; -+} -+ -+static const struct i2c_algorithm rtl9300_i2c_algo = { -+ .smbus_xfer = rtl9300_i2c_smbus_xfer, -+ .functionality = rtl9300_i2c_func, -+}; -+ -+static struct i2c_adapter_quirks rtl9300_i2c_quirks = { -+ .flags = I2C_AQ_NO_CLK_STRETCH, -+ .max_read_len = 16, -+ .max_write_len = 16, -+}; -+ -+static int rtl9300_i2c_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rtl9300_i2c *i2c; -+ u32 clock_freq, sda_pin; -+ int ret, i = 0; -+ struct fwnode_handle *child; -+ -+ i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); -+ if (!i2c) -+ return -ENOMEM; -+ -+ i2c->regmap = syscon_node_to_regmap(dev->parent->of_node); -+ if (IS_ERR(i2c->regmap)) -+ return PTR_ERR(i2c->regmap); -+ i2c->dev = dev; -+ -+ mutex_init(&i2c->lock); -+ -+ ret = device_property_read_u32(dev, "reg", &i2c->reg_base); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, i2c); -+ -+ if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) -+ return dev_err_probe(dev, -EINVAL, "Too many channels\n"); -+ -+ device_for_each_child_node(dev, child) { -+ struct rtl9300_i2c_chan *chan = &i2c->chans[i]; -+ struct i2c_adapter *adap = &chan->adap; -+ -+ ret = fwnode_property_read_u32(child, "reg", &sda_pin); -+ if (ret) -+ return ret; -+ -+ ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq); -+ if (ret) -+ clock_freq = I2C_MAX_STANDARD_MODE_FREQ; -+ -+ switch (clock_freq) { -+ case I2C_MAX_STANDARD_MODE_FREQ: -+ chan->bus_freq = RTL9300_I2C_STD_FREQ; -+ break; -+ -+ case I2C_MAX_FAST_MODE_FREQ: -+ chan->bus_freq = RTL9300_I2C_FAST_FREQ; -+ break; -+ default: -+ dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n", -+ sda_pin, clock_freq); -+ break; -+ } -+ -+ chan->sda_pin = sda_pin; -+ chan->i2c = i2c; -+ adap = &i2c->chans[i].adap; -+ adap->owner = THIS_MODULE; -+ adap->algo = &rtl9300_i2c_algo; -+ adap->quirks = &rtl9300_i2c_quirks; -+ adap->retries = 3; -+ adap->dev.parent = dev; -+ i2c_set_adapdata(adap, chan); -+ adap->dev.of_node = to_of_node(child); -+ snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin); -+ i++; -+ -+ ret = devm_i2c_add_adapter(dev, adap); -+ if (ret) -+ return ret; -+ } -+ i2c->sda_pin = 0xff; -+ -+ return 0; -+} -+ -+static const struct of_device_id i2c_rtl9300_dt_ids[] = { -+ { .compatible = "realtek,rtl9301-i2c" }, -+ { .compatible = "realtek,rtl9302b-i2c" }, -+ { .compatible = "realtek,rtl9302c-i2c" }, -+ { .compatible = "realtek,rtl9303-i2c" }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); -+ -+static struct platform_driver rtl9300_i2c_driver = { -+ .probe = rtl9300_i2c_probe, -+ .driver = { -+ .name = "i2c-rtl9300", -+ .of_match_table = i2c_rtl9300_dt_ids, -+ }, -+}; -+ -+module_platform_driver(rtl9300_i2c_driver); -+ -+MODULE_DESCRIPTION("RTL9300 I2C controller driver"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/realtek/patches-6.18/004-v6.16-dt-bindings-i2c-realtek-rtl9301-Fix-missing-reg-cons.patch b/target/linux/realtek/patches-6.18/004-v6.16-dt-bindings-i2c-realtek-rtl9301-Fix-missing-reg-cons.patch deleted file mode 100644 index c460eb1a405..00000000000 --- a/target/linux/realtek/patches-6.18/004-v6.16-dt-bindings-i2c-realtek-rtl9301-Fix-missing-reg-cons.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 5f05fc6e2218db7ecc52c60eb34b707fe69262c2 Mon Sep 17 00:00:00 2001 -From: Krzysztof Kozlowski -Date: Wed, 2 Jul 2025 08:15:31 +0200 -Subject: [PATCH] dt-bindings: i2c: realtek,rtl9301: Fix missing 'reg' - constraint - -Lists should have fixed amount if items, so add missing constraint to -the 'reg' property (only one address space entry). - -Fixes: c5eda0333076 ("dt-bindings: i2c: Add Realtek RTL I2C Controller") -Cc: # v6.13+ -Signed-off-by: Krzysztof Kozlowski -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250702061530.6940-2-krzysztof.kozlowski@linaro.org - ---- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -@@ -26,7 +26,8 @@ properties: - - const: realtek,rtl9301-i2c - - reg: -- description: Register offset and size this I2C controller. -+ items: -+ - description: Register offset and size this I2C controller. - - "#address-cells": - const: 1 diff --git a/target/linux/realtek/patches-6.18/005-01-v6.17-i2c-rtl9300-Fix-out-of-bounds-bug-in-rtl9300_i2c_smb.patch b/target/linux/realtek/patches-6.18/005-01-v6.17-i2c-rtl9300-Fix-out-of-bounds-bug-in-rtl9300_i2c_smb.patch deleted file mode 100644 index 2ffb6596430..00000000000 --- a/target/linux/realtek/patches-6.18/005-01-v6.17-i2c-rtl9300-Fix-out-of-bounds-bug-in-rtl9300_i2c_smb.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 57f312b955938fc4663f430cb57a71f2414f601b Mon Sep 17 00:00:00 2001 -From: Alex Guo -Date: Sun, 10 Aug 2025 20:05:13 +0200 -Subject: [PATCH] i2c: rtl9300: Fix out-of-bounds bug in rtl9300_i2c_smbus_xfer - -The data->block[0] variable comes from user. Without proper check, -the variable may be very large to cause an out-of-bounds bug. - -Fix this bug by checking the value of data->block[0] first. - -1. commit 39244cc75482 ("i2c: ismt: Fix an out-of-bounds bug in - ismt_access()") -2. commit 92fbb6d1296f ("i2c: xgene-slimpro: Fix out-of-bounds bug in - xgene_slimpro_i2c_xfer()") - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Signed-off-by: Alex Guo -Cc: # v6.13+ -Reviewed-by: Chris Packham -Tested-by: Chris Packham -Reviewed-by: Wolfram Sang -Signed-off-by: Sven Eckelmann -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-1-cd9dca0db722@narfation.org - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -281,6 +281,10 @@ static int rtl9300_i2c_smbus_xfer(struct - ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); - if (ret) - goto out_unlock; -+ if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } - ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); - if (ret) - goto out_unlock; diff --git a/target/linux/realtek/patches-6.18/005-02-v6.17-i2c-rtl9300-Fix-multi-byte-I2C-write.patch b/target/linux/realtek/patches-6.18/005-02-v6.17-i2c-rtl9300-Fix-multi-byte-I2C-write.patch deleted file mode 100644 index ac6bb52603b..00000000000 --- a/target/linux/realtek/patches-6.18/005-02-v6.17-i2c-rtl9300-Fix-multi-byte-I2C-write.patch +++ /dev/null @@ -1,75 +0,0 @@ -From d67b740b9edfa46310355e2b68050f79ebf05a4c Mon Sep 17 00:00:00 2001 -From: Harshal Gohel -Date: Sun, 10 Aug 2025 20:05:14 +0200 -Subject: [PATCH] i2c: rtl9300: Fix multi-byte I2C write - -The RTL93xx I2C controller has 4 32 bit registers to store the bytes for -the upcoming I2C transmission. The first byte is stored in the -least-significant byte of the first register. And the last byte in the most -significant byte of the last register. A map of the transferred bytes to -their order in the registers is: - -reg 0: 0x04_03_02_01 -reg 1: 0x08_07_06_05 -reg 2: 0x0c_0b_0a_09 -reg 3: 0x10_0f_0e_0d - -The i2c_read() function basically demonstrates how the hardware would pick -up bytes from this register set. But the i2c_write() function was just -pushing bytes one after another to the least significant byte of a register -AFTER shifting the last one to the next more significant byte position. - -If you would then have tried to send a buffer with numbers 1-11 using -i2c_write(), you would have ended up with following register content: - -reg 0: 0x01_02_03_04 -reg 1: 0x05_06_07_08 -reg 2: 0x00_09_0a_0b -reg 3: 0x00_00_00_00 - -On the wire, you would then have seen: - - Sr Addr Wr [A] 04 A 03 A 02 A 01 A 08 A 07 A 06 A 05 A 0b A 0a A 09 A P - -But the correct data transmission was expected to be - - Sr Addr Wr [A] 01 A 02 A 03 A 04 A 05 A 06 A 07 A 08 A 09 A 0a A 0b A P - -Because of this multi-byte ordering problem, only single byte i2c_write() -operations were executed correctly (on the wire). - -By shifting the byte directly to the correct end position in the register, -it is possible to avoid this incorrect byte ordering and fix multi-byte -transmissions. - -The second initialization (to 0) of vals was also be dropped because this -array is initialized to 0 on the stack by using `= {};`. This makes the -fix a lot more readable. - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Signed-off-by: Harshal Gohel -Cc: # v6.13+ -Co-developed-by: Sven Eckelmann -Signed-off-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-2-cd9dca0db722@narfation.org - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -143,10 +143,10 @@ static int rtl9300_i2c_write(struct rtl9 - return -EIO; - - for (i = 0; i < len; i++) { -- if (i % 4 == 0) -- vals[i/4] = 0; -- vals[i/4] <<= 8; -- vals[i/4] |= buf[i]; -+ unsigned int shift = (i % 4) * 8; -+ unsigned int reg = i / 4; -+ -+ vals[reg] |= buf[i] << shift; - } - - return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, diff --git a/target/linux/realtek/patches-6.18/005-03-v6.17-i2c-rtl9300-Increase-timeout-for-transfer-polling.patch b/target/linux/realtek/patches-6.18/005-03-v6.17-i2c-rtl9300-Increase-timeout-for-transfer-polling.patch deleted file mode 100644 index bfb4f4875d8..00000000000 --- a/target/linux/realtek/patches-6.18/005-03-v6.17-i2c-rtl9300-Increase-timeout-for-transfer-polling.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ceee7776c010c5f09d30985c9e5223b363a6172a Mon Sep 17 00:00:00 2001 -From: Sven Eckelmann -Date: Sun, 10 Aug 2025 20:05:15 +0200 -Subject: [PATCH] i2c: rtl9300: Increase timeout for transfer polling - -The timeout for transfers was only set to 2ms. Because of this relatively -low limit, 12-byte read operations to the frontend MCU of a RTL8239 POE PSE -chip cluster was consistently resulting in a timeout. - -The original OpenWrt downstream driver [1] was not using any timeout limit -at all. This is also possible by setting the timeout_us parameter of -regmap_read_poll_timeout() to 0. But since the driver currently implements -the ETIMEDOUT error, it is more sensible to increase the timeout in such a -way that communication with the (quite common) Realtek I2C-connected POE -management solution is possible. - -[1] https://git.openwrt.org/?p=openwrt/openwrt.git;a=blob;f=target/linux/realtek/files-6.12/drivers/i2c/busses/i2c-rtl9300.c;h=c4d973195ef39dc56d6207e665d279745525fcac#l202 - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Signed-off-by: Sven Eckelmann -Cc: # v6.13+ -Reviewed-by: Chris Packham -Tested-by: Chris Packham -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-3-cd9dca0db722@narfation.org - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -175,7 +175,7 @@ static int rtl9300_i2c_execute_xfer(stru - return ret; - - ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, -- val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 2000); -+ val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000); - if (ret) - return ret; - diff --git a/target/linux/realtek/patches-6.18/005-04-v6.17-i2c-rtl9300-Add-missing-count-byte-for-SMBus-Block-O.patch b/target/linux/realtek/patches-6.18/005-04-v6.17-i2c-rtl9300-Add-missing-count-byte-for-SMBus-Block-O.patch deleted file mode 100644 index b5314b258a4..00000000000 --- a/target/linux/realtek/patches-6.18/005-04-v6.17-i2c-rtl9300-Add-missing-count-byte-for-SMBus-Block-O.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 82b350dd8185ce790e61555c436f90b6501af23c Mon Sep 17 00:00:00 2001 -From: Sven Eckelmann -Date: Sun, 10 Aug 2025 20:05:16 +0200 -Subject: [PATCH] i2c: rtl9300: Add missing count byte for SMBus Block Ops - -The expected on-wire format of an SMBus Block Write is - - S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P - -Everything starting from the Count byte is provided by the I2C subsystem in -the array data->block. But the driver was skipping the Count byte -(data->block[0]) when sending it to the RTL93xx I2C controller. - -Only the actual data could be seen on the wire: - - S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P - -This wire format is not SMBus Block Write compatible but matches the format -of an I2C Block Write. Simply adding the count byte to the buffer for the -I2C controller is enough to fix the transmission. - -This also affects read because the I2C controller must receive the count -byte + $count * data bytes. - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Signed-off-by: Sven Eckelmann -Cc: # v6.13+ -Reviewed-by: Chris Packham -Tested-by: Chris Packham -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250810-i2c-rtl9300-multi-byte-v5-4-cd9dca0db722@narfation.org - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -285,15 +285,15 @@ static int rtl9300_i2c_smbus_xfer(struct - ret = -EINVAL; - goto out_unlock; - } -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1); - if (ret) - goto out_unlock; - if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); -+ ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1); - if (ret) - goto out_unlock; - } -- len = data->block[0]; -+ len = data->block[0] + 1; - break; - - default: diff --git a/target/linux/realtek/patches-6.18/006-01-v6.17-i2c-rtl9300-fix-channel-number-bound-check.patch b/target/linux/realtek/patches-6.18/006-01-v6.17-i2c-rtl9300-fix-channel-number-bound-check.patch deleted file mode 100644 index 2076a0ad68e..00000000000 --- a/target/linux/realtek/patches-6.18/006-01-v6.17-i2c-rtl9300-fix-channel-number-bound-check.patch +++ /dev/null @@ -1,40 +0,0 @@ -From cd6c956fbc13156bcbcca084b46a8380caebc2a8 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sun, 31 Aug 2025 10:04:46 +0000 -Subject: [PATCH] i2c: rtl9300: fix channel number bound check - -Fix the current check for number of channels (child nodes in the device -tree). Before, this was: - -if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) - -RTL9300_I2C_MUX_NCHAN gives the maximum number of channels so checking -with '>=' isn't correct because it doesn't allow the last channel -number. Thus, fix it to: - -if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN) - -Issue occured on a TP-Link TL-ST1008F v2.0 device (8 SFP+ ports) and fix -is tested there. - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Cc: stable@vger.kernel.org # v6.13+ -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250831100457.3114-2-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -353,7 +353,7 @@ static int rtl9300_i2c_probe(struct plat - - platform_set_drvdata(pdev, i2c); - -- if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN) -+ if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN) - return dev_err_probe(dev, -EINVAL, "Too many channels\n"); - - device_for_each_child_node(dev, child) { diff --git a/target/linux/realtek/patches-6.18/006-02-v6.17-i2c-rtl9300-ensure-data-length-is-within-supported-r.patch b/target/linux/realtek/patches-6.18/006-02-v6.17-i2c-rtl9300-ensure-data-length-is-within-supported-r.patch deleted file mode 100644 index 382c47a882b..00000000000 --- a/target/linux/realtek/patches-6.18/006-02-v6.17-i2c-rtl9300-ensure-data-length-is-within-supported-r.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 06418cb5a1a542a003fdb4ad8e76ea542d57cfba Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sun, 31 Aug 2025 10:04:47 +0000 -Subject: [PATCH] i2c: rtl9300: ensure data length is within supported range - -Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer' -to ensure the data length isn't within the supported range. In -particular a data length of 0 is not supported by the hardware and -causes unintended or destructive behaviour. - -This limitation becomes obvious when looking at the register -documentation [1]. 4 bits are reserved for DATA_WIDTH and the value -of these 4 bits is used as N + 1, allowing a data length range of -1 <= len <= 16. - -Affected by this is the SMBus Quick Operation which works with a data -length of 0. Passing 0 as the length causes an underflow of the value -due to: - -(len - 1) & 0xf - -and effectively specifying a transfer length of 16 via the registers. -This causes a 16-byte write operation instead of a Quick Write. For -example, on SFP modules without write-protected EEPROM this soft-bricks -them by overwriting some initial bytes. - -For completeness, also add a quirk for the zero length. - -[1] https://svanheule.net/realtek/longan/register/i2c_mst1_ctrl2 - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Cc: stable@vger.kernel.org # v6.13+ -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250831100457.3114-3-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -99,6 +99,9 @@ static int rtl9300_i2c_config_xfer(struc - { - u32 val, mask; - -+ if (len < 1 || len > 16) -+ return -EINVAL; -+ - val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; - mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; - -@@ -323,7 +326,7 @@ static const struct i2c_algorithm rtl930 - }; - - static struct i2c_adapter_quirks rtl9300_i2c_quirks = { -- .flags = I2C_AQ_NO_CLK_STRETCH, -+ .flags = I2C_AQ_NO_CLK_STRETCH | I2C_AQ_NO_ZERO_LEN, - .max_read_len = 16, - .max_write_len = 16, - }; diff --git a/target/linux/realtek/patches-6.18/006-03-v6.17-i2c-rtl9300-remove-broken-SMBus-Quick-operation-supp.patch b/target/linux/realtek/patches-6.18/006-03-v6.17-i2c-rtl9300-remove-broken-SMBus-Quick-operation-supp.patch deleted file mode 100644 index 6de11af54f6..00000000000 --- a/target/linux/realtek/patches-6.18/006-03-v6.17-i2c-rtl9300-remove-broken-SMBus-Quick-operation-supp.patch +++ /dev/null @@ -1,77 +0,0 @@ -From ede965fd555ac2536cf651893a998dbfd8e57b86 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sun, 31 Aug 2025 10:04:48 +0000 -Subject: [PATCH] i2c: rtl9300: remove broken SMBus Quick operation support - -Remove the SMBus Quick operation from this driver because it is not -natively supported by the hardware and is wrongly implemented in the -driver. - -The I2C controllers in Realtek RTL9300 and RTL9310 are SMBus-compliant -but there doesn't seem to be native support for the SMBus Quick -operation. It is not explicitly mentioned in the documentation but -looking at the registers which configure an SMBus transaction, one can -see that the data length cannot be set to 0. This suggests that the -hardware doesn't allow any SMBus message without data bytes (except for -those it does on it's own, see SMBus Block Read). - -The current implementation of SMBus Quick operation passes a length of -0 (which is actually invalid). Before the fix of a bug in a previous -commit, this led to a read operation of 16 bytes from any register (the -one of a former transaction or any other value. - -This caused issues like soft-bricked SFP modules after a simple probe -with i2cdetect which uses Quick by default. Running this with SFP -modules whose EEPROM isn't write-protected, some of the initial bytes -are overwritten because a 16-byte write operation is executed instead of -a Quick Write. (This temporarily soft-bricked one of my DAC cables.) - -Because SMBus Quick operation is obviously not supported on these -controllers (because a length of 0 cannot be set, even when no register -address is set), remove that instead of claiming there is support. There -also shouldn't be any kind of emulated 'Quick' which just does another -kind of operation in the background. Otherwise, specific issues occur -in case of a 'Quick' Write which actually writes unknown data to an -unknown register. - -Fixes: c366be720235 ("i2c: Add driver for the RTL9300 I2C controller") -Cc: stable@vger.kernel.org # v6.13+ -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250831100457.3114-4-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -225,15 +225,6 @@ static int rtl9300_i2c_smbus_xfer(struct - } - - switch (size) { -- case I2C_SMBUS_QUICK: -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); -- if (ret) -- goto out_unlock; -- ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); -- if (ret) -- goto out_unlock; -- break; -- - case I2C_SMBUS_BYTE: - if (read_write == I2C_SMBUS_WRITE) { - ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); -@@ -315,9 +306,9 @@ out_unlock: - - static u32 rtl9300_i2c_func(struct i2c_adapter *a) - { -- return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | -- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | -- I2C_FUNC_SMBUS_BLOCK_DATA; -+ return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | -+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | -+ I2C_FUNC_SMBUS_I2C_BLOCK; - } - - static const struct i2c_algorithm rtl9300_i2c_algo = { diff --git a/target/linux/realtek/patches-6.18/007-01-v6.17-i2c-rtl9300-Drop-unsupported-I2C_FUNC_SMBUS_I2C_BLOC.patch b/target/linux/realtek/patches-6.18/007-01-v6.17-i2c-rtl9300-Drop-unsupported-I2C_FUNC_SMBUS_I2C_BLOC.patch deleted file mode 100644 index 901c48abdc5..00000000000 --- a/target/linux/realtek/patches-6.18/007-01-v6.17-i2c-rtl9300-Drop-unsupported-I2C_FUNC_SMBUS_I2C_BLOC.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 095530512152e6811278de9c30f170f0ac9705eb Mon Sep 17 00:00:00 2001 -From: Sven Eckelmann -Date: Sat, 27 Sep 2025 11:52:16 +0200 -Subject: [PATCH] i2c: rtl9300: Drop unsupported I2C_FUNC_SMBUS_I2C_BLOCK - -While applying the patch for commit ede965fd555a ("i2c: rtl9300: remove -broken SMBus Quick operation support"), a conflict was incorrectly solved -by adding the I2C_FUNC_SMBUS_I2C_BLOCK feature flag. But the code to handle -I2C_SMBUS_I2C_BLOCK_DATA requests will be added by a separate commit. - -Fixes: ede965fd555a ("i2c: rtl9300: remove broken SMBus Quick operation support") -Signed-off-by: Sven Eckelmann -Signed-off-by: Wolfram Sang - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -307,8 +307,7 @@ out_unlock: - static u32 rtl9300_i2c_func(struct i2c_adapter *a) - { - return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | -- I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | -- I2C_FUNC_SMBUS_I2C_BLOCK; -+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; - } - - static const struct i2c_algorithm rtl9300_i2c_algo = { diff --git a/target/linux/realtek/patches-6.18/007-02-v6.18-i2c-rtl9300-Implement-I2C-block-read-and-write.patch b/target/linux/realtek/patches-6.18/007-02-v6.18-i2c-rtl9300-Implement-I2C-block-read-and-write.patch deleted file mode 100644 index d97b76993bc..00000000000 --- a/target/linux/realtek/patches-6.18/007-02-v6.18-i2c-rtl9300-Implement-I2C-block-read-and-write.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 415216ae3196e67bdb9515519f219d553bd38d3a Mon Sep 17 00:00:00 2001 -From: Harshal Gohel -Date: Sat, 27 Sep 2025 11:52:17 +0200 -Subject: [PATCH] i2c: rtl9300: Implement I2C block read and write - -It was noticed that the original implementation of SMBus Block Write in the -driver was actually an I2C Block Write. Both differ only in the Count byte -before the actual data: - - S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P - -The I2C Block Write is just skipping this Count byte and starts directly -with the data: - - S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P - -The I2C controller of RTL93xx doesn't handle this Count byte special and it -is simply another one of (16 possible) data bytes. Adding support for the -I2C Block Write therefore only requires skipping the count byte (0) in -data->block. - -It is similar for reads. The SMBUS Block read is having a Count byte before -the data: - - S Addr Wr [A] Comm [A] - Sr Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P - -And the I2C Block Read is directly starting with the actual data: - - S Addr Wr [A] Comm [A] - Sr Addr Rd [A] [Data] A [Data] A ... A [Data] NA P - -The I2C controller is also not handling this byte in a special way. It -simply provides every byte after the Rd marker + Ack as part of the 16 byte -receive buffer (registers). The content of this buffer just has to be -copied to the right position in the receive data->block. - -Signed-off-by: Harshal Gohel -Co-developed-by: Sven Eckelmann -Signed-off-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham -Reviewed-by: Jonas Jelonek -Tested-by: Jonas Jelonek - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -186,22 +186,32 @@ static int rtl9300_i2c_execute_xfer(stru - return -EIO; - - if (read_write == I2C_SMBUS_READ) { -- if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA) { -+ switch (size) { -+ case I2C_SMBUS_BYTE: -+ case I2C_SMBUS_BYTE_DATA: - ret = regmap_read(i2c->regmap, - i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); - if (ret) - return ret; - data->byte = val & 0xff; -- } else if (size == I2C_SMBUS_WORD_DATA) { -+ break; -+ case I2C_SMBUS_WORD_DATA: - ret = regmap_read(i2c->regmap, - i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); - if (ret) - return ret; - data->word = val & 0xffff; -- } else { -+ break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ ret = rtl9300_i2c_read(i2c, &data->block[1], len); -+ if (ret) -+ return ret; -+ break; -+ default: - ret = rtl9300_i2c_read(i2c, &data->block[0], len); - if (ret) - return ret; -+ break; - } - } - -@@ -290,6 +300,25 @@ static int rtl9300_i2c_smbus_xfer(struct - len = data->block[0] + 1; - break; - -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -+ if (ret) -+ goto out_unlock; -+ if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) { -+ ret = -EINVAL; -+ goto out_unlock; -+ } -+ ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); -+ if (ret) -+ goto out_unlock; -+ if (read_write == I2C_SMBUS_WRITE) { -+ ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); -+ if (ret) -+ goto out_unlock; -+ } -+ len = data->block[0]; -+ break; -+ - default: - dev_err(&adap->dev, "Unsupported transaction %d\n", size); - ret = -EOPNOTSUPP; -@@ -307,7 +336,8 @@ out_unlock: - static u32 rtl9300_i2c_func(struct i2c_adapter *a) - { - return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | -- I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA; -+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | -+ I2C_FUNC_SMBUS_I2C_BLOCK; - } - - static const struct i2c_algorithm rtl9300_i2c_algo = { diff --git a/target/linux/realtek/patches-6.18/008-01-v6.18-i2c-rtl9300-use-regmap-fields-and-API-for-registers.patch b/target/linux/realtek/patches-6.18/008-01-v6.18-i2c-rtl9300-use-regmap-fields-and-API-for-registers.patch deleted file mode 100644 index 30bd16ee694..00000000000 --- a/target/linux/realtek/patches-6.18/008-01-v6.18-i2c-rtl9300-use-regmap-fields-and-API-for-registers.patch +++ /dev/null @@ -1,354 +0,0 @@ -From 5a6ecb27435ef7a67d7bec4543f0c6303f34e8a6 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:23 +0000 -Subject: [PATCH] i2c: rtl9300: use regmap fields and API for registers - -Adapt the RTL9300 I2C controller driver to use more of the regmap -API, especially make use of reg_field and regmap_field instead of macros -to represent registers. Most register operations are performed through -regmap_field_* API then. - -Handle SCL selection using separate chip-specific functions since this -is already known to differ between the Realtek SoC families in such a -way that this cannot be properly handled using just a different -reg_field. - -This makes it easier to add support for newer generations or to handle -differences between specific revisions within a series. Just by -defining a separate driver data structure with the corresponding -register field definitions and linking it to a new compatible. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-2-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -23,97 +23,117 @@ struct rtl9300_i2c_chan { - u8 sda_pin; - }; - -+enum rtl9300_i2c_reg_scope { -+ REG_SCOPE_GLOBAL, -+ REG_SCOPE_MASTER, -+}; -+ -+struct rtl9300_i2c_reg_field { -+ struct reg_field field; -+ enum rtl9300_i2c_reg_scope scope; -+}; -+ -+enum rtl9300_i2c_reg_fields { -+ F_DATA_WIDTH = 0, -+ F_DEV_ADDR, -+ F_I2C_FAIL, -+ F_I2C_TRIG, -+ F_MEM_ADDR, -+ F_MEM_ADDR_WIDTH, -+ F_RD_MODE, -+ F_RWOP, -+ F_SCL_FREQ, -+ F_SCL_SEL, -+ F_SDA_OUT_SEL, -+ F_SDA_SEL, -+ -+ /* keep last */ -+ F_NUM_FIELDS -+}; -+ -+struct rtl9300_i2c_drv_data { -+ struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS]; -+ int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl); -+ u32 data_reg; -+ u8 max_nchan; -+}; -+ - #define RTL9300_I2C_MUX_NCHAN 8 - - struct rtl9300_i2c { - struct regmap *regmap; - struct device *dev; - struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN]; -+ struct regmap_field *fields[F_NUM_FIELDS]; - u32 reg_base; -+ u32 data_reg; - u8 sda_pin; - struct mutex lock; - }; - - #define RTL9300_I2C_MST_CTRL1 0x0 --#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS 8 --#define RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK GENMASK(31, 8) --#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS 4 --#define RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK GENMASK(6, 4) --#define RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL BIT(3) --#define RTL9300_I2C_MST_CTRL1_RWOP BIT(2) --#define RTL9300_I2C_MST_CTRL1_I2C_FAIL BIT(1) --#define RTL9300_I2C_MST_CTRL1_I2C_TRIG BIT(0) - #define RTL9300_I2C_MST_CTRL2 0x4 --#define RTL9300_I2C_MST_CTRL2_RD_MODE BIT(15) --#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS 8 --#define RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK GENMASK(14, 8) --#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS 4 --#define RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK GENMASK(7, 4) --#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS 2 --#define RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK GENMASK(3, 2) --#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS 0 --#define RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK GENMASK(1, 0) - #define RTL9300_I2C_MST_DATA_WORD0 0x8 - #define RTL9300_I2C_MST_DATA_WORD1 0xc - #define RTL9300_I2C_MST_DATA_WORD2 0x10 - #define RTL9300_I2C_MST_DATA_WORD3 0x14 -- - #define RTL9300_I2C_MST_GLB_CTRL 0x384 - - static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len) - { -- u32 val, mask; - int ret; - -- val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS; -- mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK; -- -- ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); -+ ret = regmap_field_write(i2c->fields[F_MEM_ADDR_WIDTH], len); - if (ret) - return ret; - -- val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS; -- mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK; -+ return regmap_field_write(i2c->fields[F_MEM_ADDR], reg); -+} - -- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl) -+{ -+ return regmap_field_write(i2c->fields[F_SCL_SEL], 1); - } - - static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin) - { -+ struct rtl9300_i2c_drv_data *drv_data; - int ret; -- u32 val, mask; - -- ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin)); -+ drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -+ -+ ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_pin), BIT(sda_pin)); - if (ret) - return ret; - -- val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) | -- RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; -- mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL; -+ ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_pin); -+ if (ret) -+ return ret; - -- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+ return drv_data->select_scl(i2c, 0); - } - - static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan, - u16 addr, u16 len) - { -- u32 val, mask; -+ int ret; - - if (len < 1 || len > 16) - return -EINVAL; - -- val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS; -- mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK; -- -- val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS; -- mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK; -+ ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); -+ if (ret) -+ return ret; - -- val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS; -- mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK; -+ ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr); -+ if (ret) -+ return ret; - -- mask |= RTL9300_I2C_MST_CTRL2_RD_MODE; -+ ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf); -+ if (ret) -+ return ret; - -- return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val); -+ return regmap_field_write(i2c->fields[F_RD_MODE], 0); - } - - static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) -@@ -124,8 +144,7 @@ static int rtl9300_i2c_read(struct rtl93 - if (len > 16) - return -EIO; - -- ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, -- vals, ARRAY_SIZE(vals)); -+ ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals)); - if (ret) - return ret; - -@@ -152,52 +171,49 @@ static int rtl9300_i2c_write(struct rtl9 - vals[reg] |= buf[i] << shift; - } - -- return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, -- vals, ARRAY_SIZE(vals)); -+ return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals)); - } - - static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data) - { -- return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data); -+ return regmap_write(i2c->regmap, i2c->data_reg, data); - } - - static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, - int size, union i2c_smbus_data *data, int len) - { -- u32 val, mask; -+ u32 val; - int ret; - -- val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0; -- mask = RTL9300_I2C_MST_CTRL1_RWOP; -- -- val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; -- mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG; -+ ret = regmap_field_write(i2c->fields[F_RWOP], read_write == I2C_SMBUS_WRITE); -+ if (ret) -+ return ret; - -- ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val); -+ ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1); - if (ret) - return ret; - -- ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, -- val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000); -+ ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000); - if (ret) - return ret; - -- if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL) -+ ret = regmap_field_read(i2c->fields[F_I2C_FAIL], &val); -+ if (ret) -+ return ret; -+ if (val) - return -EIO; - - if (read_write == I2C_SMBUS_READ) { - switch (size) { - case I2C_SMBUS_BYTE: - case I2C_SMBUS_BYTE_DATA: -- ret = regmap_read(i2c->regmap, -- i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); -+ ret = regmap_read(i2c->regmap, i2c->data_reg, &val); - if (ret) - return ret; - data->byte = val & 0xff; - break; - case I2C_SMBUS_WORD_DATA: -- ret = regmap_read(i2c->regmap, -- i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val); -+ ret = regmap_read(i2c->regmap, i2c->data_reg, &val); - if (ret) - return ret; - data->word = val & 0xffff; -@@ -355,9 +371,11 @@ static int rtl9300_i2c_probe(struct plat - { - struct device *dev = &pdev->dev; - struct rtl9300_i2c *i2c; -+ struct fwnode_handle *child; -+ struct rtl9300_i2c_drv_data *drv_data; -+ struct reg_field fields[F_NUM_FIELDS]; - u32 clock_freq, sda_pin; - int ret, i = 0; -- struct fwnode_handle *child; - - i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) -@@ -376,9 +394,22 @@ static int rtl9300_i2c_probe(struct plat - - platform_set_drvdata(pdev, i2c); - -- if (device_get_child_node_count(dev) > RTL9300_I2C_MUX_NCHAN) -+ drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -+ if (device_get_child_node_count(dev) > drv_data->max_nchan) - return dev_err_probe(dev, -EINVAL, "Too many channels\n"); - -+ i2c->data_reg = i2c->reg_base + drv_data->data_reg; -+ for (i = 0; i < F_NUM_FIELDS; i++) { -+ fields[i] = drv_data->field_desc[i].field; -+ if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER) -+ fields[i].reg += i2c->reg_base; -+ } -+ ret = devm_regmap_field_bulk_alloc(dev, i2c->regmap, i2c->fields, -+ fields, F_NUM_FIELDS); -+ if (ret) -+ return ret; -+ -+ i = 0; - device_for_each_child_node(dev, child) { - struct rtl9300_i2c_chan *chan = &i2c->chans[i]; - struct i2c_adapter *adap = &chan->adap; -@@ -395,7 +426,6 @@ static int rtl9300_i2c_probe(struct plat - case I2C_MAX_STANDARD_MODE_FREQ: - chan->bus_freq = RTL9300_I2C_STD_FREQ; - break; -- - case I2C_MAX_FAST_MODE_FREQ: - chan->bus_freq = RTL9300_I2C_FAST_FREQ; - break; -@@ -427,11 +457,37 @@ static int rtl9300_i2c_probe(struct plat - return 0; - } - -+#define GLB_REG_FIELD(reg, msb, lsb) \ -+ { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_GLOBAL } -+#define MST_REG_FIELD(reg, msb, lsb) \ -+ { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_MASTER } -+ -+static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = { -+ .field_desc = { -+ [F_MEM_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 8, 31), -+ [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 4, 6), -+ [F_SCL_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 3, 3), -+ [F_RWOP] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 2, 2), -+ [F_I2C_FAIL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 1, 1), -+ [F_I2C_TRIG] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0), -+ [F_RD_MODE] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 15, 15), -+ [F_DEV_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 8, 14), -+ [F_DATA_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 4, 7), -+ [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3), -+ [F_SCL_FREQ] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1), -+ [F_SDA_SEL] = GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7), -+ }, -+ .select_scl = rtl9300_i2c_select_scl, -+ .data_reg = RTL9300_I2C_MST_DATA_WORD0, -+ .max_nchan = RTL9300_I2C_MUX_NCHAN, -+}; -+ -+ - static const struct of_device_id i2c_rtl9300_dt_ids[] = { -- { .compatible = "realtek,rtl9301-i2c" }, -- { .compatible = "realtek,rtl9302b-i2c" }, -- { .compatible = "realtek,rtl9302c-i2c" }, -- { .compatible = "realtek,rtl9303-i2c" }, -+ { .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data }, -+ { .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data }, -+ { .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data }, -+ { .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data }, - {} - }; - MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); diff --git a/target/linux/realtek/patches-6.18/008-02-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-fix-wording-and-.patch b/target/linux/realtek/patches-6.18/008-02-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-fix-wording-and-.patch deleted file mode 100644 index 1eefe48af0c..00000000000 --- a/target/linux/realtek/patches-6.18/008-02-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-fix-wording-and-.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 80f3e37d5e734bbfe891592bb669ceb5e8b314dc Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:24 +0000 -Subject: [PATCH] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos - -Fix wording of binding description to use plural because there is not -only a single RTL9300 SoC. RTL9300 describes a whole family of Realtek -SoCs. - -Add missing word 'of' in description of reg property. - -Change 'SDA pin' to 'SDA line number' because the property must contain -the SDA (channel) number ranging from 0-7 instead of a real pin number. - -Signed-off-by: Jonas Jelonek -Reviewed-by: Rob Herring (Arm) -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-3-jelonek.jonas@gmail.com - ---- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -@@ -10,7 +10,7 @@ maintainers: - - Chris Packham - - description: -- The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which -+ RTL9300 SoCs have two I2C controllers. Each of these has an SCL line (which - if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be - assigned to either I2C controller. - -@@ -27,7 +27,7 @@ properties: - - reg: - items: -- - description: Register offset and size this I2C controller. -+ - description: Register offset and size of this I2C controller. - - "#address-cells": - const: 1 -@@ -42,7 +42,7 @@ patternProperties: - - properties: - reg: -- description: The SDA pin associated with the I2C bus. -+ description: The SDA line number associated with the I2C bus. - maxItems: 1 - - required: diff --git a/target/linux/realtek/patches-6.18/008-03-v6.18-i2c-rtl9300-rename-internal-sda_pin-to-sda_num.patch b/target/linux/realtek/patches-6.18/008-03-v6.18-i2c-rtl9300-rename-internal-sda_pin-to-sda_num.patch deleted file mode 100644 index 37f09766ff0..00000000000 --- a/target/linux/realtek/patches-6.18/008-03-v6.18-i2c-rtl9300-rename-internal-sda_pin-to-sda_num.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 8ff3819d7edcd56e4c533b9391a156cd607048fa Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:25 +0000 -Subject: [PATCH] i2c: rtl9300: rename internal sda_pin to sda_num - -Rename the internally used 'sda_pin' to 'sda_num' to make it clear that -this is NOT the actual pin number of the GPIO pin but rather the logical -SDA channel number. Although the alternate function SDA_Y is sometimes -given with the GPIO number, this is not always the case. Thus, avoid any -confusion or misconfiguration by giving the variable the correct name. - -This follows the description change in the devicetree bindings. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-4-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -20,7 +20,7 @@ struct rtl9300_i2c_chan { - struct i2c_adapter adap; - struct rtl9300_i2c *i2c; - enum rtl9300_bus_freq bus_freq; -- u8 sda_pin; -+ u8 sda_num; - }; - - enum rtl9300_i2c_reg_scope { -@@ -67,7 +67,7 @@ struct rtl9300_i2c { - struct regmap_field *fields[F_NUM_FIELDS]; - u32 reg_base; - u32 data_reg; -- u8 sda_pin; -+ u8 sda_num; - struct mutex lock; - }; - -@@ -102,11 +102,11 @@ static int rtl9300_i2c_config_io(struct - - drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); - -- ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_pin), BIT(sda_pin)); -+ ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_num), BIT(sda_num)); - if (ret) - return ret; - -- ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_pin); -+ ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_num); - if (ret) - return ret; - -@@ -243,11 +243,11 @@ static int rtl9300_i2c_smbus_xfer(struct - int len = 0, ret; - - mutex_lock(&i2c->lock); -- if (chan->sda_pin != i2c->sda_pin) { -+ if (chan->sda_num != i2c->sda_num) { - ret = rtl9300_i2c_config_io(i2c, chan->sda_pin); - if (ret) - goto out_unlock; -- i2c->sda_pin = chan->sda_pin; -+ i2c->sda_num = chan->sda_num; - } - - switch (size) { -@@ -374,7 +374,7 @@ static int rtl9300_i2c_probe(struct plat - struct fwnode_handle *child; - struct rtl9300_i2c_drv_data *drv_data; - struct reg_field fields[F_NUM_FIELDS]; -- u32 clock_freq, sda_pin; -+ u32 clock_freq, sda_num; - int ret, i = 0; - - i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); -@@ -414,7 +414,7 @@ static int rtl9300_i2c_probe(struct plat - struct rtl9300_i2c_chan *chan = &i2c->chans[i]; - struct i2c_adapter *adap = &chan->adap; - -- ret = fwnode_property_read_u32(child, "reg", &sda_pin); -+ ret = fwnode_property_read_u32(child, "reg", &sda_num); - if (ret) - return ret; - -@@ -431,11 +431,11 @@ static int rtl9300_i2c_probe(struct plat - break; - default: - dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n", -- sda_pin, clock_freq); -+ sda_num, clock_freq); - break; - } - -- chan->sda_pin = sda_pin; -+ chan->sda_num = sda_num; - chan->i2c = i2c; - adap = &i2c->chans[i].adap; - adap->owner = THIS_MODULE; -@@ -445,14 +445,14 @@ static int rtl9300_i2c_probe(struct plat - adap->dev.parent = dev; - i2c_set_adapdata(adap, chan); - adap->dev.of_node = to_of_node(child); -- snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin); -+ snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num); - i++; - - ret = devm_i2c_add_adapter(dev, adap); - if (ret) - return ret; - } -- i2c->sda_pin = 0xff; -+ i2c->sda_num = 0xff; - - return 0; - } diff --git a/target/linux/realtek/patches-6.18/008-04-v6.18-i2c-rtl9300-move-setting-SCL-frequency-to-config_io.patch b/target/linux/realtek/patches-6.18/008-04-v6.18-i2c-rtl9300-move-setting-SCL-frequency-to-config_io.patch deleted file mode 100644 index 8620ce9fe04..00000000000 --- a/target/linux/realtek/patches-6.18/008-04-v6.18-i2c-rtl9300-move-setting-SCL-frequency-to-config_io.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 6b0549abc8582a81425f89a436def8e28d8d7dce Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:26 +0000 -Subject: [PATCH] i2c: rtl9300: move setting SCL frequency to config_io - -Move the register operation to set the SCL frequency to the -rtl9300_i2c_config_io function instead of the rtl9300_i2c_config_xfer -function. This rather belongs there next to selecting the current SDA -output line. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-5-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -95,18 +95,23 @@ static int rtl9300_i2c_select_scl(struct - return regmap_field_write(i2c->fields[F_SCL_SEL], 1); - } - --static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin) -+static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan) - { - struct rtl9300_i2c_drv_data *drv_data; - int ret; - - drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); - -- ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_num), BIT(sda_num)); -+ ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num), -+ BIT(chan->sda_num)); - if (ret) - return ret; - -- ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_num); -+ ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num); -+ if (ret) -+ return ret; -+ -+ ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); - if (ret) - return ret; - -@@ -121,10 +126,6 @@ static int rtl9300_i2c_config_xfer(struc - if (len < 1 || len > 16) - return -EINVAL; - -- ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); -- if (ret) -- return ret; -- - ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr); - if (ret) - return ret; -@@ -244,7 +245,7 @@ static int rtl9300_i2c_smbus_xfer(struct - - mutex_lock(&i2c->lock); - if (chan->sda_num != i2c->sda_num) { -- ret = rtl9300_i2c_config_io(i2c, chan->sda_pin); -+ ret = rtl9300_i2c_config_io(i2c, chan); - if (ret) - goto out_unlock; - i2c->sda_num = chan->sda_num; diff --git a/target/linux/realtek/patches-6.18/008-05-v6.18-i2c-rtl9300-do-not-set-read-mode-on-every-transfer.patch b/target/linux/realtek/patches-6.18/008-05-v6.18-i2c-rtl9300-do-not-set-read-mode-on-every-transfer.patch deleted file mode 100644 index 5dc6878e5b0..00000000000 --- a/target/linux/realtek/patches-6.18/008-05-v6.18-i2c-rtl9300-do-not-set-read-mode-on-every-transfer.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0cb24186d0ebd7dd12c070fed9d782bf7c6dfb1e Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:27 +0000 -Subject: [PATCH] i2c: rtl9300: do not set read mode on every transfer - -Move the operation to set the read mode from config_xfer to probe. - -The I2C controller of RTL9300 and RTL9310 support a legacy message mode -for READs with 'Read Address Data' instead of the standard format 'Write -Address ; Read Data'. There is no way to pass that via smbus_xfer, thus -there is no point in supported this in the driver and moreover no point -in setting this on every transaction. Setting this once in the probe -call is sufficient. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-6-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -130,11 +130,7 @@ static int rtl9300_i2c_config_xfer(struc - if (ret) - return ret; - -- ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf); -- if (ret) -- return ret; -- -- return regmap_field_write(i2c->fields[F_RD_MODE], 0); -+ return regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf); - } - - static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) -@@ -455,6 +451,11 @@ static int rtl9300_i2c_probe(struct plat - } - i2c->sda_num = 0xff; - -+ /* only use standard read format */ -+ ret = regmap_field_write(i2c->fields[F_RD_MODE], 0); -+ if (ret) -+ return ret; -+ - return 0; - } - diff --git a/target/linux/realtek/patches-6.18/008-06-v6.18-i2c-rtl9300-separate-xfer-configuration-and-executio.patch b/target/linux/realtek/patches-6.18/008-06-v6.18-i2c-rtl9300-separate-xfer-configuration-and-executio.patch deleted file mode 100644 index 2d329fdb4ca..00000000000 --- a/target/linux/realtek/patches-6.18/008-06-v6.18-i2c-rtl9300-separate-xfer-configuration-and-executio.patch +++ /dev/null @@ -1,382 +0,0 @@ -From 447dd46f95014eb4ea94f6164963bf23ce05b927 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:28 +0000 -Subject: [PATCH] i2c: rtl9300: separate xfer configuration and execution - -So far, the rtl9300_i2c_smbus_xfer code is quite a mess with function -calls distributed over the whole function setting different values in -different cases. Calls to rtl9300_i2c_config_xfer and -rtl9300_i2c_reg_addr_set are used in every case-block with varying -values whose meaning is not instantly obvious. In some cases, there are -additional calls within these case-blocks doing more things. - -This is in general a bad design and especially really bad for -readability and maintainability because it distributes changes or -issues to multiple locations due to the same function being called with -different hardcoded values in different places. - -To have a good structure, setting different parameters based on the -desired operation should not be interleaved with applying these -parameters to the hardware registers. Or in different words, the -parameter site should be mixed with the call site. - -Thus, separate configuration and execution of an SMBus xfer within -rtl9300_i2c_smbus_xfer to improve readability and maintainability. Add a -new 'struct rtl9300_i2c_xfer' to carry the required parameters for an -xfer which are configured based on the input parameters within a single -switch-case block, without having any function calls within this block. - -The function calls to actually apply these values to the hardware -registers then appear below in a single place and just operate on the -passed instance of 'struct rtl9300_i2c_xfer'. These are -'rtl9300_i2c_prepare_xfer' which combines applying all parameters of the -xfer to the corresponding register, and 'rtl9300_i2c_do_xfer' which -actually executes the xfer and does post-processing if needed. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-7-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - - enum rtl9300_bus_freq { - RTL9300_I2C_STD_FREQ, -@@ -71,6 +72,22 @@ struct rtl9300_i2c { - struct mutex lock; - }; - -+enum rtl9300_i2c_xfer_type { -+ RTL9300_I2C_XFER_BYTE, -+ RTL9300_I2C_XFER_WORD, -+ RTL9300_I2C_XFER_BLOCK, -+}; -+ -+struct rtl9300_i2c_xfer { -+ enum rtl9300_i2c_xfer_type type; -+ u16 dev_addr; -+ u8 reg_addr; -+ u8 reg_addr_len; -+ u8 *data; -+ u8 data_len; -+ bool write; -+}; -+ - #define RTL9300_I2C_MST_CTRL1 0x0 - #define RTL9300_I2C_MST_CTRL2 0x4 - #define RTL9300_I2C_MST_DATA_WORD0 0x8 -@@ -95,45 +112,37 @@ static int rtl9300_i2c_select_scl(struct - return regmap_field_write(i2c->fields[F_SCL_SEL], 1); - } - --static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan) -+static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan) - { - struct rtl9300_i2c_drv_data *drv_data; - int ret; - -- drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -+ if (i2c->sda_num == chan->sda_num) -+ return 0; - -- ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num), -- BIT(chan->sda_num)); -+ ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); - if (ret) - return ret; - -- ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num); -+ drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -+ ret = drv_data->select_scl(i2c, 0); - if (ret) - return ret; - -- ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); -+ ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num), -+ BIT(chan->sda_num)); - if (ret) - return ret; - -- return drv_data->select_scl(i2c, 0); --} -- --static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan, -- u16 addr, u16 len) --{ -- int ret; -- -- if (len < 1 || len > 16) -- return -EINVAL; -- -- ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr); -+ ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num); - if (ret) - return ret; - -- return regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf); -+ i2c->sda_num = chan->sda_num; -+ return 0; - } - --static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len) -+static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len) - { - u32 vals[4] = {}; - int i, ret; -@@ -153,7 +162,7 @@ static int rtl9300_i2c_read(struct rtl93 - return 0; - } - --static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len) -+static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len) - { - u32 vals[4] = {}; - int i; -@@ -176,16 +185,51 @@ static int rtl9300_i2c_writel(struct rtl - return regmap_write(i2c->regmap, i2c->data_reg, data); - } - --static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write, -- int size, union i2c_smbus_data *data, int len) -+static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer) - { -- u32 val; - int ret; - -- ret = regmap_field_write(i2c->fields[F_RWOP], read_write == I2C_SMBUS_WRITE); -+ if (xfer->data_len < 1 || xfer->data_len > 16) -+ return -EINVAL; -+ -+ ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr); - if (ret) - return ret; - -+ ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len); -+ if (ret) -+ return ret; -+ -+ ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write); -+ if (ret) -+ return ret; -+ -+ ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf); -+ if (ret) -+ return ret; -+ -+ if (xfer->write) { -+ switch (xfer->type) { -+ case RTL9300_I2C_XFER_BYTE: -+ ret = rtl9300_i2c_writel(i2c, *xfer->data); -+ break; -+ case RTL9300_I2C_XFER_WORD: -+ ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data)); -+ break; -+ default: -+ ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len); -+ break; -+ } -+ } -+ -+ return ret; -+} -+ -+static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer) -+{ -+ u32 val; -+ int ret; -+ - ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1); - if (ret) - return ret; -@@ -200,28 +244,24 @@ static int rtl9300_i2c_execute_xfer(stru - if (val) - return -EIO; - -- if (read_write == I2C_SMBUS_READ) { -- switch (size) { -- case I2C_SMBUS_BYTE: -- case I2C_SMBUS_BYTE_DATA: -+ if (!xfer->write) { -+ switch (xfer->type) { -+ case RTL9300_I2C_XFER_BYTE: - ret = regmap_read(i2c->regmap, i2c->data_reg, &val); - if (ret) - return ret; -- data->byte = val & 0xff; -+ -+ *xfer->data = val & 0xff; - break; -- case I2C_SMBUS_WORD_DATA: -+ case RTL9300_I2C_XFER_WORD: - ret = regmap_read(i2c->regmap, i2c->data_reg, &val); - if (ret) - return ret; -- data->word = val & 0xffff; -- break; -- case I2C_SMBUS_I2C_BLOCK_DATA: -- ret = rtl9300_i2c_read(i2c, &data->block[1], len); -- if (ret) -- return ret; -+ -+ put_unaligned(val & 0xffff, (u16*)xfer->data); - break; - default: -- ret = rtl9300_i2c_read(i2c, &data->block[0], len); -+ ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len); - if (ret) - return ret; - break; -@@ -237,108 +277,62 @@ static int rtl9300_i2c_smbus_xfer(struct - { - struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap); - struct rtl9300_i2c *i2c = chan->i2c; -- int len = 0, ret; -+ struct rtl9300_i2c_xfer xfer = {0}; -+ int ret; -+ -+ if (addr > 0x7f) -+ return -EINVAL; - - mutex_lock(&i2c->lock); -- if (chan->sda_num != i2c->sda_num) { -- ret = rtl9300_i2c_config_io(i2c, chan); -- if (ret) -- goto out_unlock; -- i2c->sda_num = chan->sda_num; -- } -+ -+ ret = rtl9300_i2c_config_chan(i2c, chan); -+ if (ret) -+ goto out_unlock; -+ -+ xfer.dev_addr = addr & 0x7f; -+ xfer.write = (read_write == I2C_SMBUS_WRITE); -+ xfer.reg_addr = command; -+ xfer.reg_addr_len = 1; - - switch (size) { - case I2C_SMBUS_BYTE: -- if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0); -- if (ret) -- goto out_unlock; -- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -- if (ret) -- goto out_unlock; -- } else { -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); -- if (ret) -- goto out_unlock; -- ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0); -- if (ret) -- goto out_unlock; -- } -+ xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command; -+ xfer.data_len = 1; -+ xfer.reg_addr = 0; -+ xfer.reg_addr_len = 0; -+ xfer.type = RTL9300_I2C_XFER_BYTE; - break; -- - case I2C_SMBUS_BYTE_DATA: -- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -- if (ret) -- goto out_unlock; -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1); -- if (ret) -- goto out_unlock; -- if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_writel(i2c, data->byte); -- if (ret) -- goto out_unlock; -- } -+ xfer.data = &data->byte; -+ xfer.data_len = 1; -+ xfer.type = RTL9300_I2C_XFER_BYTE; - break; -- - case I2C_SMBUS_WORD_DATA: -- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -- if (ret) -- goto out_unlock; -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2); -- if (ret) -- goto out_unlock; -- if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_writel(i2c, data->word); -- if (ret) -- goto out_unlock; -- } -+ xfer.data = (u8 *)&data->word; -+ xfer.data_len = 2; -+ xfer.type = RTL9300_I2C_XFER_WORD; - break; -- - case I2C_SMBUS_BLOCK_DATA: -- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -- if (ret) -- goto out_unlock; -- if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) { -- ret = -EINVAL; -- goto out_unlock; -- } -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1); -- if (ret) -- goto out_unlock; -- if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1); -- if (ret) -- goto out_unlock; -- } -- len = data->block[0] + 1; -+ xfer.data = &data->block[0]; -+ xfer.data_len = data->block[0] + 1; -+ xfer.type = RTL9300_I2C_XFER_BLOCK; - break; -- - case I2C_SMBUS_I2C_BLOCK_DATA: -- ret = rtl9300_i2c_reg_addr_set(i2c, command, 1); -- if (ret) -- goto out_unlock; -- if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) { -- ret = -EINVAL; -- goto out_unlock; -- } -- ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]); -- if (ret) -- goto out_unlock; -- if (read_write == I2C_SMBUS_WRITE) { -- ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]); -- if (ret) -- goto out_unlock; -- } -- len = data->block[0]; -+ xfer.data = &data->block[1]; -+ xfer.data_len = data->block[0]; -+ xfer.type = RTL9300_I2C_XFER_BLOCK; - break; -- - default: - dev_err(&adap->dev, "Unsupported transaction %d\n", size); - ret = -EOPNOTSUPP; - goto out_unlock; - } - -- ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len); -+ ret = rtl9300_i2c_prepare_xfer(i2c, &xfer); -+ if (ret) -+ goto out_unlock; -+ -+ ret = rtl9300_i2c_do_xfer(i2c, &xfer); - - out_unlock: - mutex_unlock(&i2c->lock); diff --git a/target/linux/realtek/patches-6.18/008-07-v6.18-i2c-rtl9300-use-scoped-guard-instead-of-explicit-loc.patch b/target/linux/realtek/patches-6.18/008-07-v6.18-i2c-rtl9300-use-scoped-guard-instead-of-explicit-loc.patch deleted file mode 100644 index 58552ca2106..00000000000 --- a/target/linux/realtek/patches-6.18/008-07-v6.18-i2c-rtl9300-use-scoped-guard-instead-of-explicit-loc.patch +++ /dev/null @@ -1,68 +0,0 @@ -From bcd5f0da57e6c47a884dcad94ad6b0e32cce8705 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:29 +0000 -Subject: [PATCH] i2c: rtl9300: use scoped guard instead of explicit - lock/unlock - -Use the scoped guard infrastructure which unlocks a mutex automatically -when the guard goes out of scope, instead of explicit lock and unlock. -This simplifies the code and control flow in rtl9300_i2c_smbus_xfer and -removes the need of using goto in error cases to unlock before -returning. - -Signed-off-by: Jonas Jelonek -Reviewed-by: Chris Packham -Tested-by: Chris Packham # On RTL9302C based board -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-8-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -72,6 +72,8 @@ struct rtl9300_i2c { - struct mutex lock; - }; - -+DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock)) -+ - enum rtl9300_i2c_xfer_type { - RTL9300_I2C_XFER_BYTE, - RTL9300_I2C_XFER_WORD, -@@ -283,11 +285,11 @@ static int rtl9300_i2c_smbus_xfer(struct - if (addr > 0x7f) - return -EINVAL; - -- mutex_lock(&i2c->lock); -+ guard(rtl9300_i2c)(i2c); - - ret = rtl9300_i2c_config_chan(i2c, chan); - if (ret) -- goto out_unlock; -+ return ret; - - xfer.dev_addr = addr & 0x7f; - xfer.write = (read_write == I2C_SMBUS_WRITE); -@@ -324,20 +326,14 @@ static int rtl9300_i2c_smbus_xfer(struct - break; - default: - dev_err(&adap->dev, "Unsupported transaction %d\n", size); -- ret = -EOPNOTSUPP; -- goto out_unlock; -+ return -EOPNOTSUPP; - } - - ret = rtl9300_i2c_prepare_xfer(i2c, &xfer); - if (ret) -- goto out_unlock; -- -- ret = rtl9300_i2c_do_xfer(i2c, &xfer); -- --out_unlock: -- mutex_unlock(&i2c->lock); -+ return ret; - -- return ret; -+ return rtl9300_i2c_do_xfer(i2c, &xfer); - } - - static u32 rtl9300_i2c_func(struct i2c_adapter *a) diff --git a/target/linux/realtek/patches-6.18/008-08-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-RTL93.patch b/target/linux/realtek/patches-6.18/008-08-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-RTL93.patch deleted file mode 100644 index 9bc6851e704..00000000000 --- a/target/linux/realtek/patches-6.18/008-08-v6.18-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-RTL93.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 17689aafb793599a862617a127429dd3d6f675c9 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:30 +0000 -Subject: [PATCH] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 - support - -Adjust the regex for child-node address to account for the fact that -RTL9310 supports 12 instead of only 8 SDA lines. Also, narrow this per -variant. - -Add a vendor-specific property to explicitly specify the SCL line number -of the defined I2C controller/master. This is required, in particular -for RTL9310, to operate on the correct SCL for each controller. Require -this property to be specified for RTL9310. - -Add compatibles for known SoC variants RTL9311, RTL9312 and RTL9313. - -Signed-off-by: Jonas Jelonek -Reviewed-by: Rob Herring (Arm) -Reviewed-by: Chris Packham -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-9-jelonek.jonas@gmail.com - ---- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml -@@ -13,6 +13,8 @@ description: - RTL9300 SoCs have two I2C controllers. Each of these has an SCL line (which - if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be - assigned to either I2C controller. -+ RTL9310 SoCs have equal capabilities but support 12 common SDA lines which -+ can be assigned to either I2C controller. - - properties: - compatible: -@@ -23,7 +25,15 @@ properties: - - realtek,rtl9302c-i2c - - realtek,rtl9303-i2c - - const: realtek,rtl9301-i2c -- - const: realtek,rtl9301-i2c -+ - items: -+ - enum: -+ - realtek,rtl9311-i2c -+ - realtek,rtl9312-i2c -+ - realtek,rtl9313-i2c -+ - const: realtek,rtl9310-i2c -+ - enum: -+ - realtek,rtl9301-i2c -+ - realtek,rtl9310-i2c - - reg: - items: -@@ -35,8 +45,14 @@ properties: - "#size-cells": - const: 0 - -+ realtek,scl: -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ description: -+ The SCL line number of this I2C controller. -+ enum: [ 0, 1 ] -+ - patternProperties: -- '^i2c@[0-7]$': -+ '^i2c@[0-9ab]$': - $ref: /schemas/i2c/i2c-controller.yaml - unevaluatedProperties: false - -@@ -48,6 +64,25 @@ patternProperties: - required: - - reg - -+ -+allOf: -+ - if: -+ properties: -+ compatible: -+ contains: -+ const: realtek,rtl9310-i2c -+ then: -+ required: -+ - realtek,scl -+ - if: -+ properties: -+ compatible: -+ contains: -+ const: realtek,rtl9301-i2c -+ then: -+ patternProperties: -+ '^i2c@[89ab]$': false -+ - required: - - compatible - - reg diff --git a/target/linux/realtek/patches-6.18/008-09-v6.18-i2c-rtl9300-add-support-for-RTL9310-I2C-controller.patch b/target/linux/realtek/patches-6.18/008-09-v6.18-i2c-rtl9300-add-support-for-RTL9310-I2C-controller.patch deleted file mode 100644 index 6d5a23c0e81..00000000000 --- a/target/linux/realtek/patches-6.18/008-09-v6.18-i2c-rtl9300-add-support-for-RTL9310-I2C-controller.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 8d43287120ce6437e7a77e735d99137f3fdb3ae9 Mon Sep 17 00:00:00 2001 -From: Jonas Jelonek -Date: Sat, 27 Sep 2025 10:19:31 +0000 -Subject: [PATCH] i2c: rtl9300: add support for RTL9310 I2C controller - -Add support for the internal I2C controllers of RTL9310 series based -SoCs to the driver for RTL9300. Add register definitions, chip-specific -functions and compatible strings for known RTL9310-based SoCs RTL9311, -RTL9312 and RTL9313. - -Make use of a new device tree property 'realtek,scl' which needs to be -specified in case both or only the second master is used. This is -required due how the register layout changed in contrast to RTL9300, -which has SCL selection in a global register instead of a -master-specific one. - -Signed-off-by: Jonas Jelonek -Tested-by: Sven Eckelmann -Reviewed-by: Chris Packham -Tested-by: Markus Stockhausen -Signed-off-by: Andi Shyti -Link: https://lore.kernel.org/r/20250927101931.71575-10-jelonek.jonas@gmail.com - ---- a/drivers/i2c/busses/i2c-rtl9300.c -+++ b/drivers/i2c/busses/i2c-rtl9300.c -@@ -60,14 +60,16 @@ struct rtl9300_i2c_drv_data { - }; - - #define RTL9300_I2C_MUX_NCHAN 8 -+#define RTL9310_I2C_MUX_NCHAN 12 - - struct rtl9300_i2c { - struct regmap *regmap; - struct device *dev; -- struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN]; -+ struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN]; - struct regmap_field *fields[F_NUM_FIELDS]; - u32 reg_base; - u32 data_reg; -+ u8 scl_num; - u8 sda_num; - struct mutex lock; - }; -@@ -98,6 +100,12 @@ struct rtl9300_i2c_xfer { - #define RTL9300_I2C_MST_DATA_WORD3 0x14 - #define RTL9300_I2C_MST_GLB_CTRL 0x384 - -+#define RTL9310_I2C_MST_IF_CTRL 0x1004 -+#define RTL9310_I2C_MST_IF_SEL 0x1008 -+#define RTL9310_I2C_MST_CTRL 0x0 -+#define RTL9310_I2C_MST_MEMADDR_CTRL 0x4 -+#define RTL9310_I2C_MST_DATA_CTRL 0x8 -+ - static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len) - { - int ret; -@@ -114,6 +122,11 @@ static int rtl9300_i2c_select_scl(struct - return regmap_field_write(i2c->fields[F_SCL_SEL], 1); - } - -+static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl) -+{ -+ return regmap_field_update_bits(i2c->fields[F_SCL_SEL], BIT(scl), BIT(scl)); -+} -+ - static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan) - { - struct rtl9300_i2c_drv_data *drv_data; -@@ -127,7 +140,7 @@ static int rtl9300_i2c_config_chan(struc - return ret; - - drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -- ret = drv_data->select_scl(i2c, 0); -+ ret = drv_data->select_scl(i2c, i2c->scl_num); - if (ret) - return ret; - -@@ -361,7 +374,7 @@ static int rtl9300_i2c_probe(struct plat - struct fwnode_handle *child; - struct rtl9300_i2c_drv_data *drv_data; - struct reg_field fields[F_NUM_FIELDS]; -- u32 clock_freq, sda_num; -+ u32 clock_freq, scl_num, sda_num; - int ret, i = 0; - - i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); -@@ -379,6 +392,11 @@ static int rtl9300_i2c_probe(struct plat - if (ret) - return ret; - -+ ret = device_property_read_u32(dev, "realtek,scl", &scl_num); -+ if (ret || scl_num != 1) -+ scl_num = 0; -+ i2c->scl_num = (u8)scl_num; -+ - platform_set_drvdata(pdev, i2c); - - drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); -@@ -474,12 +492,35 @@ static const struct rtl9300_i2c_drv_data - .max_nchan = RTL9300_I2C_MUX_NCHAN, - }; - -+static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = { -+ .field_desc = { -+ [F_SCL_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 12, 13), -+ [F_SDA_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 0, 11), -+ [F_SCL_FREQ] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 30, 31), -+ [F_DEV_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 11, 17), -+ [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 18, 21), -+ [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 9, 10), -+ [F_DATA_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 5, 8), -+ [F_RD_MODE] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 4, 4), -+ [F_RWOP] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 2, 2), -+ [F_I2C_FAIL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1), -+ [F_I2C_TRIG] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0), -+ [F_MEM_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23), -+ }, -+ .select_scl = rtl9310_i2c_select_scl, -+ .data_reg = RTL9310_I2C_MST_DATA_CTRL, -+ .max_nchan = RTL9310_I2C_MUX_NCHAN, -+}; - - static const struct of_device_id i2c_rtl9300_dt_ids[] = { - { .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data }, - { .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data }, - { .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data }, - { .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data }, -+ { .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data }, -+ { .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data }, -+ { .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data }, -+ { .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data }, - {} - }; - MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); diff --git a/target/linux/realtek/patches-6.18/020-02-v6.18-timer-rtl-otto-drop-set-counter-function.patch b/target/linux/realtek/patches-6.18/020-02-v6.18-timer-rtl-otto-drop-set-counter-function.patch deleted file mode 100644 index 5ee2f07f273..00000000000 --- a/target/linux/realtek/patches-6.18/020-02-v6.18-timer-rtl-otto-drop-set-counter-function.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 85e27f218121bdaa8e8afd68674262aa154d2cb4 Mon Sep 17 00:00:00 2001 -From: Markus Stockhausen -Date: Mon, 4 Aug 2025 04:03:26 -0400 -Subject: clocksource/drivers/timer-rtl-otto: Drop set_counter function -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The current counter value is a read only register. It will be -reset when writing a new target timer value with rttm_set_period(). -rttm_set_counter() is essentially a noop. Drop it. - -While this makes rttm_start_timer() and rttm_enable_timer() the -same functions keep both to make the established abstraction layers -for register and control functions active. - -Downstream has already tested and confirmed a patch. See -https://github.com/openwrt/openwrt/pull/19468 -https://forum.openwrt.org/t/support-for-rtl838x-based-managed-switches/57875/3788 - -Tested-by: Stephen Howell -Tested-by: Bjørn Mork -Signed-off-by: Markus Stockhausen -Link: https://lore.kernel.org/r/20250804080328.2609287-3-markus.stockhausen@gmx.de -Signed-off-by: Daniel Lezcano ---- - drivers/clocksource/timer-rtl-otto.c | 6 ------ - 1 file changed, 6 deletions(-) - ---- a/drivers/clocksource/timer-rtl-otto.c -+++ b/drivers/clocksource/timer-rtl-otto.c -@@ -56,11 +56,6 @@ struct rttm_cs { - }; - - /* Simple internal register functions */ --static inline void rttm_set_counter(void __iomem *base, unsigned int counter) --{ -- iowrite32(counter, base + RTTM_CNT); --} -- - static inline unsigned int rttm_get_counter(void __iomem *base) - { - return ioread32(base + RTTM_CNT); -@@ -137,7 +132,6 @@ static void rttm_stop_timer(void __iomem - - static void rttm_start_timer(struct timer_of *to, u32 mode) - { -- rttm_set_counter(to->of_base.base, 0); - rttm_enable_timer(to->of_base.base, mode, to->of_clk.rate / RTTM_TICKS_PER_SEC); - } - diff --git a/target/linux/realtek/patches-6.18/021-v6.18-mtd-nand-add-realtek-ecc-engine.patch b/target/linux/realtek/patches-6.18/021-v6.18-mtd-nand-add-realtek-ecc-engine.patch deleted file mode 100644 index 7c7811e7072..00000000000 --- a/target/linux/realtek/patches-6.18/021-v6.18-mtd-nand-add-realtek-ecc-engine.patch +++ /dev/null @@ -1,521 +0,0 @@ -From 3148d0e5b1c5733d69ec51b70c8280e46488750a Mon Sep 17 00:00:00 2001 -From: Markus Stockhausen -Date: Fri, 19 Sep 2025 03:52:01 -0400 -Subject: mtd: nand: realtek-ecc: Add Realtek external ECC engine support - -The Realtek RTl93xx switch SoC series has a built in ECC controller -that can provide BCH6 or BCH12 over 512 data and 6 tag bytes. It -generates 10 (BCH6) or 20 (BCH12) bytes of parity. - -This engine will most likely work in conjunction with the Realtek -spi-mem based NAND controller but can work on its own. Therefore -the initial implementation will be of type external. - -Remark! The engine can support any data blocks that are multiples -of 512 bytes. For now limit it to data+oob layouts that have been -analyzed from existing devices. This way it keeps compatibility -and pre-existing vendor data can be read. - -Signed-off-by: Markus Stockhausen -Signed-off-by: Miquel Raynal ---- - drivers/mtd/nand/Kconfig | 8 + - drivers/mtd/nand/Makefile | 1 + - drivers/mtd/nand/ecc-realtek.c | 464 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 473 insertions(+) - create mode 100644 drivers/mtd/nand/ecc-realtek.c - ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -65,6 +65,14 @@ config MTD_NAND_ECC_MEDIATEK - help - This enables support for the hardware ECC engine from Mediatek. - -+config MTD_NAND_ECC_REALTEK -+ tristate "Realtek RTL93xx hardware ECC engine" -+ depends on HAS_IOMEM -+ depends on MACH_REALTEK_RTL || COMPILE_TEST -+ select MTD_NAND_ECC -+ help -+ This enables support for the hardware ECC engine from Realtek. -+ - endmenu - - endmenu ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -2,6 +2,7 @@ - - nandcore-objs := core.o bbt.o - obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o -+obj-$(CONFIG_MTD_NAND_ECC_REALTEK) += ecc-realtek.o - obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o - obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o - obj-$(CONFIG_SPI_QPIC_SNAND) += qpic_common.o ---- /dev/null -+++ b/drivers/mtd/nand/ecc-realtek.c -@@ -0,0 +1,464 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Support for Realtek hardware ECC engine in RTL93xx SoCs -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * The Realtek ECC engine has two operation modes. -+ * -+ * - BCH6 : Generate 10 ECC bytes from 512 data bytes plus 6 free bytes -+ * - BCH12 : Generate 20 ECC bytes from 512 data bytes plus 6 free bytes -+ * -+ * It can run for arbitrary NAND flash chips with different block and OOB sizes. Currently there -+ * are only two known devices in the wild that have NAND flash and make use of this ECC engine -+ * (Linksys LGS328C & LGS352C). To keep compatibility with vendor firmware, new modes can only -+ * be added when new data layouts have been analyzed. For now allow BCH6 on flash with 2048 byte -+ * blocks and 64 bytes oob. -+ * -+ * This driver aligns with kernel ECC naming conventions. Neverthless a short notice on the -+ * Realtek naming conventions for the different structures in the OOB area. -+ * -+ * - BBI : Bad block indicator. The first two bytes of OOB. Protected by ECC! -+ * - tag : 6 User/free bytes. First tag "contains" 2 bytes BBI. Protected by ECC! -+ * - syndrome : ECC/parity bytes -+ * -+ * Altogether this gives currently the following block layout. -+ * -+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ -+ * | 512 | 512 | 512 | 512 | 2 | 4 | 6 | 6 | 6 | 10 | 10 | 10 | 10 | -+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ -+ * | data | data | data | data | BBI | free | free | free | free | ECC | ECC | ECC | ECC | -+ * +------+------+------+------+-----+------+------+------+------+-----+-----+-----+-----+ -+ */ -+ -+#define RTL_ECC_ALLOWED_PAGE_SIZE 2048 -+#define RTL_ECC_ALLOWED_OOB_SIZE 64 -+#define RTL_ECC_ALLOWED_STRENGTH 6 -+ -+#define RTL_ECC_BLOCK_SIZE 512 -+#define RTL_ECC_FREE_SIZE 6 -+#define RTL_ECC_PARITY_SIZE_BCH6 10 -+#define RTL_ECC_PARITY_SIZE_BCH12 20 -+ -+/* -+ * The engine is fed with two DMA regions. One for data (always 512 bytes) and one for free bytes -+ * and parity (either 16 bytes for BCH6 or 26 bytes for BCH12). Start and length of each must be -+ * aligned to a multiple of 4. -+ */ -+ -+#define RTL_ECC_DMA_FREE_PARITY_SIZE ALIGN(RTL_ECC_FREE_SIZE + RTL_ECC_PARITY_SIZE_BCH12, 4) -+#define RTL_ECC_DMA_SIZE (RTL_ECC_BLOCK_SIZE + RTL_ECC_DMA_FREE_PARITY_SIZE) -+ -+#define RTL_ECC_CFG 0x00 -+#define RTL_ECC_BCH6 0 -+#define RTL_ECC_BCH12 BIT(28) -+#define RTL_ECC_DMA_PRECISE BIT(12) -+#define RTL_ECC_BURST_128 GENMASK(1, 0) -+#define RTL_ECC_DMA_TRIGGER 0x08 -+#define RTL_ECC_OP_DECODE 0 -+#define RTL_ECC_OP_ENCODE BIT(0) -+#define RTL_ECC_DMA_START 0x0c -+#define RTL_ECC_DMA_TAG 0x10 -+#define RTL_ECC_STATUS 0x14 -+#define RTL_ECC_CORR_COUNT GENMASK(19, 12) -+#define RTL_ECC_RESULT BIT(8) -+#define RTL_ECC_ALL_ONE BIT(4) -+#define RTL_ECC_OP_STATUS BIT(0) -+ -+struct rtl_ecc_engine { -+ struct device *dev; -+ struct nand_ecc_engine engine; -+ struct mutex lock; -+ char *buf; -+ dma_addr_t buf_dma; -+ struct regmap *regmap; -+}; -+ -+struct rtl_ecc_ctx { -+ struct rtl_ecc_engine * rtlc; -+ struct nand_ecc_req_tweak_ctx req_ctx; -+ int steps; -+ int bch_mode; -+ int strength; -+ int parity_size; -+}; -+ -+static const struct regmap_config rtl_ecc_regmap_config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+}; -+ -+static inline void *nand_to_ctx(struct nand_device *nand) -+{ -+ return nand->ecc.ctx.priv; -+} -+ -+static inline struct rtl_ecc_engine *nand_to_rtlc(struct nand_device *nand) -+{ -+ struct nand_ecc_engine *eng = nand->ecc.engine; -+ -+ return container_of(eng, struct rtl_ecc_engine, engine); -+} -+ -+static int rtl_ecc_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ struct nand_device *nand = mtd_to_nanddev(mtd); -+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); -+ -+ if (section < 0 || section >= ctx->steps) -+ return -ERANGE; -+ -+ oobregion->offset = ctx->steps * RTL_ECC_FREE_SIZE + section * ctx->parity_size; -+ oobregion->length = ctx->parity_size; -+ -+ return 0; -+} -+ -+static int rtl_ecc_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *oobregion) -+{ -+ struct nand_device *nand = mtd_to_nanddev(mtd); -+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); -+ int bbm; -+ -+ if (section < 0 || section >= ctx->steps) -+ return -ERANGE; -+ -+ /* reserve 2 BBM bytes in first block */ -+ bbm = section ? 0 : 2; -+ oobregion->offset = section * RTL_ECC_FREE_SIZE + bbm; -+ oobregion->length = RTL_ECC_FREE_SIZE - bbm; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops rtl_ecc_ooblayout_ops = { -+ .ecc = rtl_ecc_ooblayout_ecc, -+ .free = rtl_ecc_ooblayout_free, -+}; -+ -+static void rtl_ecc_kick_engine(struct rtl_ecc_ctx *ctx, int operation) -+{ -+ struct rtl_ecc_engine *rtlc = ctx->rtlc; -+ -+ regmap_write(rtlc->regmap, RTL_ECC_CFG, -+ ctx->bch_mode | RTL_ECC_BURST_128 | RTL_ECC_DMA_PRECISE); -+ -+ regmap_write(rtlc->regmap, RTL_ECC_DMA_START, rtlc->buf_dma); -+ regmap_write(rtlc->regmap, RTL_ECC_DMA_TAG, rtlc->buf_dma + RTL_ECC_BLOCK_SIZE); -+ regmap_write(rtlc->regmap, RTL_ECC_DMA_TRIGGER, operation); -+} -+ -+static int rtl_ecc_wait_for_engine(struct rtl_ecc_ctx *ctx) -+{ -+ struct rtl_ecc_engine *rtlc = ctx->rtlc; -+ int ret, status, bitflips; -+ bool all_one; -+ -+ /* -+ * The ECC engine needs 6-8 us to encode/decode a BCH6 syndrome for 512 bytes of data -+ * and 6 free bytes. In case the NAND area has been erased and all data and oob is -+ * set to 0xff, decoding takes 30us (reason unknown). Although the engine can trigger -+ * interrupts when finished, use active polling for now. 12 us maximum wait time has -+ * proven to be a good tradeoff between performance and overhead. -+ */ -+ -+ ret = regmap_read_poll_timeout(rtlc->regmap, RTL_ECC_STATUS, status, -+ !(status & RTL_ECC_OP_STATUS), 12, 1000000); -+ if (ret) -+ return ret; -+ -+ ret = FIELD_GET(RTL_ECC_RESULT, status); -+ all_one = FIELD_GET(RTL_ECC_ALL_ONE, status); -+ bitflips = FIELD_GET(RTL_ECC_CORR_COUNT, status); -+ -+ /* For erased blocks (all bits one) error status can be ignored */ -+ if (all_one) -+ ret = 0; -+ -+ return ret ? -EBADMSG : bitflips; -+} -+ -+static int rtl_ecc_run_engine(struct rtl_ecc_ctx *ctx, char *data, char *free, -+ char *parity, int operation) -+{ -+ struct rtl_ecc_engine *rtlc = ctx->rtlc; -+ char *buf_parity = rtlc->buf + RTL_ECC_BLOCK_SIZE + RTL_ECC_FREE_SIZE; -+ char *buf_free = rtlc->buf + RTL_ECC_BLOCK_SIZE; -+ char *buf_data = rtlc->buf; -+ int ret; -+ -+ mutex_lock(&rtlc->lock); -+ -+ memcpy(buf_data, data, RTL_ECC_BLOCK_SIZE); -+ memcpy(buf_free, free, RTL_ECC_FREE_SIZE); -+ memcpy(buf_parity, parity, ctx->parity_size); -+ -+ dma_sync_single_for_device(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_TO_DEVICE); -+ rtl_ecc_kick_engine(ctx, operation); -+ ret = rtl_ecc_wait_for_engine(ctx); -+ dma_sync_single_for_cpu(rtlc->dev, rtlc->buf_dma, RTL_ECC_DMA_SIZE, DMA_FROM_DEVICE); -+ -+ if (ret >= 0) { -+ memcpy(data, buf_data, RTL_ECC_BLOCK_SIZE); -+ memcpy(free, buf_free, RTL_ECC_FREE_SIZE); -+ memcpy(parity, buf_parity, ctx->parity_size); -+ } -+ -+ mutex_unlock(&rtlc->lock); -+ -+ return ret; -+} -+ -+static int rtl_ecc_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req) -+{ -+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); -+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); -+ char *data, *free, *parity; -+ int ret = 0; -+ -+ if (req->mode == MTD_OPS_RAW) -+ return 0; -+ -+ nand_ecc_tweak_req(&ctx->req_ctx, req); -+ -+ if (req->type == NAND_PAGE_READ) -+ return 0; -+ -+ free = req->oobbuf.in; -+ data = req->databuf.in; -+ parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE; -+ -+ for (int i = 0; i < ctx->steps; i++) { -+ ret |= rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_ENCODE); -+ -+ free += RTL_ECC_FREE_SIZE; -+ data += RTL_ECC_BLOCK_SIZE; -+ parity += ctx->parity_size; -+ } -+ -+ if (unlikely(ret)) -+ dev_dbg(rtlc->dev, "ECC calculation failed\n"); -+ -+ return ret ? -EBADMSG : 0; -+} -+ -+static int rtl_ecc_finish_io_req(struct nand_device *nand, struct nand_page_io_req *req) -+{ -+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); -+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); -+ struct mtd_info *mtd = nanddev_to_mtd(nand); -+ char *data, *free, *parity; -+ bool failure = false; -+ int bitflips = 0; -+ -+ if (req->mode == MTD_OPS_RAW) -+ return 0; -+ -+ if (req->type == NAND_PAGE_WRITE) { -+ nand_ecc_restore_req(&ctx->req_ctx, req); -+ return 0; -+ } -+ -+ free = req->oobbuf.in; -+ data = req->databuf.in; -+ parity = req->oobbuf.in + ctx->steps * RTL_ECC_FREE_SIZE; -+ -+ for (int i = 0 ; i < ctx->steps; i++) { -+ int ret = rtl_ecc_run_engine(ctx, data, free, parity, RTL_ECC_OP_DECODE); -+ -+ if (unlikely(ret < 0)) -+ /* ECC totally fails for bitflips in erased blocks */ -+ ret = nand_check_erased_ecc_chunk(data, RTL_ECC_BLOCK_SIZE, -+ parity, ctx->parity_size, -+ free, RTL_ECC_FREE_SIZE, -+ ctx->strength); -+ if (unlikely(ret < 0)) { -+ failure = true; -+ mtd->ecc_stats.failed++; -+ } else { -+ mtd->ecc_stats.corrected += ret; -+ bitflips = max_t(unsigned int, bitflips, ret); -+ } -+ -+ free += RTL_ECC_FREE_SIZE; -+ data += RTL_ECC_BLOCK_SIZE; -+ parity += ctx->parity_size; -+ } -+ -+ nand_ecc_restore_req(&ctx->req_ctx, req); -+ -+ if (unlikely(failure)) -+ dev_dbg(rtlc->dev, "ECC correction failed\n"); -+ else if (unlikely(bitflips > 2)) -+ dev_dbg(rtlc->dev, "%d bitflips detected\n", bitflips); -+ -+ return failure ? -EBADMSG : bitflips; -+} -+ -+static int rtl_ecc_check_support(struct nand_device *nand) -+{ -+ struct mtd_info *mtd = nanddev_to_mtd(nand); -+ struct device *dev = nand->ecc.engine->dev; -+ -+ if (mtd->oobsize != RTL_ECC_ALLOWED_OOB_SIZE || -+ mtd->writesize != RTL_ECC_ALLOWED_PAGE_SIZE) { -+ dev_err(dev, "only flash geometry data=%d, oob=%d supported\n", -+ RTL_ECC_ALLOWED_PAGE_SIZE, RTL_ECC_ALLOWED_OOB_SIZE); -+ return -EINVAL; -+ } -+ -+ if (nand->ecc.user_conf.algo != NAND_ECC_ALGO_BCH || -+ nand->ecc.user_conf.strength != RTL_ECC_ALLOWED_STRENGTH || -+ nand->ecc.user_conf.placement != NAND_ECC_PLACEMENT_OOB || -+ nand->ecc.user_conf.step_size != RTL_ECC_BLOCK_SIZE) { -+ dev_err(dev, "only algo=bch, strength=%d, placement=oob, step=%d supported\n", -+ RTL_ECC_ALLOWED_STRENGTH, RTL_ECC_BLOCK_SIZE); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rtl_ecc_init_ctx(struct nand_device *nand) -+{ -+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf; -+ struct rtl_ecc_engine *rtlc = nand_to_rtlc(nand); -+ struct mtd_info *mtd = nanddev_to_mtd(nand); -+ int strength = nand->ecc.user_conf.strength; -+ struct device *dev = nand->ecc.engine->dev; -+ struct rtl_ecc_ctx *ctx; -+ int ret; -+ -+ ret = rtl_ecc_check_support(nand); -+ if (ret) -+ return ret; -+ -+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ -+ nand->ecc.ctx.priv = ctx; -+ mtd_set_ooblayout(mtd, &rtl_ecc_ooblayout_ops); -+ -+ conf->algo = NAND_ECC_ALGO_BCH; -+ conf->strength = strength; -+ conf->step_size = RTL_ECC_BLOCK_SIZE; -+ conf->engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; -+ -+ ctx->rtlc = rtlc; -+ ctx->steps = mtd->writesize / RTL_ECC_BLOCK_SIZE; -+ ctx->strength = strength; -+ ctx->bch_mode = strength == 6 ? RTL_ECC_BCH6 : RTL_ECC_BCH12; -+ ctx->parity_size = strength == 6 ? RTL_ECC_PARITY_SIZE_BCH6 : RTL_ECC_PARITY_SIZE_BCH12; -+ -+ ret = nand_ecc_init_req_tweaking(&ctx->req_ctx, nand); -+ if (ret) -+ return ret; -+ -+ dev_dbg(dev, "using bch%d with geometry data=%dx%d, free=%dx6, parity=%dx%d", -+ conf->strength, ctx->steps, conf->step_size, -+ ctx->steps, ctx->steps, ctx->parity_size); -+ -+ return 0; -+} -+ -+static void rtl_ecc_cleanup_ctx(struct nand_device *nand) -+{ -+ struct rtl_ecc_ctx *ctx = nand_to_ctx(nand); -+ -+ if (ctx) -+ nand_ecc_cleanup_req_tweaking(&ctx->req_ctx); -+} -+ -+static struct nand_ecc_engine_ops rtl_ecc_engine_ops = { -+ .init_ctx = rtl_ecc_init_ctx, -+ .cleanup_ctx = rtl_ecc_cleanup_ctx, -+ .prepare_io_req = rtl_ecc_prepare_io_req, -+ .finish_io_req = rtl_ecc_finish_io_req, -+}; -+ -+static int rtl_ecc_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct rtl_ecc_engine *rtlc; -+ void __iomem *base; -+ int ret; -+ -+ rtlc = devm_kzalloc(dev, sizeof(*rtlc), GFP_KERNEL); -+ if (!rtlc) -+ return -ENOMEM; -+ -+ base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ ret = devm_mutex_init(dev, &rtlc->lock); -+ if (ret) -+ return ret; -+ -+ rtlc->regmap = devm_regmap_init_mmio(dev, base, &rtl_ecc_regmap_config); -+ if (IS_ERR(rtlc->regmap)) -+ return PTR_ERR(rtlc->regmap); -+ -+ /* -+ * Focus on simplicity and use a preallocated DMA buffer for data exchange with the -+ * engine. For now make it a noncoherent memory model as invalidating/flushing caches -+ * is faster than reading/writing uncached memory on the known architectures. -+ */ -+ -+ rtlc->buf = dma_alloc_noncoherent(dev, RTL_ECC_DMA_SIZE, &rtlc->buf_dma, -+ DMA_BIDIRECTIONAL, GFP_KERNEL); -+ if (IS_ERR(rtlc->buf)) -+ return PTR_ERR(rtlc->buf); -+ -+ rtlc->dev = dev; -+ rtlc->engine.dev = dev; -+ rtlc->engine.ops = &rtl_ecc_engine_ops; -+ rtlc->engine.integration = NAND_ECC_ENGINE_INTEGRATION_EXTERNAL; -+ -+ nand_ecc_register_on_host_hw_engine(&rtlc->engine); -+ -+ platform_set_drvdata(pdev, rtlc); -+ -+ return 0; -+} -+ -+static void rtl_ecc_remove(struct platform_device *pdev) -+{ -+ struct rtl_ecc_engine *rtlc = platform_get_drvdata(pdev); -+ -+ nand_ecc_unregister_on_host_hw_engine(&rtlc->engine); -+ dma_free_noncoherent(rtlc->dev, RTL_ECC_DMA_SIZE, rtlc->buf, rtlc->buf_dma, -+ DMA_BIDIRECTIONAL); -+} -+ -+static const struct of_device_id rtl_ecc_of_ids[] = { -+ { -+ .compatible = "realtek,rtl9301-ecc", -+ }, -+ { /* sentinel */ }, -+}; -+ -+static struct platform_driver rtl_ecc_driver = { -+ .driver = { -+ .name = "rtl-nand-ecc-engine", -+ .of_match_table = rtl_ecc_of_ids, -+ }, -+ .probe = rtl_ecc_probe, -+ .remove = rtl_ecc_remove, -+}; -+module_platform_driver(rtl_ecc_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Markus Stockhausen "); -+MODULE_DESCRIPTION("Realtek NAND hardware ECC controller"); diff --git a/target/linux/realtek/patches-6.18/302-6.17-irqchip-mips-gic-forced-affinity.patch b/target/linux/realtek/patches-6.18/302-6.17-irqchip-mips-gic-forced-affinity.patch deleted file mode 100644 index cf04d60703b..00000000000 --- a/target/linux/realtek/patches-6.18/302-6.17-irqchip-mips-gic-forced-affinity.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 2250db8628a0d8293ad2e0671138b848a185fba1 Mon Sep 17 00:00:00 2001 -From: Markus Stockhausen -Date: Sat, 21 Jun 2025 01:49:51 -0400 -Subject: irqchip/mips-gic: Allow forced affinity - -Devices of the Realtek MIPS Otto platform use the official rtl-otto-timer -as clock event generator and CPU clocksource. It is registered for each CPU -startup via cpuhp_setup_state() and forces the affinity of the clockevent -interrupts to the appropriate CPU via irq_force_affinity(). - -On the "smaller" devices with a vendor specific interrupt controller -(supported by irq-realtek-rtl) the registration works fine. The "larger" -RTL931x series is based on a MIPS interAptiv dual core with a MIPS GIC -controller. Interrupt routing setup is cancelled because gic_set_affinity() -does not accept the current (not yet online) CPU as a target. - -Relax the checks by evaluating the force parameter that is provided for -exactly this purpose like in other drivers. With this the affinity can be -set as follows: - - - force = false: allow to set affinity to any online cpu - - force = true: allow to set affinity to any cpu - -Co-developed-by: Sebastian Gottschall -Signed-off-by: Sebastian Gottschall -Signed-off-by: Markus Stockhausen -Signed-off-by: Thomas Gleixner -Link: https://lore.kernel.org/all/20250621054952.380374-1-markus.stockhausen@gmx.de ---- - drivers/irqchip/irq-mips-gic.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - ---- a/drivers/irqchip/irq-mips-gic.c -+++ b/drivers/irqchip/irq-mips-gic.c -@@ -263,7 +263,11 @@ static int gic_set_affinity(struct irq_d - unsigned long flags; - unsigned int cpu; - -- cpu = cpumask_first_and(cpumask, cpu_online_mask); -+ if (force) -+ cpu = cpumask_first(cpumask); -+ else -+ cpu = cpumask_first_and(cpumask, cpu_online_mask); -+ - if (cpu >= NR_CPUS) - return -EINVAL; -