Skip to content

Commit 7ad5bdf

Browse files
AaronDotmiquelraynal
authored andcommitted
mtd: rawnand: loongson: Add nand chip select support
The 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. Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
1 parent fb1dd6b commit 7ad5bdf

1 file changed

Lines changed: 90 additions & 26 deletions

File tree

drivers/mtd/nand/raw/loongson-nand-controller.c

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct loongson_nand_data {
8282
unsigned int op_scope_field;
8383
unsigned int hold_cycle;
8484
unsigned int wait_cycle;
85+
unsigned int nand_cs;
8586
void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op);
8687
};
8788

@@ -90,6 +91,7 @@ struct loongson_nand_host {
9091
struct nand_chip chip;
9192
struct nand_controller controller;
9293
const struct loongson_nand_data *data;
94+
unsigned int addr_cs_field;
9395
void __iomem *reg_base;
9496
struct regmap *regmap;
9597
/* DMA Engine stuff */
@@ -215,6 +217,26 @@ static int loongson_nand_parse_instructions(struct nand_chip *chip, const struct
215217
return 0;
216218
}
217219

220+
static void loongson_nand_set_addr_cs(struct loongson_nand_host *host)
221+
{
222+
struct nand_chip *chip = &host->chip;
223+
struct mtd_info *mtd = nand_to_mtd(chip);
224+
225+
if (!host->data->nand_cs)
226+
return;
227+
228+
/*
229+
* The Manufacturer/Chip ID read operation precedes attach_chip, at which point
230+
* information such as NAND chip selection and capacity is unknown. As a
231+
* workaround, we use 128MB cellsize (2KB pagesize) as a fallback.
232+
*/
233+
if (!mtd->writesize)
234+
host->addr_cs_field = GENMASK(17, 16);
235+
236+
regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, host->addr_cs_field,
237+
host->data->nand_cs << __ffs(host->addr_cs_field));
238+
}
239+
218240
static void ls1b_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op)
219241
{
220242
struct nand_chip *chip = &host->chip;
@@ -263,6 +285,8 @@ static void ls1c_nand_set_addr(struct loongson_nand_host *host, struct loongson_
263285
regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val);
264286
}
265287
}
288+
289+
loongson_nand_set_addr_cs(host);
266290
}
267291

268292
static void loongson_nand_trigger_op(struct loongson_nand_host *host, struct loongson_nand_op *op)
@@ -603,42 +627,82 @@ static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_opera
603627
return nand_op_parser_exec_op(chip, &loongson_nand_op_parser, op, check_only);
604628
}
605629

606-
static int loongson_nand_attach_chip(struct nand_chip *chip)
630+
static int loongson_nand_get_chip_capacity(struct nand_chip *chip)
607631
{
608632
struct loongson_nand_host *host = nand_get_controller_data(chip);
609633
u64 chipsize = nanddev_target_size(&chip->base);
610-
int cell_size = 0;
634+
struct mtd_info *mtd = nand_to_mtd(chip);
611635

612-
switch (chipsize) {
613-
case SZ_128M:
614-
cell_size = 0x0;
615-
break;
616-
case SZ_256M:
617-
cell_size = 0x1;
618-
break;
619-
case SZ_512M:
620-
cell_size = 0x2;
621-
break;
622-
case SZ_1G:
623-
cell_size = 0x3;
624-
break;
625-
case SZ_2G:
626-
cell_size = 0x4;
636+
switch (mtd->writesize) {
637+
case SZ_512:
638+
switch (chipsize) {
639+
case SZ_8M:
640+
host->addr_cs_field = GENMASK(15, 14);
641+
return 0x9;
642+
case SZ_16M:
643+
host->addr_cs_field = GENMASK(16, 15);
644+
return 0xa;
645+
case SZ_32M:
646+
host->addr_cs_field = GENMASK(17, 16);
647+
return 0xb;
648+
case SZ_64M:
649+
host->addr_cs_field = GENMASK(18, 17);
650+
return 0xc;
651+
case SZ_128M:
652+
host->addr_cs_field = GENMASK(19, 18);
653+
return 0xd;
654+
}
627655
break;
628-
case SZ_4G:
629-
cell_size = 0x5;
656+
case SZ_2K:
657+
switch (chipsize) {
658+
case SZ_128M:
659+
host->addr_cs_field = GENMASK(17, 16);
660+
return 0x0;
661+
case SZ_256M:
662+
host->addr_cs_field = GENMASK(18, 17);
663+
return 0x1;
664+
case SZ_512M:
665+
host->addr_cs_field = GENMASK(19, 18);
666+
return 0x2;
667+
case SZ_1G:
668+
host->addr_cs_field = GENMASK(20, 19);
669+
return 0x3;
670+
}
630671
break;
631-
case SZ_8G:
632-
cell_size = 0x6;
672+
case SZ_4K:
673+
if (chipsize == SZ_2G) {
674+
host->addr_cs_field = GENMASK(20, 19);
675+
return 0x4;
676+
}
633677
break;
634-
case SZ_16G:
635-
cell_size = 0x7;
678+
case SZ_8K:
679+
switch (chipsize) {
680+
case SZ_4G:
681+
host->addr_cs_field = GENMASK(20, 19);
682+
return 0x5;
683+
case SZ_8G:
684+
host->addr_cs_field = GENMASK(21, 20);
685+
return 0x6;
686+
case SZ_16G:
687+
host->addr_cs_field = GENMASK(22, 21);
688+
return 0x7;
689+
}
636690
break;
637-
default:
638-
dev_err(host->dev, "unsupported chip size: %llu MB\n", chipsize);
639-
return -EINVAL;
640691
}
641692

693+
dev_err(host->dev, "Unsupported chip size: %llu MB with page size %u B\n",
694+
chipsize, mtd->writesize);
695+
return -EINVAL;
696+
}
697+
698+
static int loongson_nand_attach_chip(struct nand_chip *chip)
699+
{
700+
struct loongson_nand_host *host = nand_get_controller_data(chip);
701+
int cell_size = loongson_nand_get_chip_capacity(chip);
702+
703+
if (cell_size < 0)
704+
return cell_size;
705+
642706
switch (chip->ecc.engine_type) {
643707
case NAND_ECC_ENGINE_TYPE_NONE:
644708
break;

0 commit comments

Comments
 (0)