Skip to contentSkip to conversation

mtd: rawnand: loongson: Add Loongson-2K nand controller support

PATCH Superseded Binbin Zhou 3 participants 12 messages Aug 21, 2025 – Aug 25, 2025

Subsystems (5)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover mtd: rawnand: loongson: Add Loongson-2K nand controller support

Hi all:

This patchset adds support for the Loongson-2K0500/Loongson-2K1000 NAND controllers, which are similar to the Loongson-1C NAND controller.

They support a maximum capacity of 16GB FLASH per chip, with a maximum page size of 8KB. The chip supports up to 4 chip selects and 4 RDY signals.

The key difference between the Loongson-2K NAND controllers is that the Loongson-2K1000 explicitly configures the DMA controller routing, while the Loongson-2K0500 defaults to using APBDMA0.

Summary of the patchset:
Ptach 1: Rename all prefixes from ls1x to loongson Patch 2: Add 6-byte NAND ID reading
Patch 3: Add chip select support
Patch 4-5: Add Loongson-2K0500 NAND controller support Patch 6-7: Add Loongson-2K1000 NAND controller support

Thanks.

-------
V3:
Patch (1/7):
- Merge the first two rename patches;
Patch (3/7)
- Refact chip capacity calculation. Use a big switch-case

    for writesize, and sort the big switch-case by writesize;

- Drop the redundant 'nand_cs = 0x0';
Patch (6/7)
- Add Reviewed-by tag from Rob, thanks.

Link to V2:
https://lore.kernel.org/all/[email protected]/

V2:
Patch (5/8):
- Add Acked-by tag from Rob, thanks;
Patch (7/8):
- Update reg-names attribute description.

Link to V1:
https://lore.kernel.org/all/[email protected]/

Binbin Zhou (6):
mtd: rawnand: loongson1: Rename the prefix from ls1x to loongson
mtd: rawnand: loongson: Add nand chip select support
dt-bindings: mtd: loongson,ls1b-nand-controller: Document the
Loongson-2K0500 NAND controller
mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support
dt-bindings: mtd: loongson,ls1b-nand-controller: Document the
Loongson-2K1000 NAND controller
mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support

Keguang Zhang (1):
mtd: rawnand: loongson: Add 6-byte NAND ID reading support

 .../mtd/loongson,ls1b-nand-controller.yaml    |   56 +-
 MAINTAINERS                                   |    2 +-
 drivers/mtd/nand/raw/Kconfig                  |    8 +-
 drivers/mtd/nand/raw/Makefile                 |    2 +-
 .../mtd/nand/raw/loongson-nand-controller.c   | 1021 +++++++++++++++++
 .../mtd/nand/raw/loongson1-nand-controller.c  |  836 --------------
 6 files changed, 1080 insertions(+), 845 deletions(-)
 create mode 100644 drivers/mtd/nand/raw/loongson-nand-controller.c
 delete mode 100644 drivers/mtd/nand/raw/loongson1-nand-controller.c

base-commit: fb2fae70e7e985c4acb1ad96110d8b98bb64a87c

Signature · 1 line
2.47.3
#1 lore raw

PATCH v3 1/7 mtd: rawnand: loongson1: Rename the prefix from ls1x to loongson

I am going to introduce the NAND controllers of the Loongson-2K series CPUs, which are similar to Loongson-1.

As preparation, rename all prefixes from Loongson1-specific to Loongson-generic.

No functional change intended.

---
 MAINTAINERS                                   |   2 +-
 drivers/mtd/nand/raw/Kconfig                  |   6 +-
 drivers/mtd/nand/raw/Makefile                 |   2 +-
 ...ontroller.c => loongson-nand-controller.c} | 337 +++++++++---------
 4 files changed, 177 insertions(+), 170 deletions(-)
 rename drivers/mtd/nand/raw/{loongson1-nand-controller.c => loongson-nand-controller.c} (61%)
MAINTAINERS +1 -1
index 4bac4ea21b64..cc502582c9f1 100644
@@ -16722,7 +16722,7 @@ F:	Documentation/devicetree/bindings/*/loongson,ls1*.yaml
 F:	arch/mips/include/asm/mach-loongson32/
 F:	arch/mips/loongson32/
 F:	drivers/*/*loongson1*
-F:	drivers/mtd/nand/raw/loongson1-nand-controller.c
+F:	drivers/mtd/nand/raw/loongson-nand-controller.c
 F:	drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c
 F:	sound/soc/loongson/loongson1_ac97.c
 
