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

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

index 427a0daf8c55f88960400123a6f270fd5b5113ee..8490412d5be191a44cce85b8cd840939e5ed4452 100644 (file)
 
 #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 {
@@ -103,6 +111,7 @@ struct loongson_nand_data {
        unsigned int wait_cycle;
        unsigned int nand_cs;
        unsigned int dma_bits;
+       int (*dma_config)(struct device *dev);
        void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
 };
 
@@ -759,6 +768,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_byname(pdev, "dma-config");
+       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;
@@ -787,6 +813,12 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)
 
        regmap_write(host->regmap, LOONGSON_NAND_CS_RDY_MAP, val);
 
+       if (host->data->dma_config) {
+               ret = host->data->dma_config(dev);
+               if (ret)
+                       return dev_err_probe(dev, ret, "failed to config DMA routing\n");
+       }
+
        chan = dma_request_chan(dev, "rxtx");
        if (IS_ERR(chan))
                return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
@@ -941,6 +973,19 @@ 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,
+       .dma_bits = 64,
+       .dma_config = ls2k1000_nand_apbdma_config,
+       .set_addr = ls1c_nand_set_addr,
+};
+
 static const struct of_device_id loongson_nand_match[] = {
        {
                .compatible = "loongson,ls1b-nand-controller",
@@ -954,6 +999,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);