mtd: rawnand: loongson: Add Loongson-2K nand controller support
Subsystems (5)
cover mtd: rawnand: loongson: Add Loongson-2K nand controller support
Hi all:
This patchset adds support for the Loongson-2K0500/Loongson-2K1000 NAND controllers, which are similar to the Loongson-1C NAND controller.
They support a maximum capacity of 16GB FLASH per chip, with a maximum page size of 8KB. The chip supports up to 4 chip selects and 4 RDY signals.
The key difference between the Loongson-2K NAND controllers is that the Loongson-2K1000 explicitly configures the DMA controller routing, while the Loongson-2K0500 defaults to using APBDMA0.
Summary of the patchset:
Ptach 1-2: Rename all prefixes from ls1x to loongson Patch 3: Add 6-byte NAND ID reading
Patch 4: Add chip select support
Patch 5-6: Add Loongson-2K0500 NAND controller support Patch 7-8: Add Loongson-2K1000 NAND controller support
Thanks.
Binbin Zhou (7):
mtd: rawnand: loongson1: Rename the prefix from ls1x to loongson
mtd: rawnand: loongson: Rename loongson1 to loongson
mtd: rawnand: loongson: Add nand chip select support
dt-bindings: mtd: loongson,ls1b-nand-controller: Document the
Loongson-2K0500 NAND controller
mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support
dt-bindings: mtd: loongson,ls1b-nand-controller: Document the
Loongson-2K1000 NAND controller
mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support
Keguang Zhang (1):
mtd: rawnand: loongson: Add 6-byte NAND ID reading support
.../mtd/loongson,ls1b-nand-controller.yaml | 64 +- MAINTAINERS | 2 +- drivers/mtd/nand/raw/Kconfig | 8 +- drivers/mtd/nand/raw/Makefile | 2 +- .../mtd/nand/raw/loongson-nand-controller.c | 1032 +++++++++++++++++ .../mtd/nand/raw/loongson1-nand-controller.c | 836 ------------- 6 files changed, 1096 insertions(+), 848 deletions(-) create mode 100644 drivers/mtd/nand/raw/loongson-nand-controller.c delete mode 100644 drivers/mtd/nand/raw/loongson1-nand-controller.c
base-commit: 9358bdb9f9f54d94ceafc650deffefd737d19fdd
Signature · 1 line
2.47.3
PATCH 1/8 mtd: rawnand: loongson1: Rename the prefix from ls1x to loongson
I am going to introduce the NAND controllers of the Loongson-2K series CPUs, which are similar to Loongson-1.
As preparation, first rename all prefixes from ls1x to loongson.
No functional change intended.
--- .../mtd/nand/raw/loongson1-nand-controller.c | 337 +++++++++--------- 1 file changed, 172 insertions(+), 165 deletions(-)
drivers/mtd/nand/raw/loongson1-nand-controller.c +172 -165
@@ -1,6 +1,6 @@// SPDX-License-Identifier: GPL-2.0-or-later /* -* NAND Controller Driver for Loongson-1 SoC +* NAND Controller Driver for Loongson family chips * * Copyright (C) 2015-2025 Keguang Zhang <[email protected]> */
@@ -17,42 +17,45 @@#include <linux/regmap.h> #include <linux/sizes.h> -/* Loongson-1 NAND Controller Registers */ -#define LS1X_NAND_CMD 0x0 -#define LS1X_NAND_ADDR1 0x4 -#define LS1X_NAND_ADDR2 0x8 -#define LS1X_NAND_TIMING 0xc -#define LS1X_NAND_IDL 0x10 -#define LS1X_NAND_IDH_STATUS 0x14 -#define LS1X_NAND_PARAM 0x18 -#define LS1X_NAND_OP_NUM 0x1c - -/* NAND Command Register Bits */ -#define LS1X_NAND_CMD_OP_DONE BIT(10) -#define LS1X_NAND_CMD_OP_SPARE BIT(9) -#define LS1X_NAND_CMD_OP_MAIN BIT(8) -#define LS1X_NAND_CMD_STATUS BIT(7) -#define LS1X_NAND_CMD_RESET BIT(6) -#define LS1X_NAND_CMD_READID BIT(5) -#define LS1X_NAND_CMD_BLOCKS_ERASE BIT(4) -#define LS1X_NAND_CMD_ERASE BIT(3) -#define LS1X_NAND_CMD_WRITE BIT(2) -#define LS1X_NAND_CMD_READ BIT(1) -#define LS1X_NAND_CMD_VALID BIT(0) - -#define LS1X_NAND_WAIT_CYCLE_MASK GENMASK(7, 0) -#define LS1X_NAND_HOLD_CYCLE_MASK GENMASK(15, 8) -#define LS1X_NAND_CELL_SIZE_MASK GENMASK(11, 8) - -#define LS1X_NAND_COL_ADDR_CYC 2U -#define LS1X_NAND_MAX_ADDR_CYC 5U - -#define BITS_PER_WORD (4 * BITS_PER_BYTE) - -struct ls1x_nand_host ; - -struct ls1x_nand_op { -char addrs[LS1X_NAND_MAX_ADDR_CYC ]; +/* Loongson NAND Controller Registers */ +#define LOONGSON_NAND_CMD 0x0 +#define LOONGSON_NAND_ADDR1 0x4 +#define LOONGSON_NAND_ADDR2 0x8 +#define LOONGSON_NAND_TIMING 0xc +#define LOONGSON_NAND_IDL 0x10 +#define LOONGSON_NAND_IDH_STATUS 0x14 +#define LOONGSON_NAND_PARAM 0x18 +#define LOONGSON_NAND_OP_NUM 0x1c + +/* Bitfields of nand command register */ +#define LOONGSON_NAND_CMD_OP_DONE BIT(10) +#define LOONGSON_NAND_CMD_OP_SPARE BIT(9) +#define LOONGSON_NAND_CMD_OP_MAIN BIT(8) +#define LOONGSON_NAND_CMD_STATUS BIT(7) +#define LOONGSON_NAND_CMD_RESET BIT(6) +#define LOONGSON_NAND_CMD_READID BIT(5) +#define LOONGSON_NAND_CMD_BLOCKS_ERASE BIT(4) +#define LOONGSON_NAND_CMD_ERASE BIT(3) +#define LOONGSON_NAND_CMD_WRITE BIT(2) +#define LOONGSON_NAND_CMD_READ BIT(1) +#define LOONGSON_NAND_CMD_VALID BIT(0) + +/* Bitfields of nand timing register */ +#define LOONGSON_NAND_WAIT_CYCLE_MASK GENMASK(7, 0) +#define LOONGSON_NAND_HOLD_CYCLE_MASK GENMASK(15, 8) + +/* Bitfields of nand parameter register */ +#define LOONGSON_NAND_CELL_SIZE_MASK GENMASK(11, 8) + +#define LOONGSON_NAND_COL_ADDR_CYC 2U +#define LOONGSON_NAND_MAX_ADDR_CYC 5U + +#define BITS_PER_WORD (4 * BITS_PER_BYTE) + +struct loongson_nand_host ; + +struct loongson_nand_op { +char addrs[LOONGSON_NAND_MAX_ADDR_CYC ];unsigned int naddrs;unsigned int addrs_offset;unsigned int aligned_offset;
@@ -69,19 +72,19 @@ struct ls1x_nand_op {char *buf; }; -struct ls1x_nand_data { +struct loongson_nand_data {unsigned int status_field;unsigned int op_scope_field;unsigned int hold_cycle;unsigned int wait_cycle; -void (*set_addr)(struct ls1x_nand_host *host,struct ls1x_nand_op *op); +void (*set_addr)(struct loongson_nand_host *host,struct loongson_nand_op *op); }; -struct ls1x_nand_host { +struct loongson_nand_host {struct device *dev;struct nand_chip chip;struct nand_controller controller; -const struct ls1x_nand_data *data; +const struct loongson_nand_data *data;void __iomem *reg_base;struct regmap *regmap;/* DMA Engine stuff */
@@ -91,40 +94,41 @@ struct ls1x_nand_host {struct completion dma_complete; }; -static const struct regmap_config ls1x_nand_regmap_config = { +static const struct regmap_config loongson_nand_regmap_config = { .reg_bits =32 , .val_bits =32 , .reg_stride =4 , }; -static int ls1x_nand_op_cmd_mapping (struct nand_chip *chip,struct ls1x_nand_op *op,u8 opcode) +static int loongson_nand_op_cmd_mapping (struct nand_chip *chip,struct loongson_nand_op *op, +u8 opcode) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_host *host =nand_get_controller_data (chip); op->row_start = chip->page_shift +1 ;/* The controller abstracts the following NAND operations. */ switch (opcode) {case NAND_CMD_STATUS : - op->cmd_reg =LS1X_NAND_CMD_STATUS ; + op->cmd_reg =LOONGSON_NAND_CMD_STATUS ;break ;case NAND_CMD_RESET : - op->cmd_reg =LS1X_NAND_CMD_RESET ; + op->cmd_reg =LOONGSON_NAND_CMD_RESET ;break ;case NAND_CMD_READID : op->is_readid = true; - op->cmd_reg =LS1X_NAND_CMD_READID ; + op->cmd_reg =LOONGSON_NAND_CMD_READID ;break ;case NAND_CMD_ERASE1 : op->is_erase = true; - op->addrs_offset =LS1X_NAND_COL_ADDR_CYC ; + op->addrs_offset =LOONGSON_NAND_COL_ADDR_CYC ;break ;case NAND_CMD_ERASE2 :if (!op->is_erase)return -EOPNOTSUPP ;/* During erasing, row_start differs from the default value. */ op->row_start = chip->page_shift; - op->cmd_reg =LS1X_NAND_CMD_ERASE ; + op->cmd_reg =LOONGSON_NAND_CMD_ERASE ;break ;case NAND_CMD_SEQIN : op->is_write = true;
@@ -132,7 +136,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_opcase NAND_CMD_PAGEPROG :if (!op->is_write)return -EOPNOTSUPP ; - op->cmd_reg =LS1X_NAND_CMD_WRITE ; + op->cmd_reg =LOONGSON_NAND_CMD_WRITE ;break ;case NAND_CMD_READ0 : op->is_read = true;
@@ -140,7 +144,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_opcase NAND_CMD_READSTART :if (!op->is_read)return -EOPNOTSUPP ; - op->cmd_reg =LS1X_NAND_CMD_READ ; + op->cmd_reg =LOONGSON_NAND_CMD_READ ;break ;case NAND_CMD_RNDOUT : op->is_change_column = true;
@@ -148,7 +152,7 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_opcase NAND_CMD_RNDOUTSTART :if (!op->is_change_column)return -EOPNOTSUPP ; - op->cmd_reg =LS1X_NAND_CMD_READ ; + op->cmd_reg =LOONGSON_NAND_CMD_READ ;break ;default :dev_dbg (host->dev,"unsupported opcode: %u\n" , opcode);
@@ -158,8 +162,8 @@ static int ls1x_nand_op_cmd_mapping(struct nand_chip *chip, struct ls1x_nand_opreturn 0 ; } -static int ls1x_nand_parse_instructions (struct nand_chip *chip, -const struct nand_subop *subop,struct ls1x_nand_op *op) +static int loongson_nand_parse_instructions (struct nand_chip *chip,const struct nand_subop *subop, +struct loongson_nand_op *op) {unsigned int op_id;int ret;
@@ -171,14 +175,14 @@ static int ls1x_nand_parse_instructions(struct nand_chip *chip,switch (instr->type) {case NAND_OP_CMD_INSTR : - ret =ls1x_nand_op_cmd_mapping (chip, op, instr->ctx.cmd.opcode); + ret =loongson_nand_op_cmd_mapping (chip, op, instr->ctx.cmd.opcode);if (ret <0 )return ret;break ;case NAND_OP_ADDR_INSTR : naddrs =nand_subop_get_num_addr_cyc (subop, op_id); -if (naddrs >LS1X_NAND_MAX_ADDR_CYC ) +if (naddrs >LOONGSON_NAND_MAX_ADDR_CYC )return -EOPNOTSUPP ; op->naddrs = naddrs; offset =nand_subop_get_addr_start_off (subop, op_id);
@@ -206,57 +210,57 @@ static int ls1x_nand_parse_instructions(struct nand_chip *chip,return 0 ; } -static void ls1b_nand_set_addr (struct ls1x_nand_host *host,struct ls1x_nand_op *op) +static void ls1b_nand_set_addr (struct loongson_nand_host *host,struct loongson_nand_op *op) {struct nand_chip *chip = &host->chip;int i; -for (i =0 ; i <LS1X_NAND_MAX_ADDR_CYC ; i++) { +for (i =0 ; i <LOONGSON_NAND_MAX_ADDR_CYC ; i++) {int shift, mask, val; -if (i <LS1X_NAND_COL_ADDR_CYC ) { +if (i <LOONGSON_NAND_COL_ADDR_CYC ) { shift = i *BITS_PER_BYTE ; mask = (u32 )0xff << shift; mask &=GENMASK (chip->page_shift,0 ); val = (u32 )op->addrs[i] << shift; -regmap_update_bits (host->regmap,LS1X_NAND_ADDR1 , mask, val); +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR1 , mask, val); }else if (!op->is_change_column) { - shift = op->row_start + (i -LS1X_NAND_COL_ADDR_CYC ) *BITS_PER_BYTE ; + shift = op->row_start + (i -LOONGSON_NAND_COL_ADDR_CYC ) *BITS_PER_BYTE ; mask = (u32 )0xff << shift; val = (u32 )op->addrs[i] << shift; -regmap_update_bits (host->regmap,LS1X_NAND_ADDR1 , mask, val); +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR1 , mask, val);if (i ==4 ) { mask = (u32 )0xff >> (BITS_PER_WORD - shift); val = (u32 )op->addrs[i] >> (BITS_PER_WORD - shift); -regmap_update_bits (host->regmap,LS1X_NAND_ADDR2 , mask, val); +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR2 , mask, val); } } } } -static void ls1c_nand_set_addr (struct ls1x_nand_host *host,struct ls1x_nand_op *op) +static void ls1c_nand_set_addr (struct loongson_nand_host *host,struct loongson_nand_op *op) {int i; -for (i =0 ; i <LS1X_NAND_MAX_ADDR_CYC ; i++) { +for (i =0 ; i <LOONGSON_NAND_MAX_ADDR_CYC ; i++) {int shift, mask, val; -if (i <LS1X_NAND_COL_ADDR_CYC ) { +if (i <LOONGSON_NAND_COL_ADDR_CYC ) { shift = i *BITS_PER_BYTE ; mask = (u32 )0xff << shift; val = (u32 )op->addrs[i] << shift; -regmap_update_bits (host->regmap,LS1X_NAND_ADDR1 , mask, val); +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR1 , mask, val); }else if (!op->is_change_column) { - shift = (i -LS1X_NAND_COL_ADDR_CYC ) *BITS_PER_BYTE ; + shift = (i -LOONGSON_NAND_COL_ADDR_CYC ) *BITS_PER_BYTE ; mask = (u32 )0xff << shift; val = (u32 )op->addrs[i] << shift; -regmap_update_bits (host->regmap,LS1X_NAND_ADDR2 , mask, val); +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR2 , mask, val); } } } -static void ls1x_nand_trigger_op (struct ls1x_nand_host *host,struct ls1x_nand_op *op) +static void loongson_nand_trigger_op (struct loongson_nand_host *host,struct loongson_nand_op *op) {struct nand_chip *chip = &host->chip;struct mtd_info *mtd =nand_to_mtd (chip);
@@ -280,7 +284,7 @@ static void ls1x_nand_trigger_op(struct ls1x_nand_host *host, struct ls1x_nand_oelse op->len = op->orig_len; -writel (op->len, host->reg_base +LS1X_NAND_OP_NUM ); +writel (op->len, host->reg_base +LOONGSON_NAND_OP_NUM );/* set operation area and scope */ col = op->addrs[1 ] <<BITS_PER_BYTE | op->addrs[0 ];
@@ -288,33 +292,35 @@ static void ls1x_nand_trigger_op(struct ls1x_nand_host *host, struct ls1x_nand_ounsigned int op_scope =0 ;if (col < mtd->writesize) { - op->cmd_reg |=LS1X_NAND_CMD_OP_MAIN ; + op->cmd_reg |=LOONGSON_NAND_CMD_OP_MAIN ; op_scope = mtd->writesize; } - op->cmd_reg |=LS1X_NAND_CMD_OP_SPARE ; + op->cmd_reg |=LOONGSON_NAND_CMD_OP_SPARE ; op_scope += mtd->oobsize; op_scope <<=__ffs (host->data->op_scope_field); -regmap_update_bits (host->regmap,LS1X_NAND_PARAM , +regmap_update_bits (host->regmap,LOONGSON_NAND_PARAM , host->data->op_scope_field, op_scope); }/* set command */ -writel (op->cmd_reg, host->reg_base +LS1X_NAND_CMD ); +writel (op->cmd_reg, host->reg_base +LOONGSON_NAND_CMD );/* trigger operation */ -regmap_write_bits (host->regmap,LS1X_NAND_CMD ,LS1X_NAND_CMD_VALID ,LS1X_NAND_CMD_VALID ); +regmap_write_bits (host->regmap,LOONGSON_NAND_CMD ,LOONGSON_NAND_CMD_VALID , +LOONGSON_NAND_CMD_VALID ); } -static int ls1x_nand_wait_for_op_done (struct ls1x_nand_host *host,struct ls1x_nand_op *op) +static int loongson_nand_wait_for_op_done (struct loongson_nand_host *host, +struct loongson_nand_op *op) {unsigned int val;int ret =0 ;if (op->rdy_timeout_ms) { - ret =regmap_read_poll_timeout (host->regmap,LS1X_NAND_CMD , - val, val &LS1X_NAND_CMD_OP_DONE , + ret =regmap_read_poll_timeout (host->regmap,LOONGSON_NAND_CMD , + val, val &LOONGSON_NAND_CMD_OP_DONE ,0 , op->rdy_timeout_ms *MSEC_PER_SEC );if (ret)dev_err (host->dev,"operation failed\n" );
@@ -323,9 +329,9 @@ static int ls1x_nand_wait_for_op_done(struct ls1x_nand_host *host, struct ls1x_nreturn ret; } -static void ls1x_nand_dma_callback (void *data) +static void loongson_nand_dma_callback (void *data) { -struct ls1x_nand_host *host = (struct ls1x_nand_host *)data; +struct loongson_nand_host *host = (struct loongson_nand_host *)data;struct dma_chan *chan = host->dma_chan;struct device *dev = chan->device->dev;enum dma_status status;
@@ -339,7 +345,7 @@ static void ls1x_nand_dma_callback(void *data) } } -static int ls1x_nand_dma_transfer (struct ls1x_nand_host *host,struct ls1x_nand_op *op) +static int loongson_nand_dma_transfer (struct loongson_nand_host *host,struct loongson_nand_op *op) {struct nand_chip *chip = &host->chip;struct dma_chan *chan = host->dma_chan;
@@ -374,7 +380,7 @@ static int ls1x_nand_dma_transfer(struct ls1x_nand_host *host, struct ls1x_nand_ ret = -ENOMEM ; goto err; } - desc->callback = ls1x_nand_dma_callback; + desc->callback = loongson_nand_dma_callback; desc->callback_param = host; host->dma_cookie =dmaengine_submit (desc);
@@ -405,51 +411,51 @@ static int ls1x_nand_dma_transfer(struct ls1x_nand_host *host, struct ls1x_nand_return ret; } -static int ls1x_nand_data_type_exec (struct nand_chip *chip,const struct nand_subop *subop) +static int loongson_nand_data_type_exec (struct nand_chip *chip,const struct nand_subop *subop) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); -struct ls1x_nand_op op = {}; +struct loongson_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_op op = {};int ret; - ret =ls1x_nand_parse_instructions (chip, subop, &op); + ret =loongson_nand_parse_instructions (chip, subop, &op);if (ret)return ret; -ls1x_nand_trigger_op (host, &op); +loongson_nand_trigger_op (host, &op); - ret =ls1x_nand_dma_transfer (host, &op); + ret =loongson_nand_dma_transfer (host, &op);if (ret)return ret; -return ls1x_nand_wait_for_op_done (host, &op); +return loongson_nand_wait_for_op_done (host, &op); } -static int ls1x_nand_misc_type_exec (struct nand_chip *chip, -const struct nand_subop *subop,struct ls1x_nand_op *op) +static int loongson_nand_misc_type_exec (struct nand_chip *chip,const struct nand_subop *subop, +struct loongson_nand_op *op) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_host *host =nand_get_controller_data (chip);int ret; - ret =ls1x_nand_parse_instructions (chip, subop, op); + ret =loongson_nand_parse_instructions (chip, subop, op);if (ret)return ret; -ls1x_nand_trigger_op (host, op); +loongson_nand_trigger_op (host, op); -return ls1x_nand_wait_for_op_done (host, op); +return loongson_nand_wait_for_op_done (host, op); } -static int ls1x_nand_zerolen_type_exec (struct nand_chip *chip,const struct nand_subop *subop) +static int loongson_nand_zerolen_type_exec (struct nand_chip *chip,const struct nand_subop *subop) { -struct ls1x_nand_op op = {}; +struct loongson_nand_op op = {}; -return ls1x_nand_misc_type_exec (chip, subop, &op); +return loongson_nand_misc_type_exec (chip, subop, &op); } -static int ls1x_nand_read_id_type_exec (struct nand_chip *chip,const struct nand_subop *subop) +static int loongson_nand_read_id_type_exec (struct nand_chip *chip,const struct nand_subop *subop) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); -struct ls1x_nand_op op = {}; +struct loongson_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_op op = {};int i, ret;union {char ids[5 ];
@@ -459,12 +465,12 @@ static int ls1x_nand_read_id_type_exec(struct nand_chip *chip, const struct nand }; } nand_id; - ret =ls1x_nand_misc_type_exec (chip, subop, &op); + ret =loongson_nand_misc_type_exec (chip, subop, &op);if (ret)return ret; - nand_id.idl =readl (host->reg_base +LS1X_NAND_IDL ); - nand_id.idh =readb (host->reg_base +LS1X_NAND_IDH_STATUS ); + nand_id.idl =readl (host->reg_base +LOONGSON_NAND_IDL ); + nand_id.idh =readb (host->reg_base +LOONGSON_NAND_IDH_STATUS );for (i =0 ; i <min (sizeof (nand_id.ids), op.orig_len); i++) op.buf[i] = nand_id.ids[sizeof (nand_id.ids) -1 - i];
@@ -472,60 +478,61 @@ static int ls1x_nand_read_id_type_exec(struct nand_chip *chip, const struct nandreturn ret; } -static int ls1x_nand_read_status_type_exec (struct nand_chip *chip,const struct nand_subop *subop) +static int loongson_nand_read_status_type_exec (struct nand_chip *chip, +const struct nand_subop *subop) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); -struct ls1x_nand_op op = {}; +struct loongson_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_op op = {};int val, ret; - ret =ls1x_nand_misc_type_exec (chip, subop, &op); + ret =loongson_nand_misc_type_exec (chip, subop, &op);if (ret)return ret; - val =readl (host->reg_base +LS1X_NAND_IDH_STATUS ); + val =readl (host->reg_base +LOONGSON_NAND_IDH_STATUS ); val &= ~host->data->status_field; op.buf[0 ] = val <<ffs (host->data->status_field);return ret; } -static const struct nand_op_parser ls1x_nand_op_parser =NAND_OP_PARSER ( +static const struct nand_op_parser loongson_nand_op_parser =NAND_OP_PARSER (NAND_OP_PARSER_PATTERN ( - ls1x_nand_read_id_type_exec, + loongson_nand_read_id_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false), -NAND_OP_PARSER_PAT_ADDR_ELEM (false,LS1X_NAND_MAX_ADDR_CYC ), +NAND_OP_PARSER_PAT_ADDR_ELEM (false,LOONGSON_NAND_MAX_ADDR_CYC ),NAND_OP_PARSER_PAT_DATA_IN_ELEM (false,8 )),NAND_OP_PARSER_PATTERN ( - ls1x_nand_read_status_type_exec, + loongson_nand_read_status_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false),NAND_OP_PARSER_PAT_DATA_IN_ELEM (false,1 )),NAND_OP_PARSER_PATTERN ( - ls1x_nand_zerolen_type_exec, + loongson_nand_zerolen_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false),NAND_OP_PARSER_PAT_WAITRDY_ELEM (false)),NAND_OP_PARSER_PATTERN ( - ls1x_nand_zerolen_type_exec, + loongson_nand_zerolen_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false), -NAND_OP_PARSER_PAT_ADDR_ELEM (false,LS1X_NAND_MAX_ADDR_CYC ), +NAND_OP_PARSER_PAT_ADDR_ELEM (false,LOONGSON_NAND_MAX_ADDR_CYC ),NAND_OP_PARSER_PAT_CMD_ELEM (false),NAND_OP_PARSER_PAT_WAITRDY_ELEM (false)),NAND_OP_PARSER_PATTERN ( - ls1x_nand_data_type_exec, + loongson_nand_data_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false), -NAND_OP_PARSER_PAT_ADDR_ELEM (false,LS1X_NAND_MAX_ADDR_CYC ), +NAND_OP_PARSER_PAT_ADDR_ELEM (false,LOONGSON_NAND_MAX_ADDR_CYC ),NAND_OP_PARSER_PAT_CMD_ELEM (false),NAND_OP_PARSER_PAT_WAITRDY_ELEM (true),NAND_OP_PARSER_PAT_DATA_IN_ELEM (false,0 )),NAND_OP_PARSER_PATTERN ( - ls1x_nand_data_type_exec, + loongson_nand_data_type_exec,NAND_OP_PARSER_PAT_CMD_ELEM (false), -NAND_OP_PARSER_PAT_ADDR_ELEM (false,LS1X_NAND_MAX_ADDR_CYC ), +NAND_OP_PARSER_PAT_ADDR_ELEM (false,LOONGSON_NAND_MAX_ADDR_CYC ),NAND_OP_PARSER_PAT_DATA_OUT_ELEM (false,0 ),NAND_OP_PARSER_PAT_CMD_ELEM (false), NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)), ); -static int ls1x_nand_is_valid_cmd (u8 opcode) +static int loongson_nand_is_valid_cmd (u8 opcode) {if (opcode ==NAND_CMD_STATUS || opcode ==NAND_CMD_RESET || opcode ==NAND_CMD_READID )return 0 ;
@@ -533,7 +540,7 @@ static int ls1x_nand_is_valid_cmd(u8 opcode)return -EOPNOTSUPP ; } -static int ls1x_nand_is_valid_cmd_seq (u8 opcode1,u8 opcode2) +static int loongson_nand_is_valid_cmd_seq (u8 opcode1,u8 opcode2) {if (opcode1 ==NAND_CMD_RNDOUT && opcode2 ==NAND_CMD_RNDOUTSTART )return 0 ;
@@ -550,7 +557,7 @@ static int ls1x_nand_is_valid_cmd_seq(u8 opcode1, u8 opcode2)return -EOPNOTSUPP ; } -static int ls1x_nand_check_op (struct nand_chip *chip,const struct nand_operation *op) +static int loongson_nand_check_op (struct nand_chip *chip,const struct nand_operation *op) {const struct nand_op_instr *instr1 =NULL , *instr2 =NULL ;int op_id;
@@ -572,23 +579,23 @@ static int ls1x_nand_check_op(struct nand_chip *chip, const struct nand_operatioreturn -EOPNOTSUPP ;if (!instr2) -return ls1x_nand_is_valid_cmd (instr1->ctx.cmd.opcode); +return loongson_nand_is_valid_cmd (instr1->ctx.cmd.opcode); -return ls1x_nand_is_valid_cmd_seq (instr1->ctx.cmd.opcode, instr2->ctx.cmd.opcode); +return loongson_nand_is_valid_cmd_seq (instr1->ctx.cmd.opcode, instr2->ctx.cmd.opcode); } -static int ls1x_nand_exec_op (struct nand_chip *chip, -const struct nand_operation *op,bool check_only) +static int loongson_nand_exec_op (struct nand_chip *chip,const struct nand_operation *op, +bool check_only) {if (check_only) -return ls1x_nand_check_op (chip, op); +return loongson_nand_check_op (chip, op); -return nand_op_parser_exec_op (chip, &ls1x_nand_op_parser, op, check_only); +return nand_op_parser_exec_op (chip, &loongson_nand_op_parser, op, check_only); } -static int ls1x_nand_attach_chip (struct nand_chip *chip) +static int loongson_nand_attach_chip (struct nand_chip *chip) { -struct ls1x_nand_host *host =nand_get_controller_data (chip); +struct loongson_nand_host *host =nand_get_controller_data (chip);u64 chipsize =nanddev_target_size (&chip->base);int cell_size =0 ;
@@ -632,14 +639,14 @@ static int ls1x_nand_attach_chip(struct nand_chip *chip) }/* set cell size */ -regmap_update_bits (host->regmap,LS1X_NAND_PARAM ,LS1X_NAND_CELL_SIZE_MASK , -FIELD_PREP (LS1X_NAND_CELL_SIZE_MASK , cell_size)); +regmap_update_bits (host->regmap,LOONGSON_NAND_PARAM ,LOONGSON_NAND_CELL_SIZE_MASK , +FIELD_PREP (LOONGSON_NAND_CELL_SIZE_MASK , cell_size)); -regmap_update_bits (host->regmap,LS1X_NAND_TIMING ,LS1X_NAND_HOLD_CYCLE_MASK , -FIELD_PREP (LS1X_NAND_HOLD_CYCLE_MASK , host->data->hold_cycle)); +regmap_update_bits (host->regmap,LOONGSON_NAND_TIMING ,LOONGSON_NAND_HOLD_CYCLE_MASK , +FIELD_PREP (LOONGSON_NAND_HOLD_CYCLE_MASK , host->data->hold_cycle)); -regmap_update_bits (host->regmap,LS1X_NAND_TIMING ,LS1X_NAND_WAIT_CYCLE_MASK , -FIELD_PREP (LS1X_NAND_WAIT_CYCLE_MASK , host->data->wait_cycle)); +regmap_update_bits (host->regmap,LOONGSON_NAND_TIMING ,LOONGSON_NAND_WAIT_CYCLE_MASK , +FIELD_PREP (LOONGSON_NAND_WAIT_CYCLE_MASK , host->data->wait_cycle)); chip->ecc.read_page_raw = nand_monolithic_read_page_raw; chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
@@ -647,25 +654,25 @@ static int ls1x_nand_attach_chip(struct nand_chip *chip)return 0 ; } -static const struct nand_controller_ops ls1x_nand_controller_ops = { - .exec_op = ls1x_nand_exec_op, - .attach_chip = ls1x_nand_attach_chip, +static const struct nand_controller_ops loongson_nand_controller_ops = { + .exec_op = loongson_nand_exec_op, + .attach_chip = loongson_nand_attach_chip, }; -static void ls1x_nand_controller_cleanup (struct ls1x_nand_host *host) +static void loongson_nand_controller_cleanup (struct loongson_nand_host *host) {if (host->dma_chan)dma_release_channel (host->dma_chan); } -static int ls1x_nand_controller_init (struct ls1x_nand_host *host) +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; - host->regmap =devm_regmap_init_mmio (dev, host->reg_base, &ls1x_nand_regmap_config); + host->regmap =devm_regmap_init_mmio (dev, host->reg_base, &loongson_nand_regmap_config);if (IS_ERR (host->regmap))return dev_err_probe (dev,PTR_ERR (host->regmap),"failed to init regmap\n" );
@@ -687,7 +694,7 @@ static int ls1x_nand_controller_init(struct ls1x_nand_host *host)return 0 ; } -static int ls1x_nand_chip_init (struct ls1x_nand_host *host) +static int loongson_nand_chip_init (struct loongson_nand_host *host) {struct device *dev = host->dev;int nchips =of_get_child_count (dev->of_node);
@@ -728,11 +735,11 @@ static int ls1x_nand_chip_init(struct ls1x_nand_host *host)return 0 ; } -static int ls1x_nand_probe (struct platform_device *pdev) +static int loongson_nand_probe (struct platform_device *pdev) {struct device *dev = &pdev->dev; -const struct ls1x_nand_data *data; -struct ls1x_nand_host *host; +const struct loongson_nand_data *data; +struct loongson_nand_host *host;struct resource *res;int ret;
@@ -759,15 +766,15 @@ static int ls1x_nand_probe(struct platform_device *pdev) host->dev = dev; host->data = data; - host->controller.ops = &ls1x_nand_controller_ops; + host->controller.ops = &loongson_nand_controller_ops;nand_controller_init (&host->controller); - ret =ls1x_nand_controller_init (host); + ret =loongson_nand_controller_init (host);if (ret) goto err; - ret =ls1x_nand_chip_init (host); + ret =loongson_nand_chip_init (host);if (ret) goto err;
@@ -775,31 +782,31 @@ static int ls1x_nand_probe(struct platform_device *pdev)return 0 ; err: -ls1x_nand_controller_cleanup (host); +loongson_nand_controller_cleanup (host);return ret; } -static void ls1x_nand_remove (struct platform_device *pdev) +static void loongson_nand_remove (struct platform_device *pdev) { -struct ls1x_nand_host *host =platform_get_drvdata (pdev); +struct loongson_nand_host *host =platform_get_drvdata (pdev);struct nand_chip *chip = &host->chip;int ret; ret =mtd_device_unregister (nand_to_mtd (chip));WARN_ON (ret);nand_cleanup (chip); -ls1x_nand_controller_cleanup (host); +loongson_nand_controller_cleanup (host); } -static const struct ls1x_nand_data ls1b_nand_data = { +static const struct loongson_nand_data ls1b_nand_data = { .status_field =GENMASK (15 ,8 ), .hold_cycle =0x2 , .wait_cycle =0xc , .set_addr = ls1b_nand_set_addr, }; -static const struct ls1x_nand_data ls1c_nand_data = { +static const struct loongson_nand_data ls1c_nand_data = { .status_field =GENMASK (23 ,16 ), .op_scope_field =GENMASK (29 ,16 ), .hold_cycle =0x2 ,
@@ -807,7 +814,7 @@ static const struct ls1x_nand_data ls1c_nand_data = { .set_addr = ls1c_nand_set_addr, }; -static const struct of_device_id ls1x_nand_match[] = { +static const struct of_device_id loongson_nand_match[] = { { .compatible ="loongson,ls1b-nand-controller" , .data = &ls1b_nand_data,
@@ -818,19 +825,19 @@ static const struct of_device_id ls1x_nand_match[] = { }, {/* sentinel */ } }; -MODULE_DEVICE_TABLE (of, ls1x_nand_match); +MODULE_DEVICE_TABLE (of, loongson_nand_match); -static struct platform_driver ls1x_nand_driver = { - .probe = ls1x_nand_probe, - .remove = ls1x_nand_remove, +static struct platform_driver loongson_nand_driver = { + .probe = loongson_nand_probe, + .remove = loongson_nand_remove, .driver = { .name =KBUILD_MODNAME , - .of_match_table = ls1x_nand_match, + .of_match_table = loongson_nand_match, }, }; -module_platform_driver (ls1x_nand_driver); +module_platform_driver (loongson_nand_driver);MODULE_AUTHOR ("Keguang Zhang <[email protected]>" ); -MODULE_DESCRIPTION ("Loongson-1 NAND Controller Driver" ); +MODULE_DESCRIPTION ("Loongson NAND Controller Driver" );MODULE_LICENSE ("GPL" );
Signature · 1 line
2.47.3
PATCH 2/8 mtd: rawnand: loongson: Rename loongson1 to loongson
In reply to Binbin ZhouThe second step in preparing to add Loongson-2K support is to change the names of the driver files and Kconfig options from Loongson1-specific to Loongson-generic.
---
MAINTAINERS | 2 +-
drivers/mtd/nand/raw/Kconfig | 6 +++---
drivers/mtd/nand/raw/Makefile | 2 +-
...ongson1-nand-controller.c => loongson-nand-controller.c} | 0
4 files changed, 5 insertions(+), 5 deletions(-)
rename drivers/mtd/nand/raw/{loongson1-nand-controller.c => loongson-nand-controller.c} (100%)MAINTAINERS +1 -1
@@ -16685,7 +16685,7 @@ F: Documentation/devicetree/bindings/*/loongson,ls1*.yaml F: arch/mips/include/asm/mach-loongson32/ F: arch/mips/loongson32/ F: drivers/*/*loongson1* -F: drivers/mtd/nand/raw/loongson1-nand-controller.c +F: drivers/mtd/nand/raw/loongson-nand-controller.c F: drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c F: sound/soc/loongson/loongson1_ac97.c
drivers/mtd/nand/raw/Kconfig +3 -3
@@ -462,12 +462,12 @@ config MTD_NAND_NUVOTON_MA35 Enables support for the NAND controller found on the Nuvoton MA35 series SoCs. -config MTD_NAND_LOONGSON1 - tristate "Loongson1 NAND controller" +config MTD_NAND_LOONGSON + tristate "Loongson NAND controller" depends on LOONGSON1_APB_DMA || COMPILE_TEST select REGMAP_MMIO help - Enables support for NAND controller on Loongson1 SoCs. + Enables support for NAND controller on Loongson family chips. comment "Misc"
drivers/mtd/nand/raw/Makefile +1 -1
@@ -59,7 +59,7 @@ obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o obj-$(CONFIG_MTD_NAND_RENESAS) += renesas-nand-controller.o obj-$(CONFIG_MTD_NAND_NUVOTON_MA35) += nuvoton-ma35d1-nand-controller.o -obj-$(CONFIG_MTD_NAND_LOONGSON1) += loongson1-nand-controller.o +obj-$(CONFIG_MTD_NAND_LOONGSON) += loongson-nand-controller.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs += nand_onfi.o
drivers/mtd/nand/raw/loongson-nand-controller.c renamed from drivers/mtd/nand/raw/loongson1-nand-controller.c +0 -0
Signature · 1 line
2.47.3
PATCH 3/8 mtd: rawnand: loongson: Add 6-byte NAND ID reading support
In reply to Binbin ZhouFrom: Keguang Zhang <[email protected]>
Loongson-1C and Loongson-2K SoCs support NAND flash chips with 6-byte ID. However, the current implementation only handles 5-byte ID which can lead to incorrect chip detection.
Extend loongson_nand_read_id_type_exec() to support 6-byte NAND ID.
--- .../mtd/nand/raw/loongson-nand-controller.c | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/mtd/nand/raw/loongson-nand-controller.c +23 -6
@@ -50,6 +50,9 @@#define LOONGSON_NAND_COL_ADDR_CYC 2U#define LOONGSON_NAND_MAX_ADDR_CYC 5U +#define LOONGSON_NAND_READ_ID_SLEEP_US 1000 +#define LOONGSON_NAND_READ_ID_TIMEOUT_US 5000 +#define BITS_PER_WORD (4 * BITS_PER_BYTE)struct loongson_nand_host ;
@@ -73,6 +76,8 @@ struct loongson_nand_op { };struct loongson_nand_data { +unsigned int max_id_cycle; +unsigned int id_cycle_field;unsigned int status_field;unsigned int op_scope_field;unsigned int hold_cycle;
@@ -458,10 +463,10 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const structstruct loongson_nand_op op = {};int i, ret;union { -char ids[5 ]; +char ids[6 ];struct {int idl; -char idh; +u16 idh; }; } nand_id;
@@ -469,11 +474,16 @@ static int loongson_nand_read_id_type_exec(struct nand_chip *chip, const structif (ret)return ret; - nand_id.idl =readl (host->reg_base +LOONGSON_NAND_IDL ); - nand_id.idh =readb (host->reg_base +LOONGSON_NAND_IDH_STATUS ); + ret =regmap_read_poll_timeout (host->regmap,LOONGSON_NAND_IDL , nand_id.idl, nand_id.idl, +LOONGSON_NAND_READ_ID_SLEEP_US , +LOONGSON_NAND_READ_ID_TIMEOUT_US ); +if (ret) +return ret; -for (i =0 ; i <min (sizeof (nand_id.ids), op.orig_len); i++) - op.buf[i] = nand_id.ids[sizeof (nand_id.ids) -1 - i]; + nand_id.idh =readw (host->reg_base +LOONGSON_NAND_IDH_STATUS ); + +for (i =0 ; i <min (host->data->max_id_cycle, op.orig_len); i++) + op.buf[i] = nand_id.ids[host->data->max_id_cycle -1 - i];return ret; }
@@ -676,6 +686,10 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)if (IS_ERR (host->regmap))return dev_err_probe (dev,PTR_ERR (host->regmap),"failed to init regmap\n" ); +if (host->data->id_cycle_field) +regmap_update_bits (host->regmap,LOONGSON_NAND_PARAM , host->data->id_cycle_field, + host->data->max_id_cycle <<__ffs (host->data->id_cycle_field)); + chan =dma_request_chan (dev,"rxtx" );if (IS_ERR (chan))return dev_err_probe (dev,PTR_ERR (chan),"failed to request DMA channel\n" );
@@ -800,6 +814,7 @@ static void loongson_nand_remove(struct platform_device *pdev) }static const struct loongson_nand_data ls1b_nand_data = { + .max_id_cycle =5 , .status_field =GENMASK (15 ,8 ), .hold_cycle =0x2 , .wait_cycle =0xc ,
@@ -807,6 +822,8 @@ static const struct loongson_nand_data ls1b_nand_data = { };static const struct loongson_nand_data ls1c_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 =0x2 ,
Signature · 1 line
2.47.3
PATCH 4/8 mtd: rawnand: loongson: Add nand chip select support
In reply to Binbin ZhouThe page address register describes the page address of the starting address for NAND read/write/erase operations.
According to the manual, it consists of two parts:
{chip select, page number}The chip select is fixed at 2 bits, and the page number is determined based on the actual capacity of the single-chip memory. Therefore we need to determine the chip select bits base on the page number.
For example, for a 1GB capacity chip (2K page size), it has 1M pages. Thus, [19:0] is used to represent the page number, and [21:20] represents the chip select.
--- .../mtd/nand/raw/loongson-nand-controller.c | 133 ++++++++++++++---- 1 file changed, 103 insertions(+), 30 deletions(-)
drivers/mtd/nand/raw/loongson-nand-controller.c +103 -30
@@ -82,6 +82,7 @@ struct loongson_nand_data {unsigned int op_scope_field;unsigned int hold_cycle;unsigned int wait_cycle; +unsigned int nand_cs;void (*set_addr)(struct loongson_nand_host *host,struct loongson_nand_op *op); };
@@ -90,6 +91,7 @@ struct loongson_nand_host {struct nand_chip chip;struct nand_controller controller;const struct loongson_nand_data *data; +unsigned int addr_cs_field;void __iomem *reg_base;struct regmap *regmap;/* DMA Engine stuff */
@@ -215,6 +217,26 @@ static int loongson_nand_parse_instructions(struct nand_chip *chip, const structreturn 0 ; } +static void loongson_nand_set_addr_cs (struct loongson_nand_host *host) +{ +struct nand_chip *chip = &host->chip; +struct mtd_info *mtd =nand_to_mtd (chip); + +if (!host->data->nand_cs) +return ; + +/* +* The Manufacturer/Chip ID read operation precedes attach_chip, at which point +* information such as NAND chip selection and capacity is unknown. As a +* workaround, we use 128MB cellsize (2KB pagesize) as a fallback. +*/ +if (!mtd->writesize) + host->addr_cs_field =GENMASK (17 ,16 ); + +regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR2 , host->addr_cs_field, + host->data->nand_cs <<__ffs (host->addr_cs_field)); +} +static void ls1b_nand_set_addr (struct loongson_nand_host *host,struct loongson_nand_op *op) {struct nand_chip *chip = &host->chip;
@@ -263,6 +285,8 @@ static void ls1c_nand_set_addr(struct loongson_nand_host *host, struct loongson_regmap_update_bits (host->regmap,LOONGSON_NAND_ADDR2 , mask, val); } } + +loongson_nand_set_addr_cs (host); }static void loongson_nand_trigger_op (struct loongson_nand_host *host,struct loongson_nand_op *op)
@@ -603,42 +627,89 @@ static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_operareturn nand_op_parser_exec_op (chip, &loongson_nand_op_parser, op, check_only); } -static int loongson_nand_attach_chip (struct nand_chip *chip) +static int loongson_nand_get_chip_capacity (struct nand_chip *chip) {struct loongson_nand_host *host =nand_get_controller_data (chip);u64 chipsize =nanddev_target_size (&chip->base); -int cell_size =0 ; +struct mtd_info *mtd =nand_to_mtd (chip); -switch (chipsize) { -case SZ_128M : - cell_size =0x0 ; -break ; -case SZ_256M : - cell_size =0x1 ; -break ; -case SZ_512M : - cell_size =0x2 ; -break ; -case SZ_1G : - cell_size =0x3 ; -break ; -case SZ_2G : - cell_size =0x4 ; -break ; -case SZ_4G : - cell_size =0x5 ; -break ; -case SZ_8G : - cell_size =0x6 ; -break ; -case SZ_16G : - cell_size =0x7 ; -break ; -default : -dev_err (host->dev,"unsupported chip size: %llu MB\n" , chipsize); -return -EINVAL ; +if (mtd->writesize ==SZ_4K && chipsize ==SZ_2G ) { + host->addr_cs_field =GENMASK (20 ,19 ); +return 0x4 ; } +if (mtd->writesize ==SZ_2K ) { +switch (chipsize) { +case SZ_128M : + host->addr_cs_field =GENMASK (17 ,16 ); +return 0 ; +case SZ_256M : + host->addr_cs_field =GENMASK (18 ,17 ); +return 0x1 ; +case SZ_512M : + host->addr_cs_field =GENMASK (19 ,18 ); +return 0x2 ; +case SZ_1G : + host->addr_cs_field =GENMASK (20 ,19 ); +return 0x3 ; +default : + goto err; + } + } + +if (mtd->writesize ==SZ_8K ) { +switch (chipsize) { +case SZ_4G : + host->addr_cs_field =GENMASK (20 ,19 ); +return 0x5 ; +case SZ_8G : + host->addr_cs_field =GENMASK (21 ,20 ); +return 0x6 ; +case SZ_16G : + host->addr_cs_field =GENMASK (22 ,21 ); +return 0x7 ; +default : + goto err; + } + } + +if (mtd->writesize ==SZ_512 ) { +switch (chipsize) { +case SZ_8M : + host->addr_cs_field =GENMASK (15 ,14 ); +return 0x9 ; +case SZ_16M : + host->addr_cs_field =GENMASK (16 ,15 ); +return 0xa ; +case SZ_32M : + host->addr_cs_field =GENMASK (17 ,16 ); +return 0xb ; +case SZ_64M : + host->addr_cs_field =GENMASK (18 ,17 ); +return 0xc ; +case SZ_128M : + host->addr_cs_field =GENMASK (19 ,18 ); +return 0xd ; +default : + goto err; + } + } + +err: +dev_err (host->dev,"Unsupported chip size: %llu MB with page size %u B\n" , + chipsize, mtd->writesize); +return -EINVAL ; +} + +static int loongson_nand_attach_chip (struct nand_chip *chip) +{ +struct loongson_nand_host *host =nand_get_controller_data (chip); +int cell_size =0 ; + + cell_size =loongson_nand_get_chip_capacity (chip); +if (cell_size <0 ) +return cell_size; +switch (chip->ecc.engine_type) {case NAND_ECC_ENGINE_TYPE_NONE :break ;
@@ -818,6 +889,7 @@ static const struct loongson_nand_data ls1b_nand_data = { .status_field = GENMASK(15, 8), .hold_cycle = 0x2, .wait_cycle = 0xc, + .nand_cs = 0x0, .set_addr = ls1b_nand_set_addr, };
@@ -828,6 +900,7 @@ static const struct loongson_nand_data ls1c_nand_data = { .op_scope_field = GENMASK(29, 16), .hold_cycle = 0x2, .wait_cycle = 0xc, + .nand_cs = 0x0, .set_addr = ls1c_nand_set_addr, };
Signature · 1 line
2.47.3
PATCH 5/8 dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K0500 NAND controller
In reply to Binbin ZhouAdd new compatible for the Loongson-2K NAND controller used for Loongson-2K0500 SoC.
--- .../bindings/mtd/loongson,ls1b-nand-controller.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +4 -2
@@ -4,13 +4,14 @@ $id: http://devicetree.org/schemas/mtd/loongson,ls1b-nand-controller.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Loongson-1 NAND Controller +title: Loongson NAND Controller maintainers: - Keguang Zhang <[email protected]> + - Binbin Zhou <[email protected]> description: - The Loongson-1 NAND controller abstracts all supported operations, + The Loongson NAND controller abstracts all supported operations, meaning it does not support low-level access to raw NAND flash chips. Moreover, the controller is paired with the DMA engine to perform READ and PROGRAM functions.
@@ -24,6 +25,7 @@ properties: - enum: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller + - loongson,ls2k0500-nand-controller - items: - enum: - loongson,ls1a-nand-controller
Signature · 1 line
2.47.3
Re: [PATCH v1 5/8] dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K0500 NAND controller
Quoted 8 lines · Binbin Zhou
Add new compatible for the Loongson-2K NAND controller used for Loongson-2K0500 SoC.
Signed-off-by Binbin Zhou <[email protected]>--- .../bindings/mtd/loongson,ls1b-nand-controller.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
PATCH 6/8 mtd: rawnand: loongson: Add Loongson-2K0500 NAND controller support
In reply to Binbin ZhouThe 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.
--- drivers/mtd/nand/raw/Kconfig | 2 +- .../mtd/nand/raw/loongson-nand-controller.c | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-)
drivers/mtd/nand/raw/Kconfig +1 -1
@@ -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.
drivers/mtd/nand/raw/loongson-nand-controller.c +53 -2
126 lines not on this page · raw message
Signature · 1 line
2.47.3
PATCH 7/8 dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K1000 NAND controller
In reply to Binbin ZhouAdd new compatible for the Loongson-2K NAND controller used for Loongson-2K1000 SoC.
--- .../mtd/loongson,ls1b-nand-controller.yaml | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-)
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +54 -4
@@ -26,18 +26,19 @@ properties: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller - loongson,ls2k0500-nand-controller + - loongson,ls2k1000-nand-controller - items: - enum: - loongson,ls1a-nand-controller - const: loongson,ls1b-nand-controller reg: - maxItems: 2 + minItems: 2 + maxItems: 3 reg-names: - items: - - const: nand - - const: nand-dma + minItems: 2 + maxItems: 3 dmas: maxItems: 1
@@ -54,6 +55,32 @@ required: unevaluatedProperties: false +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k1000-nand-controller + +then: + properties: + reg: + minItems: 3 + reg-names: + items: + - const: nand + - const: nand-dma + - const: dma-config + +else: + properties: + reg: + maxItems: 2 + reg-names: + items: + - const: nand + - const: nand-dma + examples: - | nand-controller@1fe78000 {
@@ -72,3 +99,26 @@ examples: nand-ecc-algo = "hamming"; }; }; + + - | + nand-controller@1fe26000 { + compatible = "loongson,ls2k1000-nand-controller"; + reg = <0x1fe26000 0x24>, + <0x1fe26040 0x4>, + <0x1fe00438 0x8>; + reg-names = "nand", "nand-dma", "dma-config"; + dmas = <&apbdma0 0>; + dma-names = "rxtx"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + label = "ls2k1000-nand"; + nand-use-soft-ecc-engine; + nand-ecc-algo = "bch"; + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + }; + };
Signature · 1 line
2.47.3
Rob Herring
maintainerRe: [PATCH v1 7/8] dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K1000 NAND controller
Quoted 21 lines · Binbin Zhou
Add new compatible for the Loongson-2K NAND controller used for Loongson-2K1000 SoC.
Signed-off-by Binbin Zhou <[email protected]>--- .../mtd/loongson,ls1b-nand-controller.yaml | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-)Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +1
-0@@ -26,18 +26,19 @@ properties: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller - loongson,ls2k0500-nand-controller + - loongson,ls2k1000-nand-controller - items: - enum: - loongson,ls1a-nand-controller - const: loongson,ls1b-nand-controller
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml properties: · line 40
Quoted 10 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +2
-4reg: - maxItems: 2 + minItems: 2 + maxItems: 3 reg-names: - items: - - const: nand - - const: nand-dma
Keep the list and add dma-config here and 'minItems: 2'
Quoted 15 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +8
-0+ minItems: 2 + maxItems: 3 dmas: maxItems: 1@@ -54,6 +55,32 @@ required: unevaluatedProperties: false +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k1000-nand-controller
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml required: · line 73
Quoted 10 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +10
-0+ +then: + properties: + reg: + minItems: 3 + reg-names: + items: + - const: nand + - const: nand-dma + - const: dma-config
And just 'minItems: 3' here
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml required: · line 82
Quoted 9 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +9
-0+ +else: + properties: + reg: + maxItems: 2 + reg-names: + items: + - const: nand + - const: nand-dma
And 'maxItems: 2' here.
Quoted 34 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +24
-0+ examples: - | nand-controller@1fe78000 {@@ -72,3 +99,26 @@ examples: nand-ecc-algo = "hamming"; }; }; + + - | + nand-controller@1fe26000 { + compatible = "loongson,ls2k1000-nand-controller"; + reg = <0x1fe26000 0x24>, + <0x1fe26040 0x4>, + <0x1fe00438 0x8>; + reg-names = "nand", "nand-dma", "dma-config"; + dmas = <&apbdma0 0>; + dma-names = "rxtx"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + label = "ls2k1000-nand"; + nand-use-soft-ecc-engine; + nand-ecc-algo = "bch"; + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + }; + };Signature · 1 line
2.47.3
Re: [PATCH v1 7/8] dt-bindings: mtd: loongson,ls1b-nand-controller: Document the Loongson-2K1000 NAND controller
Hi Rob:
Thanks for your review.
Quoted 29 lines · Rob Herring
Quoted 27 lines · Binbin Zhou
Add new compatible for the Loongson-2K NAND controller used for Loongson-2K1000 SoC.
Signed-off-by Binbin Zhou <[email protected]>--- .../mtd/loongson,ls1b-nand-controller.yaml | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-)Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +3
-1@@ -26,18 +26,19 @@ properties: - loongson,ls1b-nand-controller - loongson,ls1c-nand-controller - loongson,ls2k0500-nand-controller + - loongson,ls2k1000-nand-controller - items: - enum: - loongson,ls1a-nand-controller - const: loongson,ls1b-nand-controller reg: - maxItems: 2 + minItems: 2 + maxItems: 3
Quoted 6 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml properties: · line 40
Quoted 4 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +0
-3reg-names: - items: - - const: nand - - const: nand-dmaKeep the list and add dma-config here and 'minItems: 2'
OK, It will be rewritten as follows:
reg-names:
minItems: 2
items:
- const: nand
- const: nand-dma
- const: dma-config
Quoted 20 lines
Quoted 20 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +12
-0+ minItems: 2 + maxItems: 3 dmas: maxItems: 1@@ -54,6 +55,32 @@ required: unevaluatedProperties: false +if: + properties: + compatible: + contains: + enum: + - loongson,ls2k1000-nand-controller + +then: + properties: + reg:
Quoted 8 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml required: · line 73
Quoted 6 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +6
-0+ minItems: 3 + reg-names: + items: + - const: nand + - const: nand-dma + - const: dma-configAnd just 'minItems: 3' here
OK...
Quoted 12 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml required: · line 82
Quoted 10 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +9
-0+ +else: + properties: + reg: + maxItems: 2 + reg-names: + items: + - const: nand + - const: nand-dmaAnd 'maxItems: 2' here.
OK...
Quoted 27 lines
Quoted 27 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +19
-0+ examples: - | nand-controller@1fe78000 {@@ -72,3 +99,26 @@ examples: nand-ecc-algo = "hamming"; }; }; + + - | + nand-controller@1fe26000 { + compatible = "loongson,ls2k1000-nand-controller"; + reg = <0x1fe26000 0x24>, + <0x1fe26040 0x4>, + <0x1fe00438 0x8>; + reg-names = "nand", "nand-dma", "dma-config"; + dmas = <&apbdma0 0>; + dma-names = "rxtx"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + label = "ls2k1000-nand"; + nand-use-soft-ecc-engine;
Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/mtd/loongson,ls1b-nand-controller.yaml +5
-1+ nand-ecc-algo = "bch"; + nand-ecc-strength = <8>; + nand-ecc-step-size = <512>; + }; + }; --2.47.3
--
Thanks.
Binbin
PATCH 8/8 mtd: rawnand: loongson: Add Loongson-2K1000 NAND controller support
In reply to Binbin ZhouThe 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.
--- .../mtd/nand/raw/loongson-nand-controller.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+)
drivers/mtd/nand/raw/loongson-nand-controller.c +48 -0
@@ -73,9 +73,18 @@#define LOONGSON_NAND_READ_ID_TIMEOUT_US 5000#define LOONGSON_NAND_64BIT_DMA BIT(0) +#define LOONGSON_NAND_DMA_CONFIG BIT(1)#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 {
@@ -768,6 +777,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 (pdev,2 ); +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;
@@ -786,6 +812,12 @@ static int loongson_nand_controller_init(struct loongson_nand_host *host)if (host->data->flags &LOONGSON_NAND_64BIT_DMA )dma_set_mask_and_coherent (dev,DMA_BIT_MASK (64 )); +if (host->data->flags &LOONGSON_NAND_DMA_CONFIG ) { + ret =ls2k1000_nand_apbdma_config (dev); +if (ret) +return ret; + } + chan =dma_request_chan (dev,"rxtx" );if (IS_ERR (chan))return dev_err_probe (dev,PTR_ERR (chan),"failed to request DMA channel\n" );
@@ -950,6 +982,18 @@ 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 , + .flags =LOONGSON_NAND_64BIT_DMA |LOONGSON_NAND_DMA_CONFIG , + .set_addr = ls1c_nand_set_addr, +}; +static const struct of_device_id loongson_nand_match[] = { { .compatible ="loongson,ls1b-nand-controller" ,
@@ -963,6 +1007,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);
Signature · 1 line
2.47.3