[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