Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Binbin Zhou and committed by
Miquel Raynal
7ad5bdf8 fb1dd6b6

+90 -26
+90 -26
drivers/mtd/nand/raw/loongson-nand-controller.c
··· 82 82 unsigned int op_scope_field; 83 83 unsigned int hold_cycle; 84 84 unsigned int wait_cycle; 85 + unsigned int nand_cs; 85 86 void (*set_addr)(struct loongson_nand_host *host, struct loongson_nand_op *op); 86 87 }; 87 88 ··· 91 90 struct nand_chip chip; 92 91 struct nand_controller controller; 93 92 const struct loongson_nand_data *data; 93 + unsigned int addr_cs_field; 94 94 void __iomem *reg_base; 95 95 struct regmap *regmap; 96 96 /* DMA Engine stuff */ ··· 217 215 return 0; 218 216 } 219 217 218 + static void loongson_nand_set_addr_cs(struct loongson_nand_host *host) 219 + { 220 + struct nand_chip *chip = &host->chip; 221 + struct mtd_info *mtd = nand_to_mtd(chip); 222 + 223 + if (!host->data->nand_cs) 224 + return; 225 + 226 + /* 227 + * The Manufacturer/Chip ID read operation precedes attach_chip, at which point 228 + * information such as NAND chip selection and capacity is unknown. As a 229 + * workaround, we use 128MB cellsize (2KB pagesize) as a fallback. 230 + */ 231 + if (!mtd->writesize) 232 + host->addr_cs_field = GENMASK(17, 16); 233 + 234 + regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, host->addr_cs_field, 235 + host->data->nand_cs << __ffs(host->addr_cs_field)); 236 + } 237 + 220 238 static void ls1b_nand_set_addr(struct loongson_nand_host *host, struct loongson_nand_op *op) 221 239 { 222 240 struct nand_chip *chip = &host->chip; ··· 285 263 regmap_update_bits(host->regmap, LOONGSON_NAND_ADDR2, mask, val); 286 264 } 287 265 } 266 + 267 + loongson_nand_set_addr_cs(host); 288 268 } 289 269 290 270 static void loongson_nand_trigger_op(struct loongson_nand_host *host, struct loongson_nand_op *op) ··· 627 603 return nand_op_parser_exec_op(chip, &loongson_nand_op_parser, op, check_only); 628 604 } 629 605 630 - static int loongson_nand_attach_chip(struct nand_chip *chip) 606 + static int loongson_nand_get_chip_capacity(struct nand_chip *chip) 631 607 { 632 608 struct loongson_nand_host *host = nand_get_controller_data(chip); 633 609 u64 chipsize = nanddev_target_size(&chip->base); 634 - int cell_size = 0; 610 + struct mtd_info *mtd = nand_to_mtd(chip); 635 611 636 - switch (chipsize) { 637 - case SZ_128M: 638 - cell_size = 0x0; 612 + switch (mtd->writesize) { 613 + case SZ_512: 614 + switch (chipsize) { 615 + case SZ_8M: 616 + host->addr_cs_field = GENMASK(15, 14); 617 + return 0x9; 618 + case SZ_16M: 619 + host->addr_cs_field = GENMASK(16, 15); 620 + return 0xa; 621 + case SZ_32M: 622 + host->addr_cs_field = GENMASK(17, 16); 623 + return 0xb; 624 + case SZ_64M: 625 + host->addr_cs_field = GENMASK(18, 17); 626 + return 0xc; 627 + case SZ_128M: 628 + host->addr_cs_field = GENMASK(19, 18); 629 + return 0xd; 630 + } 639 631 break; 640 - case SZ_256M: 641 - cell_size = 0x1; 632 + case SZ_2K: 633 + switch (chipsize) { 634 + case SZ_128M: 635 + host->addr_cs_field = GENMASK(17, 16); 636 + return 0x0; 637 + case SZ_256M: 638 + host->addr_cs_field = GENMASK(18, 17); 639 + return 0x1; 640 + case SZ_512M: 641 + host->addr_cs_field = GENMASK(19, 18); 642 + return 0x2; 643 + case SZ_1G: 644 + host->addr_cs_field = GENMASK(20, 19); 645 + return 0x3; 646 + } 642 647 break; 643 - case SZ_512M: 644 - cell_size = 0x2; 648 + case SZ_4K: 649 + if (chipsize == SZ_2G) { 650 + host->addr_cs_field = GENMASK(20, 19); 651 + return 0x4; 652 + } 645 653 break; 646 - case SZ_1G: 647 - cell_size = 0x3; 654 + case SZ_8K: 655 + switch (chipsize) { 656 + case SZ_4G: 657 + host->addr_cs_field = GENMASK(20, 19); 658 + return 0x5; 659 + case SZ_8G: 660 + host->addr_cs_field = GENMASK(21, 20); 661 + return 0x6; 662 + case SZ_16G: 663 + host->addr_cs_field = GENMASK(22, 21); 664 + return 0x7; 665 + } 648 666 break; 649 - case SZ_2G: 650 - cell_size = 0x4; 651 - break; 652 - case SZ_4G: 653 - cell_size = 0x5; 654 - break; 655 - case SZ_8G: 656 - cell_size = 0x6; 657 - break; 658 - case SZ_16G: 659 - cell_size = 0x7; 660 - break; 661 - default: 662 - dev_err(host->dev, "unsupported chip size: %llu MB\n", chipsize); 663 - return -EINVAL; 664 667 } 668 + 669 + dev_err(host->dev, "Unsupported chip size: %llu MB with page size %u B\n", 670 + chipsize, mtd->writesize); 671 + return -EINVAL; 672 + } 673 + 674 + static int loongson_nand_attach_chip(struct nand_chip *chip) 675 + { 676 + struct loongson_nand_host *host = nand_get_controller_data(chip); 677 + int cell_size = loongson_nand_get_chip_capacity(chip); 678 + 679 + if (cell_size < 0) 680 + return cell_size; 665 681 666 682 switch (chip->ecc.engine_type) { 667 683 case NAND_ECC_ENGINE_TYPE_NONE: