From 5808ae66f22e665c7131816e146548f2d7903ae1 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Thu, 4 Sep 2025 21:07:11 +0800 Subject: [PATCH] mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support 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 Signed-off-by: Miquel Raynal --- .../mtd/nand/raw/loongson-nand-controller.c | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 427a0daf8c55..8490412d5be1 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -74,6 +74,14 @@ #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); -- 2.47.3