mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
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 <zhoubinbin@loongson.cn> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
parent
4a2bab7ccc
commit
e55bbdd4a4
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* NAND Controller Driver for Loongson family chips
|
||||
*
|
||||
* Copyright (C) 2015-2025 Keguang Zhang <keguang.zhang@gmail.com>
|
||||
* Copyright (C) 2025 Binbin Zhou <zhoubinbin@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)
|
||||
|
|
@ -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 <keguang.zhang@gmail.com>");
|
||||
MODULE_AUTHOR("Binbin Zhou <zhoubinbin@loongson.cn>");
|
||||
MODULE_DESCRIPTION("Loongson NAND Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user