]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support
authorBinbin Zhou <zhoubinbin@loongson.cn>
Thu, 4 Sep 2025 13:07:09 +0000 (21:07 +0800)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Wed, 10 Sep 2025 08:56:09 +0000 (10:56 +0200)
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.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/loongson-nand-controller.c

index 489f5c05cda9a73ad07625d417389b1e3d5056dc..7408f34f0c68acaafaa09528483422914275d449 100644 (file)
@@ -438,7 +438,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.
index 1427dd6943a7bd8eb30e3b54d71d9b271dcfbc37..427a0daf8c55f88960400123a6f270fd5b5113ee 100644 (file)
@@ -3,6 +3,7 @@
  * NAND Controller Driver for Loongson family chips
  *
  * Copyright (C) 2015-2025 Keguang Zhang <keguang.zhang@gmail.com>
+ * Copyright (C) 2025 Binbin Zhou <zhoubinbin@loongson.cn>
  */
 
 #include <linux/kernel.h>
@@ -26,6 +27,7 @@
 #define LOONGSON_NAND_IDH_STATUS       0x14
 #define LOONGSON_NAND_PARAM            0x18
 #define LOONGSON_NAND_OP_NUM           0x1c
+#define LOONGSON_NAND_CS_RDY_MAP       0x20
 
 /* Bitfields of nand command register */
 #define LOONGSON_NAND_CMD_OP_DONE      BIT(10)
 #define LOONGSON_NAND_CMD_READ         BIT(1)
 #define LOONGSON_NAND_CMD_VALID                BIT(0)
 
+/* Bitfields of nand cs/rdy map register */
+#define LOONGSON_NAND_MAP_CS1_SEL      GENMASK(11, 8)
+#define LOONGSON_NAND_MAP_RDY1_SEL     GENMASK(15, 12)
+#define LOONGSON_NAND_MAP_CS2_SEL      GENMASK(19, 16)
+#define LOONGSON_NAND_MAP_RDY2_SEL     GENMASK(23, 20)
+#define LOONGSON_NAND_MAP_CS3_SEL      GENMASK(27, 24)
+#define LOONGSON_NAND_MAP_RDY3_SEL     GENMASK(31, 28)
+
+#define LOONGSON_NAND_CS_SEL0          BIT(0)
+#define LOONGSON_NAND_CS_SEL1          BIT(1)
+#define LOONGSON_NAND_CS_SEL2          BIT(2)
+#define LOONGSON_NAND_CS_SEL3          BIT(3)
+#define LOONGSON_NAND_CS_RDY0          BIT(0)
+#define LOONGSON_NAND_CS_RDY1          BIT(1)
+#define LOONGSON_NAND_CS_RDY2          BIT(2)
+#define LOONGSON_NAND_CS_RDY3          BIT(3)
+
 /* Bitfields of nand timing register */
 #define LOONGSON_NAND_WAIT_CYCLE_MASK  GENMASK(7, 0)
 #define LOONGSON_NAND_HOLD_CYCLE_MASK  GENMASK(15, 8)
@@ -83,6 +102,7 @@ struct loongson_nand_data {
        unsigned int hold_cycle;
        unsigned int wait_cycle;
        unsigned int nand_cs;
+       unsigned int dma_bits;
        void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
 };
 
@@ -744,7 +764,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))
@@ -754,6 +774,19 @@ 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));
 
+       ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(host->data->dma_bits));
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to set DMA mask\n");
+
+       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);
+
+       regmap_write(host->regmap, LOONGSON_NAND_CS_RDY_MAP, val);
+
        chan = dma_request_chan(dev, "rxtx");
        if (IS_ERR(chan))
                return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
@@ -882,6 +915,7 @@ static const struct loongson_nand_data ls1b_nand_data = {
        .status_field = GENMASK(15, 8),
        .hold_cycle = 0x2,
        .wait_cycle = 0xc,
+       .dma_bits = 32,
        .set_addr = ls1b_nand_set_addr,
 };
 
@@ -892,6 +926,18 @@ static const struct loongson_nand_data ls1c_nand_data = {
        .op_scope_field = GENMASK(29, 16),
        .hold_cycle = 0x2,
        .wait_cycle = 0xc,
+       .dma_bits = 32,
+       .set_addr = ls1c_nand_set_addr,
+};
+
+static const struct loongson_nand_data ls2k0500_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,
+       .dma_bits = 64,
        .set_addr = ls1c_nand_set_addr,
 };
 
@@ -904,6 +950,10 @@ static const struct of_device_id loongson_nand_match[] = {
                .compatible = "loongson,ls1c-nand-controller",
                .data = &ls1c_nand_data,
        },
+       {
+               .compatible = "loongson,ls2k0500-nand-controller",
+               .data = &ls2k0500_nand_data,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, loongson_nand_match);
@@ -920,5 +970,6 @@ static struct platform_driver loongson_nand_driver = {
 module_platform_driver(loongson_nand_driver);
 
 MODULE_AUTHOR("Keguang Zhang <keguang.zhang@gmail.com>");
+MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
 MODULE_DESCRIPTION("Loongson NAND Controller Driver");
 MODULE_LICENSE("GPL");