From: Binbin Zhou Date: Thu, 4 Sep 2025 13:07:09 +0000 (+0800) Subject: mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support X-Git-Tag: v6.18-rc1~78^2^2~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e55bbdd4a4b654dfe8ee8649b3be1db82319d6c0;p=thirdparty%2Fkernel%2Flinux.git mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support 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 Signed-off-by: Miquel Raynal --- diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 489f5c05cda9a..7408f34f0c68a 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -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. diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 1427dd6943a7b..427a0daf8c55f 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -3,6 +3,7 @@ * NAND Controller Driver for Loongson family chips * * Copyright (C) 2015-2025 Keguang Zhang + * Copyright (C) 2025 Binbin Zhou */ #include @@ -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) @@ -40,6 +42,23 @@ #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 "); +MODULE_AUTHOR("Binbin Zhou "); MODULE_DESCRIPTION("Loongson NAND Controller Driver"); MODULE_LICENSE("GPL");