[PATCH v2 6/8] mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support
Binbin Zhou
zhoubb.aaron at gmail.com
Thu Aug 21 00:13:58 PDT 2025
Hi Keguang:
Thanks for your reply.
On Thu, Aug 21, 2025 at 2:46 PM Keguang Zhang <keguang.zhang at gmail.com> wrote:
>
> On Mon, Aug 11, 2025 at 2:03 PM Binbin Zhou <zhoubinbin at loongson.cn> wrote:
> >
> > 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 at loongson.cn>
> > ---
> > drivers/mtd/nand/raw/Kconfig | 2 +-
> > .../mtd/nand/raw/loongson-nand-controller.c | 55 ++++++++++++++++++-
> > 2 files changed, 54 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
> > index d9e3f13666ac..7b0c5d06aa95 100644
> > --- a/drivers/mtd/nand/raw/Kconfig
> > +++ b/drivers/mtd/nand/raw/Kconfig
> > @@ -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.
> > diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c
> > index 5a51c7d299cc..7a15df3fcd31 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 <keguang.zhang at gmail.com>
> > + * Copyright (C) 2025 Binbin Zhou <zhoubinbin at 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)
> > @@ -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)
> > @@ -53,6 +72,8 @@
> > #define LOONGSON_NAND_READ_ID_SLEEP_US 1000
> > #define LOONGSON_NAND_READ_ID_TIMEOUT_US 5000
> >
> > +#define LOONGSON_NAND_64BIT_DMA BIT(0)
>
> It's strongly suggested to replace this flag with a dma_bits field in
> loongson_nand_host.
> Please see the comments below.
>
> > +
> > #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;
>
> Add unsigned int dma_bits;
>
> > + unsigned int flags;
> > void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
> > };
> >
> > @@ -751,7 +773,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))
> > @@ -761,6 +783,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));
> > +
>
> Sorry, all platforms should call dma_set_mask_and_coherent(),
> including Loongson-1, which I missed earlier.
> 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");
>
OK, if it is also required by Loongson-1, I will refactor this part.
In addition, I will address all of the following comments in the V4
patchset, as the V3 patchset[1] has already been submitted.
[1]: https://lore.kernel.org/all/cover.1755757841.git.zhoubinbin@loongson.cn/
You are welcome to continue to comment on that patchset as well.
> > chan = dma_request_chan(dev, "rxtx");
> > if (IS_ERR(chan))
> > return dev_err_probe(dev, PTR_ERR(chan), "failed to request DMA channel\n");
> > @@ -776,7 +801,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);
> > +
> > + return regmap_write(host->regmap, LOONGSON_NAND_CS_RDY_MAP, val);
>
> Chip selects should be set before requesting the DMA channel.
>
> > }
> >
> > static int loongson_nand_chip_init(struct loongson_nand_host *host)
> > @@ -890,6 +922,7 @@ static const struct loongson_nand_data ls1b_nand_data = {
> > .hold_cycle = 0x2,
> > .wait_cycle = 0xc,
> > .nand_cs = 0x0,
>
> Add .dma_bits = 32,
>
> > + .flags = 0,
>
> The assignment `.flags = 0x0` is redundant and can be removed.
>
> > .set_addr = ls1b_nand_set_addr,
> > };
> >
> > @@ -901,6 +934,19 @@ static const struct loongson_nand_data ls1c_nand_data = {
> > .hold_cycle = 0x2,
> > .wait_cycle = 0xc,
> > .nand_cs = 0x0,
>
> Add .dma_bits = 32,
>
> > + .flags = 0,
>
> Ditto.
>
> > + .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,
> > + .nand_cs = 0x0,
> > + .flags = LOONGSON_NAND_64BIT_DMA,
>
> Replace LOONGSON_NAND_64BIT_DMA with .dma_bits = 64,
>
> > .set_addr = ls1c_nand_set_addr,
> > };
> >
> > @@ -913,6 +959,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);
> > @@ -929,5 +979,6 @@ static struct platform_driver loongson_nand_driver = {
> > module_platform_driver(loongson_nand_driver);
> >
> > MODULE_AUTHOR("Keguang Zhang <keguang.zhang at gmail.com>");
> > +MODULE_AUTHOR("Binbin Zhou <zhoubinbin at loongson.cn>");
> > MODULE_DESCRIPTION("Loongson NAND Controller Driver");
> > MODULE_LICENSE("GPL");
> > --
> > 2.47.3
> >
>
>
> --
> Best regards,
>
> Keguang Zhang
--
Thanks.
Binbin
More information about the linux-mtd
mailing list