drivers/mtd/nand/raw/Kconfig +3 -3
index 4b99d9c422c3..d9e3f13666ac 100644
@@ -462,12 +462,12 @@ config MTD_NAND_NUVOTON_MA35
 	  Enables support for the NAND controller found on
 	  the Nuvoton MA35 series SoCs.
 
-config MTD_NAND_LOONGSON1
-	tristate "Loongson1 NAND controller"
+config MTD_NAND_LOONGSON
+	tristate "Loongson NAND controller"
 	depends on LOONGSON1_APB_DMA || COMPILE_TEST
 	select REGMAP_MMIO
 	help
-	  Enables support for NAND controller on Loongson1 SoCs.
+	  Enables support for NAND controller on Loongson family chips.
 
 comment "Misc"
 
drivers/mtd/nand/raw/Makefile +1 -1
index 711d043ad4f8..c182b9703a9e 100644
@@ -59,7 +59,7 @@ obj-$(CONFIG_MTD_NAND_ROCKCHIP)		+= rockchip-nand-controller.o
 obj-$(CONFIG_MTD_NAND_PL35X)		+= pl35x-nand-controller.o
 obj-$(CONFIG_MTD_NAND_RENESAS)		+= renesas-nand-controller.o
 obj-$(CONFIG_MTD_NAND_NUVOTON_MA35)	+= nuvoton-ma35d1-nand-controller.o
-obj-$(CONFIG_MTD_NAND_LOONGSON1)	+= loongson1-nand-controller.o
+obj-$(CONFIG_MTD_NAND_LOONGSON)		+= loongson-nand-controller.o
 
 nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
 nand-objs += nand_onfi.o
drivers/mtd/nand/raw/loongson-nand-controller.c renamed from drivers/mtd/nand/raw/loongson1-nand-controller.c +172 -165

731 lines not on this page · raw message

Signature · 1 line
2.47.3
#2 lore raw

PATCH v3 2/7 mtd: rawnand: loongson: Add 6-byte NAND ID reading support

In reply to Binbin Zhou

From: Keguang Zhang <[email protected]>

Loongson-1C and Loongson-2K SoCs support NAND flash chips with 6-byte ID. However, the current implementation only handles 5-byte ID which can lead to incorrect chip detection.

Extend loongson_nand_read_id_type_exec() to support 6-byte NAND ID.

---
 .../mtd/nand/raw/loongson-nand-controller.c   | 29 +++++++++++++++----
 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/mtd/nand/raw/loongson-nand-controller.c +23 -6
index b5a7be0fcacc..97cd566420a8 100644
@@ -50,6 +50,9 @@
 #define LOONGSON_NAND_COL_ADDR_CYC	2U
 #define LOONGSON_NAND_MAX_ADDR_CYC	5U
 
+#define LOONGSON_NAND_READ_ID_SLEEP_US		1000
+#define LOONGSON_NAND_READ_ID_TIMEOUT_US	5000
+
 #define BITS_PER_WORD			(4 * BITS_PER_BYTE)
 
 struct loongson_nand_host;
@@ -73,6 +76,8 @@ struct loongson_nand_op {
 };
 
 struct loongson_nand_data {
+	unsigned int max_id_cycle;
+	unsigned int id_cycle_field;
 	unsigned int status_field;
 	unsigned int op_scope_field;
 	unsigned int hold_cycle;
@@ -458,10 +463,10 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const struct
 	struct loongson_nand_op op = {};
 	int i, ret;
 	union {
-		char ids[5];
+		char ids[6];
 		struct {
 			int idl;
-			char idh;
+			u16 idh;
 		};
 	} nand_id;
 
@@ -469,11 +474,16 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const struct
 	if (ret)
 		return ret;
 
-	nand_id.idl = readl(host->reg_base + LOONGSON_NAND_IDL);
-	nand_id.idh = readb(host->reg_base + LOONGSON_NAND_IDH_STATUS);
+	ret = regmap_read_poll_timeout(host->regmap, LOONGSON_NAND_IDL, nand_id.idl, nand_id.idl,
+				       LOONGSON_NAND_READ_ID_SLEEP_US,
+				       LOONGSON_NAND_READ_ID_TIMEOUT_US);
+	if (ret)
+		return ret;
 
-	for (i = 0; i < min(sizeof(nand_id.ids), op.orig_len); i++)
-		op.buf[i] = nand_id.ids[sizeof(nand_id.ids) - 1 - i];
+	nand_id.idh = readw(host->reg_base + LOONGSON_NAND_IDH_STATUS);
+
+	for (i = 0; i < min(host->data->max_id_cycle, op.orig_len); i++)
+		op.buf[i] = nand_id.ids[host->data->max_id_cycle - 1 - i];
 
 	return ret;
 }
