From: Markus Stockhausen Date: Mon, 28 Jul 2025 14:13:26 +0000 (-0400) Subject: realtek: backport NAND driver for RTL93xx X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=41b0340ff084321a4b39df8cb2cf624dd7acc57f;p=thirdparty%2Fopenwrt.git realtek: backport NAND driver for RTL93xx RTL93xx devices have a NAND controller built in. Upstream already has a driver in place. Include it downstream. Activate it in the RTL93xx builds and disable it for the RTL83xx builds. Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/19583 Signed-off-by: Robert Marko --- diff --git a/target/linux/realtek/patches-6.12/001-v6.13-spi-mem-add-realtek-nand-controller.patch b/target/linux/realtek/patches-6.12/001-v6.13-spi-mem-add-realtek-nand-controller.patch new file mode 100644 index 00000000000..ab630a0ee4c --- /dev/null +++ b/target/linux/realtek/patches-6.12/001-v6.13-spi-mem-add-realtek-nand-controller.patch @@ -0,0 +1,481 @@ +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 +@@ -19494,6 +19494,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.12/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch b/target/linux/realtek/patches-6.12/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch new file mode 100644 index 00000000000..a929c670974 --- /dev/null +++ b/target/linux/realtek/patches-6.12/002-v6.13-spi-mem-rtl-snand-correctly-handle-dma-transfers.patch @@ -0,0 +1,96 @@ +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/rtl838x/config-6.12 b/target/linux/realtek/rtl838x/config-6.12 index 6676ae96606..a7cd07212ce 100644 --- a/target/linux/realtek/rtl838x/config-6.12 +++ b/target/linux/realtek/rtl838x/config-6.12 @@ -226,6 +226,7 @@ CONFIG_SFP=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y +# CONFIG_SPI_REALTEK_SNAND is not set CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SRAM=y CONFIG_SWPHY=y diff --git a/target/linux/realtek/rtl839x/config-6.12 b/target/linux/realtek/rtl839x/config-6.12 index de849a41c1c..15a01c87dad 100644 --- a/target/linux/realtek/rtl839x/config-6.12 +++ b/target/linux/realtek/rtl839x/config-6.12 @@ -239,6 +239,7 @@ CONFIG_SOCK_RX_QUEUE_MAPPING=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y +# CONFIG_SPI_REALTEK_SNAND is not set CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SRAM=y CONFIG_SWPHY=y diff --git a/target/linux/realtek/rtl930x/config-6.12 b/target/linux/realtek/rtl930x/config-6.12 index 531360df5ff..74eeac1f005 100644 --- a/target/linux/realtek/rtl930x/config-6.12 +++ b/target/linux/realtek/rtl930x/config-6.12 @@ -137,6 +137,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_SPI_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_BRNIMAGE_FW=y CONFIG_MTD_SPLIT_EVA_FW=y @@ -206,6 +207,7 @@ CONFIG_SFP=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y +CONFIG_SPI_REALTEK_SNAND=y CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SWPHY=y CONFIG_SYSCTL_EXCEPTION_TRACE=y diff --git a/target/linux/realtek/rtl931x/config-6.12 b/target/linux/realtek/rtl931x/config-6.12 index 8d79bcbec22..8d2a3553b47 100644 --- a/target/linux/realtek/rtl931x/config-6.12 +++ b/target/linux/realtek/rtl931x/config-6.12 @@ -153,6 +153,7 @@ CONFIG_MTD_CFI_ADV_OPTIONS=y CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_SPI_NAND=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_SPLIT_BRNIMAGE_FW=y CONFIG_MTD_SPLIT_EVA_FW=y @@ -227,6 +228,7 @@ CONFIG_SOCK_RX_QUEUE_MAPPING=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MEM=y +CONFIG_SPI_REALTEK_SNAND=y CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SWPHY=y CONFIG_SYNC_R4K=y