diff options
| -rw-r--r-- | drivers/mtd/nand/raw/loongson-nand-controller.c | 116 |
1 files changed, 90 insertions, 26 deletions
diff --git a/drivers/mtd/nand/raw/loongson-nand-controller.c b/drivers/mtd/nand/raw/loongson-nand-controller.c index 97cd566420a8..1427dd6943a7 100644 --- a/drivers/mtd/nand/raw/loongson-nand-controller.c +++ b/drivers/mtd/nand/raw/loongson-nand-controller.c @@ -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 struct return 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,82 @@ static int loongson_nand_exec_op(struct nand_chip *chip, const struct nand_opera return 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; + switch (mtd->writesize) { + case 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; + } break; - case SZ_4G: - cell_size = 0x5; + case SZ_2K: + switch (chipsize) { + case SZ_128M: + host->addr_cs_field = GENMASK(17, 16); + return 0x0; + 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; + } break; - case SZ_8G: - cell_size = 0x6; + case SZ_4K: + if (chipsize == SZ_2G) { + host->addr_cs_field = GENMASK(20, 19); + return 0x4; + } break; - case SZ_16G: - cell_size = 0x7; + case 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; + } break; - default: - dev_err(host->dev, "unsupported chip size: %llu MB\n", chipsize); - return -EINVAL; } + 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 = 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; |