@@ -676,6 +686,10 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 	if (IS_ERR(host->regmap))
 		return dev_err_probe(dev, PTR_ERR(host->regmap), "failed to init regmap\n");
 
+	if (host->data->id_cycle_field)
+		regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->id_cycle_field,
+				   host->data->max_id_cycle << __ffs(host->data->id_cycle_field));
+
 	chan = dma_request_chan(dev, "rxtx");
 	if (IS_ERR(chan))
 		return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
@@ -800,6 +814,7 @@ static void loongson_nand_remove(struct platform_device *pdev)
 }
 
 static const struct loongson_nand_data ls1b_nand_data = {
+	.max_id_cycle = 5,
 	.status_field = GENMASK(15, 8),
 	.hold_cycle = 0x2,
 	.wait_cycle = 0xc,
@@ -807,6 +822,8 @@ static const struct loongson_nand_data ls1b_nand_data = {
 };
 
 static const struct loongson_nand_data ls1c_nand_data = {
+	.max_id_cycle = 6,
+	.id_cycle_field = GENMASK(14, 12),
 	.status_field = GENMASK(23, 16),
 	.op_scope_field = GENMASK(29, 16),
 	.hold_cycle = 0x2,
Signature · 1 line
2.47.3
#3 lore raw

PATCH v3 3/7 mtd: rawnand: loongson: Add nand chip select support

In reply to Binbin Zhou

The page address register describes the page address of the starting address for NAND read/write/erase operations.

According to the manual, it consists of two parts:

	{chip select, page number}

The chip select is fixed at 2 bits, and the page number is determined based on the actual capacity of the single-chip memory. Therefore we need to determine the chip select bits base on the page number.

For example, for a 1GB capacity chip (2K page size), it has 1M pages. Thus, [19:0] is used to represent the page number, and [21:20] represents the chip select.

---
 .../mtd/nand/raw/loongson-nand-controller.c   | 117 ++++++++++++++----
 1 file changed, 91 insertions(+), 26 deletions(-)
drivers/mtd/nand/raw/loongson-nand-controller.c +91 -26
index 97cd566420a8..b26d1e133594 100644
@@ -82,6 +82,7 @@ struct loongson_nand_data {
 	unsigned int op_scope_field;
 	unsigned int hold_cycle;
 	unsigned int wait_cycle;
+	unsigned int nand_cs;
 	void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
 };
 
@@ -90,6 +91,7 @@ struct loongson_nand_host {
 	struct nand_chip chip;
 	struct nand_controller controller;
 	const struct loongson_nand_data *data;
+	unsigned int addr_cs_field;
 	void __iomem *reg_base;
 	struct regmap *regmap;
 	/* DMA Engine stuff */
@@ -215,6 +217,26 @@ static int loongson_nand_parse_instructions(struct nand_chip *chip, const struct
 	return 0;
 }
 
+static void loongson_nand_set_addr_cs(struct loongson_nand_host *host)
+{
+	struct nand_chip *chip = &host->chip;
+	struct mtd_info *mtd = nand_to_mtd(chip);
+
+	if (!host->data->nand_cs)
+		return;
+
+	/*
+	 * The Manufacturer/Chip ID read operation precedes attach_chip, at which point
+	 * information such as NAND chip selection and capacity is unknown. As a
+	 * workaround, we use 128MB cellsize (2KB pagesize) as a fallback.
+	 */
+	if (!mtd->writesize)
+		host->addr_cs_field = GENMASK(17, 16);
+
+	regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, host->addr_cs_field,
+			   host->data->nand_cs << __ffs(host->addr_cs_field));
+}
+
 static void ls1b_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op)
 {
 	struct nand_chip *chip = &host->chip;
@@ -263,6 +285,8 @@ static void ls1c_nand_set_addr(struct loongson_nand_host *host, struct loongson_
 			regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val);
 		}
 	}
+
+	loongson_nand_set_addr_cs(host);
 }
 
 static void loongson_nand_trigger_op(struct loongson_nand_host *host, struct loongson_nand_op *op)
@@ -603,42 +627,83 @@ static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_opera
 	return nand_op_parser_exec_op(chip, &loongson_nand_op_parser, op, check_only);
 }
 
-static int loongson_nand_attach_chip(struct nand_chip *chip)
+static int loongson_nand_get_chip_capacity(struct nand_chip *chip)
 {
 	struct loongson_nand_host *host = nand_get_controller_data(chip);
 	u64 chipsize = nanddev_target_size(&chip->base);
-	int cell_size = 0;
+	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	switch (chipsize) {
-	case SZ_128M:
-		cell_size = 0x0;
-		break;
-	case SZ_256M:
-		cell_size = 0x1;
-		break;
-	case SZ_512M:
-		cell_size = 0x2;
-		break;
-	case SZ_1G:
-		cell_size = 0x3;
-		break;
-	case SZ_2G:
-		cell_size = 0x4;
+	switch (mtd->writesize) {
+	case SZ_512:
+		switch (chipsize) {
+		case SZ_8M:
+			host->addr_cs_field = GENMASK(15, 14);
+			return 0x9;
+		case SZ_16M:
+			host->addr_cs_field = GENMASK(16, 15);
+			return 0xa;
+		case SZ_32M:
+			host->addr_cs_field = GENMASK(17, 16);
+			return 0xb;
+		case SZ_64M:
+			host->addr_cs_field = GENMASK(18, 17);
+			return 0xc;
+		case SZ_128M:
+			host->addr_cs_field = GENMASK(19, 18);
+			return 0xd;
+		}
 		break;
-	case SZ_4G:
-		cell_size = 0x5;
+	case SZ_2K:
+		switch (chipsize) {
+		case SZ_128M:
+			host->addr_cs_field = GENMASK(17, 16);
+			return 0x0;
+		case SZ_256M:
+			host->addr_cs_field = GENMASK(18, 17);
+			return 0x1;
+		case SZ_512M:
+			host->addr_cs_field = GENMASK(19, 18);
+			return 0x2;
+		case SZ_1G:
+			host->addr_cs_field = GENMASK(20, 19);
+			return 0x3;
+		}
 		break;
-	case SZ_8G:
-		cell_size = 0x6;
+	case SZ_4K:
+		if (chipsize == SZ_2G) {
+			host->addr_cs_field = GENMASK(20, 19);
+			return 0x4;
+		}
 		break;
-	case SZ_16G:
-		cell_size = 0x7;
+	case SZ_8K:
+		switch (chipsize) {
+		case SZ_4G:
+			host->addr_cs_field = GENMASK(20, 19);
+			return 0x5;
+		case SZ_8G:
+			host->addr_cs_field = GENMASK(21, 20);
+			return 0x6;
+		case SZ_16G:
+			host->addr_cs_field = GENMASK(22, 21);
+			return 0x7;
+		}
 		break;
-	default:
-		dev_err(host->dev, "unsupported chip size: %llu MB\n", chipsize);
-		return -EINVAL;
 	}
 
+	dev_err(host->dev, "Unsupported chip size: %llu MB with page size %u B\n",
+		chipsize, mtd->writesize);
+	return -EINVAL;
+}
+
+static int loongson_nand_attach_chip(struct nand_chip *chip)
+{
+	struct loongson_nand_host *host = nand_get_controller_data(chip);
+	int cell_size = 0;
+
+	cell_size = loongson_nand_get_chip_capacity(chip);
+	if (cell_size < 0)
+		return cell_size;
+
 	switch (chip->ecc.engine_type) {
 	case NAND_ECC_ENGINE_TYPE_NONE:
 		break;
Signature · 1 line
2.47.3
#4 lore raw

PATCH v3 4/7 dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K0500 NAND controller

In reply to Binbin Zhou

Add new compatible for the Loongson-2K NAND controller used for Loongson-2K0500 SoC.

---
 .../bindings/mtd/loongson,ls1b-nand-controller.yaml         | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +4 -2
index a09e92e416c4..4ec2b5d1e89d 100644
@@ -4,13 +4,14 @@
 $id: http://devicetree.org/schemas/mtd/loongson,ls1b-nand-controller.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Loongson-1 NAND Controller
+title: Loongson NAND Controller
 
 maintainers:
   - Keguang Zhang <[email protected]>
+  - Binbin Zhou <[email protected]>
 
 description:
-  The Loongson-1 NAND controller abstracts all supported operations,
+  The Loongson NAND controller abstracts all supported operations,
   meaning it does not support low-level access to raw NAND flash chips.
   Moreover, the controller is paired with the DMA engine to perform
   READ and PROGRAM functions.
@@ -24,6 +25,7 @@ properties:
       - enum:
           - loongson,ls1b-nand-controller
           - loongson,ls1c-nand-controller
+          - loongson,ls2k0500-nand-controller
       - items:
           - enum:
               - loongson,ls1a-nand-controller
Signature · 1 line
2.47.3
#5 lore raw

PATCH v3 5/7 mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support

In reply to Binbin Zhou

The Loongson-2K0500 NAND controller is similar to the Loongson-1C.

It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals.

Its DMA controller is defaulted to APBDMA0.

---
 drivers/mtd/nand/raw/Kconfig                  |  2 +-
 .../mtd/nand/raw/loongson-nand-controller.c   | 52 ++++++++++++++++++-
 2 files changed, 51 insertions(+), 3 deletions(-)
drivers/mtd/nand/raw/Kconfig +1 -1
index d9e3f13666ac..7b0c5d06aa95 100644
@@ -464,7 +464,7 @@ config MTD_NAND_NUVOTON_MA35
 
 config MTD_NAND_LOONGSON
 	tristate "Loongson NAND controller"
-	depends on LOONGSON1_APB_DMA || COMPILE_TEST
+	depends on LOONGSON1_APB_DMA || LOONGSON2_APB_DMA || COMPILE_TEST
 	select REGMAP_MMIO
 	help
 	  Enables support for NAND controller on Loongson family chips.
drivers/mtd/nand/raw/loongson-nand-controller.c +50 -2

117 lines not on this page · raw message

Signature · 1 line
2.47.3
maintainer
#6 lore raw

Re: [PATCH v3 5/7] mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support

Hi Binbin,

drivers/mtd/nand/raw/loongson-nand-controller.c struct loongson_nand_data { · line 107

Quoted 10 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +3 -0
+#define LOONGSON_NAND_64BIT_DMA		BIT(0)
+
 #define BITS_PER_WORD			(4 * BITS_PER_BYTE)
 
 struct loongson_nand_host;
@@ -83,6 +104,7 @@ struct loongson_nand_data {
 	unsigned int hold_cycle;
 	unsigned int wait_cycle;
 	unsigned int nand_cs;
+	unsigned int flags;

Can we turn this into a boolean instead and give it a DMA related name? I'm not sure the list of flags will extend rapidly...

Quoted 23 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +4 -1
 	void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
 };
 
@@ -745,7 +767,7 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 	struct device *dev = host->dev;
 	struct dma_chan *chan;
 	struct dma_slave_config cfg = {};
-	int ret;
+	int ret, val;
 
 	host->regmap = devm_regmap_init_mmio(dev, host->reg_base, &loongson_nand_regmap_config);
 	if (IS_ERR(host->regmap))
@@ -755,6 +777,9 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 		regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->id_cycle_field,
 				   host->data->max_id_cycle << __ffs(host->data->id_cycle_field));
 
+	if (host->data->flags & LOONGSON_NAND_64BIT_DMA)
+		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+
 	chan = dma_request_chan(dev, "rxtx");
 	if (IS_ERR(chan))
 		return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");

drivers/mtd/nand/raw/loongson-nand-controller.c static int loongson_nand_controller_init(struct loongson_nand_host *host) · line 803

Quoted 10 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +6 -1
@@ -770,7 +795,14 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 
 	init_completion(&host->dma_complete);
 
-	return 0;
+	val = FIELD_PREP(LOONGSON_NAND_MAP_CS1_SEL, LOONGSON_NAND_CS_SEL1)
+	    | FIELD_PREP(LOONGSON_NAND_MAP_RDY1_SEL, LOONGSON_NAND_CS_RDY1)
+	    | FIELD_PREP(LOONGSON_NAND_MAP_CS2_SEL, LOONGSON_NAND_CS_SEL2)
+	    | FIELD_PREP(LOONGSON_NAND_MAP_RDY2_SEL, LOONGSON_NAND_CS_RDY2)
+	    | FIELD_PREP(LOONGSON_NAND_MAP_CS3_SEL, LOONGSON_NAND_CS_SEL3)
+	    | FIELD_PREP(LOONGSON_NAND_MAP_RDY3_SEL, LOONGSON_NAND_CS_RDY3);

Just a nit about the style, '|' should be last character on the previous line.

Otherwise the rest lgtm.

Thanks,
Miquèl

#7 lore raw

Re: [PATCH v3 5/7] mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support

Hi Miquel:

Thanks for your review.

Quoted 7 lines · Miquel Raynal

Hi Binbin,

Quoted 4 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +2 -0
+#define LOONGSON_NAND_64BIT_DMA              BIT(0)
+
 #define BITS_PER_WORD                        (4 * BITS_PER_BYTE)
Quoted 9 lines

drivers/mtd/nand/raw/loongson-nand-controller.c struct loongson_nand_data { · line 107

Quoted 6 lines

struct loongson_nand_host;

drivers/mtd/nand/raw/loongson-nand-controller.c +1 -0
@@ -83,6 +104,7 @@ struct loongson_nand_data {
      unsigned int hold_cycle;
      unsigned int wait_cycle;
      unsigned int nand_cs;
+     unsigned int flags;

Can we turn this into a boolean instead and give it a DMA related name? I'm not sure the list of flags will extend rapidly...

Keguang has a different opinion on this part [1]. Since his reply email and my V3 patchset email were sent at about the same time, I plan to address these comments in the V4 patchset.

He found that the Loongson-1 series NAND controller also needs dma_set_mask_and_coherent(), so we still need to explicitly set the value of dma_bits.

Specifically:
The flags variable will be split into:

```
unsigned int dma_bits;
int (*dma_config)(struct device *dev);
```

[1]: https://lore.kernel.org/all/CAJhJPsW3KGL=FH5ZVqvRr-RD+ih09mFNuk7wGXepGVSw7bTaiw@mail.gmail.com/

Quoted 27 lines
Quoted 27 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +4 -1
      void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
 };
 
@@ -745,7 +767,7 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
      struct device *dev = host->dev;
      struct dma_chan *chan;
      struct dma_slave_config cfg = {};
-     int ret;
+     int ret, val;
 
      host->regmap = devm_regmap_init_mmio(dev, host->reg_base, &loongson_nand_regmap_config);
      if (IS_ERR(host->regmap))
@@ -755,6 +777,9 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
              regmap_update_bits(host->regmap, LOONGSON_NAND_PARAM, host->data->id_cycle_field,
                                 host->data->max_id_cycle << __ffs(host->data->id_cycle_field));
 
+     if (host->data->flags & LOONGSON_NAND_64BIT_DMA)
+             dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+
      chan = dma_request_chan(dev, "rxtx");
      if (IS_ERR(chan))
              return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
@@ -770,7 +795,14 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 
      init_completion(&host->dma_complete);
 
Quoted 10 lines

drivers/mtd/nand/raw/loongson-nand-controller.c static int loongson_nand_controller_init(struct loongson_nand_host *host) · line 803

Quoted 7 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +6 -1
-     return 0;
+     val = FIELD_PREP(LOONGSON_NAND_MAP_CS1_SEL, LOONGSON_NAND_CS_SEL1)
+         | FIELD_PREP(LOONGSON_NAND_MAP_RDY1_SEL, LOONGSON_NAND_CS_RDY1)
+         | FIELD_PREP(LOONGSON_NAND_MAP_CS2_SEL, LOONGSON_NAND_CS_SEL2)
+         | FIELD_PREP(LOONGSON_NAND_MAP_RDY2_SEL, LOONGSON_NAND_CS_RDY2)
+         | FIELD_PREP(LOONGSON_NAND_MAP_CS3_SEL, LOONGSON_NAND_CS_SEL3)
+         | FIELD_PREP(LOONGSON_NAND_MAP_RDY3_SEL, LOONGSON_NAND_CS_RDY3);

Just a nit about the style, '|' should be last character on the previous line.

OK. I will do it.

Quoted 5 lines

Otherwise the rest lgtm.

Thanks,
Miquèl

Signature · 2 lines
Thanks.
Binbin
#8 lore raw

PATCH v3 6/7 dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K1000 NAND controller

In reply to Binbin Zhou

Add new compatible for the Loongson-2K NAND controller used for Loongson-2K1000 SoC.

---
 .../mtd/loongson,ls1b-nand-controller.yaml    | 50 ++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +49 -1
index 4ec2b5d1e89d..cf85d0cede00 100644
@@ -26,18 +26,22 @@ properties:
           - loongson,ls1b-nand-controller
           - loongson,ls1c-nand-controller
           - loongson,ls2k0500-nand-controller
+          - loongson,ls2k1000-nand-controller
       - items:
           - enum:
               - loongson,ls1a-nand-controller
           - const: loongson,ls1b-nand-controller
 
   reg:
-    maxItems: 2
+    minItems: 2
+    maxItems: 3
 
   reg-names:
+    minItems: 2
     items:
       - const: nand
       - const: nand-dma
+      - const: dma-config
 
   dmas:
     maxItems: 1
@@ -54,6 +58,27 @@ required:
 
 unevaluatedProperties: false
 
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - loongson,ls2k1000-nand-controller
+
+then:
+  properties:
+    reg:
+      minItems: 3
+    reg-names:
+      minItems: 3
+
+else:
+  properties:
+    reg:
+      maxItems: 2
+    reg-names:
+      maxItems: 2
+
 examples:
   - |
     nand-controller@1fe78000 {
@@ -72,3 +97,26 @@ examples:
             nand-ecc-algo = "hamming";
         };
     };
+
+  - |
+    nand-controller@1fe26000 {
+        compatible = "loongson,ls2k1000-nand-controller";
+        reg = <0x1fe26000 0x24>,
+              <0x1fe26040 0x4>,
+              <0x1fe00438 0x8>;
+        reg-names = "nand", "nand-dma", "dma-config";
+        dmas = <&apbdma0 0>;
+        dma-names = "rxtx";
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        nand@0 {
+            reg = <0>;
+            label = "ls2k1000-nand";
+            nand-use-soft-ecc-engine;
+            nand-ecc-algo = "bch";
+            nand-ecc-strength = <8>;
+            nand-ecc-step-size = <512>;
+        };
+    };
Signature · 1 line
2.47.3
#9 lore raw

PATCH v3 7/7 mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support

In reply to Binbin Zhou

The Loongson-2K1000 NAND controller is also similar to the Loongson-1C.

It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals.

The key difference from the Loongson-2K0500 is that it requires explicit configuration of the DMA control route. Typically, it is configured as APBDMA0.

---
 .../mtd/nand/raw/loongson-nand-controller.c   | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
drivers/mtd/nand/raw/loongson-nand-controller.c +48 -0
index 7b331d0ca2f0..6610c239f721 100644
@@ -73,9 +73,18 @@
 #define LOONGSON_NAND_READ_ID_TIMEOUT_US	5000
 
 #define LOONGSON_NAND_64BIT_DMA		BIT(0)
+#define LOONGSON_NAND_DMA_CONFIG	BIT(1)
 
 #define BITS_PER_WORD			(4 * BITS_PER_BYTE)
 
+/* Loongson-2K1000 NAND DMA routing register */
+#define LS2K1000_NAND_DMA_MASK         GENMASK(2, 0)
+#define LS2K1000_DMA0_CONF             0x0
+#define LS2K1000_DMA1_CONF             0x1
+#define LS2K1000_DMA2_CONF             0x2
+#define LS2K1000_DMA3_CONF             0x3
+#define LS2K1000_DMA4_CONF             0x4
+
 struct loongson_nand_host;
 
 struct loongson_nand_op {
@@ -762,6 +771,23 @@ static void loongson_nand_controller_cleanup(struct loongson_nand_host *host)
 		dma_release_channel(host->dma_chan);
 }
 
+static int ls2k1000_nand_apbdma_config(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	void __iomem *regs;
+	int val;
+
+	regs = devm_platform_ioremap_resource(pdev, 2);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	val = readl(regs);
+	val |= FIELD_PREP(LS2K1000_NAND_DMA_MASK, LS2K1000_DMA0_CONF);
+	writel(val, regs);
+
+	return 0;
+}
+
 static int loongson_nand_controller_init(struct loongson_nand_host *host)
 {
 	struct device *dev = host->dev;
@@ -780,6 +806,12 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 	if (host->data->flags & LOONGSON_NAND_64BIT_DMA)
 		dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
 
+	if (host->data->flags & LOONGSON_NAND_DMA_CONFIG) {
+		ret = ls2k1000_nand_apbdma_config(dev);
+		if (ret)
+			return ret;
+	}
+
 	chan = dma_request_chan(dev, "rxtx");
 	if (IS_ERR(chan))
 		return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
@@ -939,6 +971,18 @@ static const struct loongson_nand_data ls2k0500_nand_data = {
 	.set_addr = ls1c_nand_set_addr,
 };
 
+static const struct loongson_nand_data ls2k1000_nand_data = {
+	.max_id_cycle = 6,
+	.id_cycle_field = GENMASK(14, 12),
+	.status_field = GENMASK(23, 16),
+	.op_scope_field = GENMASK(29, 16),
+	.hold_cycle = 0x4,
+	.wait_cycle = 0x12,
+	.nand_cs = 0x2,
+	.flags = LOONGSON_NAND_64BIT_DMA | LOONGSON_NAND_DMA_CONFIG,
+	.set_addr = ls1c_nand_set_addr,
+};
+
 static const struct of_device_id loongson_nand_match[] = {
 	{
 		.compatible = "loongson,ls1b-nand-controller",
@@ -952,6 +996,10 @@ static const struct of_device_id loongson_nand_match[] = {
 		.compatible = "loongson,ls2k0500-nand-controller",
 		.data = &ls2k0500_nand_data,
 	},
+	{
+		.compatible = "loongson,ls2k1000-nand-controller",
+		.data = &ls2k1000_nand_data,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, loongson_nand_match);
Signature · 1 line
2.47.3
maintainer
#10 lore raw

Re: [PATCH v3 7/7] mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support

Quoted 20 lines · Binbin Zhou

The Loongson-2K1000 NAND controller is also similar to the Loongson-1C.

It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals.

The key difference from the Loongson-2K0500 is that it requires explicit configuration of the DMA control route. Typically, it is configured as APBDMA0.

---
 .../mtd/nand/raw/loongson-nand-controller.c   | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
drivers/mtd/nand/raw/loongson-nand-controller.c +0 -0
index 7b331d0ca2f0..6610c239f721 100644

drivers/mtd/nand/raw/loongson-nand-controller.c line 76

Quoted 4 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +1 -0
@@ -73,9 +73,18 @@
 #define LOONGSON_NAND_READ_ID_TIMEOUT_US	5000
 
 #define LOONGSON_NAND_64BIT_DMA		BIT(0)
+#define LOONGSON_NAND_DMA_CONFIG	BIT(1)

You're reusing this flags member, so it's fine, please ignore the previous comment (except the style issue).

...

drivers/mtd/nand/raw/loongson-nand-controller.c static void loongson_nand_controller_cleanup(struct loongson_nand_host *host) · line 780

Quoted 1 line
drivers/mtd/nand/raw/loongson-nand-controller.c +1 -0
+	regs = devm_platform_ioremap_resource(pdev, 2);

Would it be clearer to get the resource by name? (not a strong request)

Thanks
Miquèl

#11 lore raw

Re: [PATCH v3 7/7] mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support

Hi Miquel:

Thanks for your reply.

Quoted 31 lines · Miquel Raynal
Quoted 20 lines · Binbin Zhou

The Loongson-2K1000 NAND controller is also similar to the Loongson-1C.

It supports a maximum capacity of 16GB FLASH per chip with a maximum page size of 8KB, and it supports up to 4 chip selects and 4 RDY signals.

The key difference from the Loongson-2K0500 is that it requires explicit configuration of the DMA control route. Typically, it is configured as APBDMA0.

---
 .../mtd/nand/raw/loongson-nand-controller.c   | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)
drivers/mtd/nand/raw/loongson-nand-controller.c +0 -0
index 7b331d0ca2f0..6610c239f721 100644

drivers/mtd/nand/raw/loongson-nand-controller.c line 76

Quoted 4 lines
drivers/mtd/nand/raw/loongson-nand-controller.c +1 -0
@@ -73,9 +73,18 @@
 #define LOONGSON_NAND_READ_ID_TIMEOUT_US     5000
 
 #define LOONGSON_NAND_64BIT_DMA              BIT(0)
+#define LOONGSON_NAND_DMA_CONFIG     BIT(1)

You're reusing this flags member, so it's fine, please ignore the previous comment (except the style issue).

Quoted 5 lines

...

Quoted 1 line

+ regs = devm_platform_ioremap_resource(pdev, 2);

Would it be clearer to get the resource by name? (not a strong request)

It will be replaced by

devm_platform_ioremap_resource_byname(pdev, "dma-config");

Quoted 3 lines

Thanks
Miquèl

Signature · 2 lines
Thanks.
Binbin