From 5828c60826e9422169b3711aa58a583242864cc8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 31 Jul 2014 18:36:20 +0300 Subject: mtd: ndfc: silence an array underflow static checker warning We check "cs" for array overflows but we don't check for underflows and it upsets the static checkers. Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 69eaba6..253a644 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -203,7 +203,8 @@ static int ndfc_probe(struct platform_device *ofdev) struct ndfc_controller *ndfc; const __be32 *reg; u32 ccr; - int err, len, cs; + u32 cs; + int err, len; /* Read the reg property to get the chip select */ reg = of_get_property(ofdev->dev.of_node, "reg", &len); -- cgit v0.10.2 From 9b6e5172e363b0c35a6be4d3197f3bcdc789292e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 31 Jul 2014 16:31:16 +0200 Subject: mtd: use NULL instead of 0 for an address Use NULL instead of 0 when returning an address. This fixes a sparse warning. Signed-off-by: Martin Kepplinger Signed-off-by: Brian Norris diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index a3cfad3..af747af 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -89,7 +89,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) if (!pcmcia_dev_present(dev->p_dev)) { pr_debug("device removed\n"); - return 0; + return NULL; } offset = to & ~(dev->win_size-1); -- cgit v0.10.2 From 796fe3648a13b311f5b9a125e2d2532a2ce7c78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Poggi?= Date: Tue, 29 Jul 2014 15:27:27 +0200 Subject: mtd: atmel_nand: increase chip_delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some nand with 8k page size like Micron MT29F32G08ABAAAWP need more than 20us. Signed-off-by: Raphaël Poggi Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e321c56..77bd877 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -2099,7 +2099,7 @@ static int atmel_nand_probe(struct platform_device *pdev) } nand_chip->ecc.mode = host->board.ecc_mode; - nand_chip->chip_delay = 20; /* 20us command delay time */ + nand_chip->chip_delay = 40; /* 40us command delay time */ if (host->board.bus_width_16) /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; -- cgit v0.10.2 From a35571058ec8e7c82dceea90cdecead51674f963 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Tue, 22 Jul 2014 17:24:18 +0800 Subject: mtd: atmel_nand: add pmecc support for 512, 1k, 4k, 8k page size PMECC can support 512, 1k, 2k, 4k, 8k page size. The driver currently only support 2k page size nand flash. So this patch add support to 512, 1k, 4k and 8k page size nand flash. Signed-off-by: Josh Wu Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 77bd877..e4d57ff 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1174,7 +1174,17 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, /* set ECC page size and oob layout */ switch (mtd->writesize) { + case 512: + case 1024: case 2048: + case 4096: + case 8192: + if (sector_size > mtd->writesize) { + dev_err(host->dev, "pmecc sector size is bigger than the page size!\n"); + err_no = -EINVAL; + goto err; + } + host->pmecc_degree = (sector_size == 512) ? PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; @@ -1201,13 +1211,9 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, nand_chip->ecc.layout = &atmel_pmecc_oobinfo; break; - case 512: - case 1024: - case 4096: - /* TODO */ + default: dev_warn(host->dev, "Unsupported page size for PMECC, use Software ECC\n"); - default: /* page size not handled by HW ECC */ /* switching back to soft ECC */ nand_chip->ecc.mode = NAND_ECC_SOFT; -- cgit v0.10.2 From 7b7d8982f0169d5ac67c6c2877449fb7f6968cac Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 27 Jul 2014 14:31:53 -0700 Subject: mtd: fix linux/mtd/nand.h kernel-doc warning Fix kernel-doc warning in : Warning(..//include/linux/mtd/nand.h:795): No description found for parameter 'ecc' Signed-off-by: Randy Dunlap Cc: David Woodhouse Cc: Brian Norris Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 3083c53..b7c1199 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -766,6 +766,7 @@ struct nand_chip { * @options: stores various chip bit options * @id_len: The valid length of the @id. * @oobsize: OOB size + * @ecc: ECC correctability and step information from the datasheet. * @ecc.strength_ds: The ECC correctability from the datasheet, same as the * @ecc_strength_ds in nand_chip{}. * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the -- cgit v0.10.2 From f2fabe16b819cdead86fb38c8ab88a0d9c308293 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 27 Jul 2014 23:56:08 +0200 Subject: mtd: spi-nor: add support for Micron M25PX80 This commit adds the support in the spi-nor driver of the Micron M25PX80 flash, a 8 Mbit SPI flash from Micron. Signed-off-by: Thomas Petazzoni Signed-off-by: Brian Norris diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b5ad6be..4dc0c86 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -611,6 +611,7 @@ const struct spi_device_id spi_nor_ids[] = { { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, + { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, -- cgit v0.10.2 From 8fb7b9309c41407801958138db978eb38fd80c01 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 28 Jul 2014 21:19:55 +0800 Subject: mtd: atmel_nand: remove redundant dev_err call There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e4d57ff..0abc965 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1148,7 +1148,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, host->ecc = devm_ioremap_resource(&pdev->dev, regs); if (IS_ERR(host->ecc)) { - dev_err(host->dev, "ioremap failed\n"); err_no = PTR_ERR(host->ecc); goto err; } @@ -1156,8 +1155,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2); host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr); if (IS_ERR(host->pmerrloc_base)) { - dev_err(host->dev, - "Can not get I/O resource for PMECC ERRLOC controller!\n"); err_no = PTR_ERR(host->pmerrloc_base); goto err; } @@ -1165,7 +1162,6 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); if (IS_ERR(host->pmecc_rom_base)) { - dev_err(host->dev, "Can not get I/O resource for ROM!\n"); err_no = PTR_ERR(host->pmecc_rom_base); goto err; } @@ -1536,10 +1532,8 @@ static int atmel_hw_nand_init_params(struct platform_device *pdev, } host->ecc = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(host->ecc)) { - dev_err(host->dev, "ioremap failed\n"); + if (IS_ERR(host->ecc)) return PTR_ERR(host->ecc); - } /* ECC is calculated for the whole page (1 step) */ nand_chip->ecc.size = mtd->writesize; @@ -2046,7 +2040,6 @@ static int atmel_nand_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->io_base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(host->io_base)) { - dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n"); res = PTR_ERR(host->io_base); goto err_nand_ioremap; } -- cgit v0.10.2 From 2902330e7ac16d5962f114d92bb17631e9cb49e9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 11 Jul 2014 11:14:05 +0900 Subject: mtd: denali: avoid using a magic number MAP10 command with '0x2000' data sets up a read-ahead/write access. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0b071a3..da0fcc2 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -74,6 +74,7 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 +#define PIPELINE_ACCESS 0x2000 #define DENALI_READ 0 #define DENALI_WRITE 0x100 @@ -765,7 +766,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, iowrite32(cmd, denali->flash_mem); } else { index_addr(denali, (uint32_t)cmd, - 0x2000 | op | page_count); + PIPELINE_ACCESS | op | page_count); /* wait for command to be accepted * can always use status0 bit as the -- cgit v0.10.2 From 6f3c0f163103fb225c77b73ca17fc4ecea308103 Mon Sep 17 00:00:00 2001 From: Samarth Parikh Date: Wed, 16 Jul 2014 16:14:37 +0530 Subject: mtd: Fixed checkpatch seq_printf warnings Fixed checkpatch warnings: "WARNING: Prefer seq_puts to seq_printf" This patch is created with reference to the ongoing lkml thread https://lkml.org/lkml/2014/7/15/646 where Andrew Morton wrote: " - puts is presumably faster - puts doesn't go rogue if you accidentally pass it a "%". - this patch would actually make compiled object files few bytes smaller. Perhaps because seq_printf() is a varargs function, forcing the caller to pass args on the stack instead of in registers. " Signed-off-by: Samarth Parikh Signed-off-by: Brian Norris diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 91a169c..21cc4b6 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1697,16 +1697,16 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) switch (mode) { case DOC_ASICMODE_RESET: - pos += seq_printf(s, "reset"); + pos += seq_puts(s, "reset"); break; case DOC_ASICMODE_NORMAL: - pos += seq_printf(s, "normal"); + pos += seq_puts(s, "normal"); break; case DOC_ASICMODE_POWERDOWN: - pos += seq_printf(s, "powerdown"); + pos += seq_puts(s, "powerdown"); break; } - pos += seq_printf(s, ")\n"); + pos += seq_puts(s, ")\n"); return pos; } DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); @@ -1745,22 +1745,22 @@ static int dbg_protection_show(struct seq_file *s, void *p) pos += seq_printf(s, "Protection = 0x%02x (", protect); if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) - pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); + pos += seq_puts(s, "FOUNDRY_OTP_LOCK,"); if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) - pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); + pos += seq_puts(s, "CUSTOMER_OTP_LOCK,"); if (protect & DOC_PROTECT_LOCK_INPUT) - pos += seq_printf(s, "LOCK_INPUT,"); + pos += seq_puts(s, "LOCK_INPUT,"); if (protect & DOC_PROTECT_STICKY_LOCK) - pos += seq_printf(s, "STICKY_LOCK,"); + pos += seq_puts(s, "STICKY_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ENABLED) - pos += seq_printf(s, "PROTECTION ON,"); + pos += seq_puts(s, "PROTECTION ON,"); if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) - pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); + pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,"); if (protect & DOC_PROTECT_PROTECTION_ERROR) - pos += seq_printf(s, "PROTECT_ERR,"); + pos += seq_puts(s, "PROTECT_ERR,"); else - pos += seq_printf(s, "NO_PROTECT_ERR"); - pos += seq_printf(s, ")\n"); + pos += seq_puts(s, "NO_PROTECT_ERR"); + pos += seq_puts(s, ")\n"); pos += seq_printf(s, "DPS0 = 0x%02x : " "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 8b33b26..0ec96cd 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1287,7 +1287,7 @@ static int mtdswap_show(struct seq_file *s, void *data) seq_printf(s, "total erasures: %lu\n", sum); - seq_printf(s, "\n"); + seq_puts(s, "\n"); seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count); seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count); @@ -1296,7 +1296,7 @@ static int mtdswap_show(struct seq_file *s, void *data) seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count); seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); - seq_printf(s, "\n"); + seq_puts(s, "\n"); seq_printf(s, "total pages: %u\n", pages); seq_printf(s, "pages mapped: %u\n", mapped); -- cgit v0.10.2 From 57d3a9a89a0645f3597561e214f8d6852a2c56b4 Mon Sep 17 00:00:00 2001 From: White Ding Date: Thu, 24 Jul 2014 00:10:45 +0800 Subject: mtd: nand: fix nand_lock/unlock() function Do nand reset before write protect check. If we want to check the WP# low or high through STATUS READ and check bit 7, we must reset the device, other operation (eg.erase/program a locked block) can also clear the bit 7 of status register. As we know the status register can be refreshed, if we do some operation to trigger it, for example if we do erase/program operation to one block that is locked, then READ STATUS, the bit 7 of READ STATUS will be 0 indicate the device in write protect, then if we do erase/program operation to another block that is unlocked, the bit 7 of READ STATUS will be 1 indicate the device is not write protect. Suppose we checked the bit 7 of READ STATUS is 0 then judge the WP# is low (write protect), but in this case the WP# maybe high if we do erase/program operation to a locked block, so we must reset the device if we want to check the WP# low or high through STATUS READ and check bit 7. Signed-off-by: White Ding Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d8cdf06..1a27c2d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -982,6 +982,15 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) chip->select_chip(mtd, chipnr); + /* + * Reset the chip. + * If we want to check the WP through READ STATUS and check the bit 7 + * we must reset the chip + * some operation can also clear the bit 7 of status register + * eg. erase/program a locked block + */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* Check, if it is write protected */ if (nand_check_wp(mtd)) { pr_debug("%s: device is write protected!\n", @@ -1032,6 +1041,15 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) chip->select_chip(mtd, chipnr); + /* + * Reset the chip. + * If we want to check the WP through READ STATUS and check the bit 7 + * we must reset the chip + * some operation can also clear the bit 7 of status register + * eg. erase/program a locked block + */ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* Check, if it is write protected */ if (nand_check_wp(mtd)) { pr_debug("%s: device is write protected!\n", -- cgit v0.10.2 From 36c6a7ac74044b8025488c018279115bb3c32eb0 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:19 -0700 Subject: mtd: cfi_cmdset_0002: allow retry/timeout loop to exit The variable 'retries' is never modified, so if the reset operation never is going to complete, we'll get stuck in an infinite loop. It looks like the intention was to decrement 'retries' on every loop. Untested. Caught by Coverity. Signed-off-by: Brian Norris diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 5a4bfe3..6da141a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -2029,6 +2029,8 @@ static int cfi_amdstd_panic_wait(struct map_info *map, struct flchip *chip, udelay(1); } + + retries--; } /* the chip never became ready */ -- cgit v0.10.2 From 0c2b4e21444d0e274e91fc7db85caddb30988853 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:27 -0700 Subject: mtd: correct upper bounds check for mtd_*() APIs When checking the upper boundary (i.e., whether an address is higher than the maximum size of the MTD), we should be doing an inclusive check (greater or equal). For instance, an address of 16MB (0x1000000) on a 16MB device is invalid. The strengthening of this bounds check is redundant for those which already have a address+length check and ensure that the length is non-zero, but let's just fix them all, for completeness. Signed-off-by: Brian Norris diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index e4831b4..c101517 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -778,7 +778,7 @@ EXPORT_SYMBOL_GPL(__put_mtd_device); */ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { - if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) + if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -804,7 +804,7 @@ int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, *phys = 0; if (!mtd->_point) return -EOPNOTSUPP; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -817,7 +817,7 @@ int mtd_unpoint(struct mtd_info *mtd, loff_t from, size_t len) { if (!mtd->_point) return -EOPNOTSUPP; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -835,7 +835,7 @@ unsigned long mtd_get_unmapped_area(struct mtd_info *mtd, unsigned long len, { if (!mtd->_get_unmapped_area) return -EOPNOTSUPP; - if (offset > mtd->size || len > mtd->size - offset) + if (offset >= mtd->size || len > mtd->size - offset) return -EINVAL; return mtd->_get_unmapped_area(mtd, len, offset, flags); } @@ -846,7 +846,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, { int ret_code; *retlen = 0; - if (from < 0 || from > mtd->size || len > mtd->size - from) + if (from < 0 || from >= mtd->size || len > mtd->size - from) return -EINVAL; if (!len) return 0; @@ -869,7 +869,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { *retlen = 0; - if (to < 0 || to > mtd->size || len > mtd->size - to) + if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -892,7 +892,7 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, *retlen = 0; if (!mtd->_panic_write) return -EOPNOTSUPP; - if (to < 0 || to > mtd->size || len > mtd->size - to) + if (to < 0 || to >= mtd->size || len > mtd->size - to) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; @@ -1011,7 +1011,7 @@ int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_lock) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1023,7 +1023,7 @@ int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_unlock) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1035,7 +1035,7 @@ int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) { if (!mtd->_is_locked) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + if (ofs < 0 || ofs >= mtd->size || len > mtd->size - ofs) return -EINVAL; if (!len) return 0; @@ -1045,7 +1045,7 @@ EXPORT_SYMBOL_GPL(mtd_is_locked); int mtd_block_isreserved(struct mtd_info *mtd, loff_t ofs) { - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!mtd->_block_isreserved) return 0; @@ -1055,7 +1055,7 @@ EXPORT_SYMBOL_GPL(mtd_block_isreserved); int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) { - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!mtd->_block_isbad) return 0; @@ -1067,7 +1067,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) { if (!mtd->_block_markbad) return -EOPNOTSUPP; - if (ofs < 0 || ofs > mtd->size) + if (ofs < 0 || ofs >= mtd->size) return -EINVAL; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; -- cgit v0.10.2 From f7f0d358f5f2f1133b5a14337028ddab848cd74e Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:39 -0700 Subject: mtd: sm_ftl: initialize error code There is one theoretical case that could fall through to using an uninitialized value as the return code. Let's give it a value of 0. Untested. Caught by Coverity. Signed-off-by: Brian Norris diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index cf49c22..c23184a 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -1058,7 +1058,7 @@ static int sm_write(struct mtd_blktrans_dev *dev, { struct sm_ftl *ftl = dev->priv; struct ftl_zone *zone; - int error, zone_num, block, boffset; + int error = 0, zone_num, block, boffset; BUG_ON(ftl->readonly); sm_break_offset(ftl, sec_no << 9, &zone_num, &block, &boffset); -- cgit v0.10.2 From 5e47212831ac565993d21ebd36216d98f2b58f30 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:06:47 -0700 Subject: mtd: remove dead non-char logic MTD used to allow compiling out character device support. This was dropped in the following commit, but some of the accompanying logic was never dropped: commit 660685d9d1b4730f0b5ca97fa95f272f99c63bce Author: Artem Bityutskiy Date: Thu Mar 14 13:27:40 2013 +0200 mtd: merge mtdchar module with mtdcore The weird logic was flagged by Coverity. Signed-off-by: Brian Norris Cc: Artem Bityutskiy diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c101517..4c61187 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -105,12 +105,11 @@ static LIST_HEAD(mtd_notifiers); */ static void mtd_release(struct device *dev) { - struct mtd_info __maybe_unused *mtd = dev_get_drvdata(dev); + struct mtd_info *mtd = dev_get_drvdata(dev); dev_t index = MTD_DEVT(mtd->index); - /* remove /dev/mtdXro node if needed */ - if (index) - device_destroy(&mtd_class, index + 1); + /* remove /dev/mtdXro node */ + device_destroy(&mtd_class, index + 1); } static int mtd_cls_suspend(struct device *dev, pm_message_t state) @@ -442,10 +441,8 @@ int add_mtd_device(struct mtd_info *mtd) if (device_register(&mtd->dev) != 0) goto fail_added; - if (MTD_DEVT(i)) - device_create(&mtd_class, mtd->dev.parent, - MTD_DEVT(i) + 1, - NULL, "mtd%dro", i); + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, + "mtd%dro", i); pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing -- cgit v0.10.2 From 8c3f3f1d7941bcb25590b784f84accd7dcb44ba3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:02 -0700 Subject: mtd: mtdswap: fix integer overflow Caught by Coverity. Signed-off-by: Brian Norris diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 0ec96cd..48cf6f9 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1474,7 +1474,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) } eblocks = mtd_div_by_eb(use_size, mtd); - use_size = eblocks * mtd->erasesize; + use_size = (uint64_t)eblocks * mtd->erasesize; bad_blocks = mtdswap_badblocks(mtd, use_size); eavailable = eblocks - bad_blocks; -- cgit v0.10.2 From 1001ff7a4f64f3f4264e69d3ed70ff428f627e01 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:12 -0700 Subject: mtd: tests: fix integer overflow issues These multiplications are done with 32-bit arithmetic, then converted to 64-bit. We should widen the integers first to prevent overflow. This could be a problem for large (>4GB) MTD's. Detected by Coverity. Signed-off-by: Brian Norris Cc: Akinobu Mita diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c index 111ee46..34736bb 100644 --- a/drivers/mtd/tests/mtd_test.c +++ b/drivers/mtd/tests/mtd_test.c @@ -10,7 +10,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) { int err; struct erase_info ei; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; @@ -33,7 +33,7 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum) static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum) { int ret; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; ret = mtd_block_isbad(mtd, addr); if (ret) diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index 6f97615..273f7e5 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -364,7 +364,7 @@ static int __init mtd_nandbiterrs_init(void) pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize); - offset = page_offset * mtd->writesize; + offset = (loff_t)page_offset * mtd->writesize; eraseblock = mtd_div_by_eb(offset, mtd); pr_info("Using page=%u, offset=%llu, eraseblock=%u\n", diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index f19ab1a..dc4f960 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -120,7 +120,7 @@ static int verify_eraseblock(int ebnum) int i; struct mtd_oob_ops ops; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { @@ -214,7 +214,7 @@ static int verify_eraseblock_in_one_go(int ebnum) { struct mtd_oob_ops ops; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->ecclayout->oobavail * pgcnt; prandom_bytes_state(&rnd_state, writebuf, len); @@ -568,7 +568,7 @@ static int __init mtd_oobtest_init(void) size_t sz = mtd->ecclayout->oobavail; if (bbt[i] || bbt[i + 1]) continue; - addr = (i + 1) * mtd->erasesize - mtd->writesize; + addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; prandom_bytes_state(&rnd_state, writebuf, sz * cnt); for (pg = 0; pg < cnt; ++pg) { ops.mode = MTD_OPS_AUTO_OOB; @@ -598,7 +598,7 @@ static int __init mtd_oobtest_init(void) continue; prandom_bytes_state(&rnd_state, writebuf, mtd->ecclayout->oobavail * 2); - addr = (i + 1) * mtd->erasesize - mtd->writesize; + addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index ed2d3f6..88296e8 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -52,7 +52,7 @@ static struct rnd_state rnd_state; static int write_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize); cond_resched(); @@ -64,7 +64,7 @@ static int verify_eraseblock(int ebnum) uint32_t j; int err = 0, i; loff_t addr0, addrn; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; addr0 = 0; for (i = 0; i < ebcnt && bbt[i]; ++i) diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c index 626e66d..a54cf15 100644 --- a/drivers/mtd/tests/readtest.c +++ b/drivers/mtd/tests/readtest.c @@ -47,7 +47,7 @@ static int pgcnt; static int read_eraseblock_by_page(int ebnum) { int i, ret, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; void *oobbuf = iobuf1; diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index 87ff6a2..5ee9f70 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -55,7 +55,7 @@ static int multiblock_erase(int ebnum, int blocks) { int err; struct erase_info ei; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(&ei, 0, sizeof(struct erase_info)); ei.mtd = mtd; @@ -80,7 +80,7 @@ static int multiblock_erase(int ebnum, int blocks) static int write_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; return mtdtest_write(mtd, addr, mtd->erasesize, iobuf); } @@ -88,7 +88,7 @@ static int write_eraseblock(int ebnum) static int write_eraseblock_by_page(int ebnum) { int i, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < pgcnt; i++) { @@ -106,7 +106,7 @@ static int write_eraseblock_by_2pages(int ebnum) { size_t sz = pgsize * 2; int i, n = pgcnt / 2, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < n; i++) { @@ -124,7 +124,7 @@ static int write_eraseblock_by_2pages(int ebnum) static int read_eraseblock(int ebnum) { - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; return mtdtest_read(mtd, addr, mtd->erasesize, iobuf); } @@ -132,7 +132,7 @@ static int read_eraseblock(int ebnum) static int read_eraseblock_by_page(int ebnum) { int i, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < pgcnt; i++) { @@ -150,7 +150,7 @@ static int read_eraseblock_by_2pages(int ebnum) { size_t sz = pgsize * 2; int i, n = pgcnt / 2, err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; void *buf = iobuf; for (i = 0; i < n; i++) { diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index a876371..7b59ef5 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -57,7 +57,7 @@ static int write_eraseblock(int ebnum) { size_t written; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); err = mtd_write(mtd, addr, subpgsize, &written, writebuf); @@ -92,7 +92,7 @@ static int write_eraseblock2(int ebnum) { size_t written; int err = 0, k; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) @@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum) { size_t read; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, subpgsize); clear_data(readbuf, subpgsize); @@ -192,7 +192,7 @@ static int verify_eraseblock2(int ebnum) { size_t read; int err = 0, k; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) @@ -227,7 +227,7 @@ static int verify_eraseblock_ff(int ebnum) uint32_t j; size_t read; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; memset(writebuf, 0xff, subpgsize); for (j = 0; j < mtd->erasesize / subpgsize; ++j) { -- cgit v0.10.2 From 31f754628cbb12c983600f22d9f0fed50dfe2134 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:22 -0700 Subject: mtd: use __packed shorthand Signed-off-by: Brian Norris diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 48cf6f9..fc8b3d1 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -145,7 +145,7 @@ struct mtdswap_dev { struct mtdswap_oobdata { __le16 magic; __le32 count; -} __attribute__((packed)); +} __packed; #define MTDSWAP_MAGIC_CLEAN 0x2095 #define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1) diff --git a/drivers/mtd/nand/sm_common.h b/drivers/mtd/nand/sm_common.h index 00f4a83..d3e028e 100644 --- a/drivers/mtd/nand/sm_common.h +++ b/drivers/mtd/nand/sm_common.h @@ -18,7 +18,7 @@ struct sm_oob { uint8_t ecc2[3]; uint8_t lba_copy2[2]; uint8_t ecc1[3]; -} __attribute__((packed)); +} __packed; /* one sector is always 512 bytes, but it can consist of two nand pages */ diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 37ef6b1..299d7d3 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -153,7 +153,7 @@ struct cfi_ident { uint16_t MaxBufWriteSize; uint8_t NumEraseRegions; uint32_t EraseRegionInfo[0]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; /* Extended Query Structure for both PRI and ALT */ @@ -161,7 +161,7 @@ struct cfi_extquery { uint8_t pri[3]; uint8_t MajorVersion; uint8_t MinorVersion; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */ @@ -180,7 +180,7 @@ struct cfi_pri_intelext { uint8_t FactProtRegSize; uint8_t UserProtRegSize; uint8_t extra[0]; -} __attribute__((packed)); +} __packed; struct cfi_intelext_otpinfo { uint32_t ProtRegAddr; @@ -188,7 +188,7 @@ struct cfi_intelext_otpinfo { uint8_t FactProtRegSize; uint16_t UserGroups; uint8_t UserProtRegSize; -} __attribute__((packed)); +} __packed; struct cfi_intelext_blockinfo { uint16_t NumIdentBlocks; @@ -196,7 +196,7 @@ struct cfi_intelext_blockinfo { uint16_t MinBlockEraseCycles; uint8_t BitsPerCell; uint8_t BlockCap; -} __attribute__((packed)); +} __packed; struct cfi_intelext_regioninfo { uint16_t NumIdentPartitions; @@ -205,7 +205,7 @@ struct cfi_intelext_regioninfo { uint8_t NumOpAllowedSimEraMode; uint8_t NumBlockTypes; struct cfi_intelext_blockinfo BlockTypes[1]; -} __attribute__((packed)); +} __packed; struct cfi_intelext_programming_regioninfo { uint8_t ProgRegShift; @@ -214,7 +214,7 @@ struct cfi_intelext_programming_regioninfo { uint8_t Reserved2; uint8_t ControlInvalid; uint8_t Reserved3; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ @@ -233,7 +233,7 @@ struct cfi_pri_amdstd { uint8_t VppMin; uint8_t VppMax; uint8_t TopBottom; -} __attribute__((packed)); +} __packed; /* Vendor-Specific PRI for Atmel chips (command set 0x0002) */ @@ -245,18 +245,18 @@ struct cfi_pri_atmel { uint8_t BottomBoot; uint8_t BurstMode; uint8_t PageMode; -} __attribute__((packed)); +} __packed; struct cfi_pri_query { uint8_t NumFields; uint32_t ProtField[1]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; struct cfi_bri_query { uint8_t PageModeReadCap; uint8_t NumFields; uint32_t ConfField[1]; /* Not host ordered */ -} __attribute__((packed)); +} __packed; #define P_ID_NONE 0x0000 #define P_ID_INTEL_EXT 0x0001 -- cgit v0.10.2 From c115add9d073752d38f6517882dfeafe76fc4458 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:31 -0700 Subject: mtd: nand: denali: set proper error code on timeout The condition "if (irq_status == 0)" already ensures that one half of the ternary ?: is dead. I think this should probably actually be a FAIL, not a PASS. Caught by Coverity. Signed-off-by: Brian Norris Cc: Jamie Iles diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index da0fcc2..4885a0f 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1062,9 +1062,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dev_err(denali->dev, "timeout on write_page (type = %d)\n", raw_xfer); - denali->status = - (irq_status & INTR_STATUS__PROGRAM_FAIL) ? - NAND_STATUS_FAIL : PASS; + denali->status = NAND_STATUS_FAIL; } denali_enable_dma(denali, false); -- cgit v0.10.2 From b033e1aac9afd314add799b6cd2a5489f892757f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:44 -0700 Subject: mtd: nandsim: fix integer widening This multiplication should be done in 64-bit, not 32-bit. Caught by Coverity. Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 4f0d836..7dc1dd2 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -827,7 +827,7 @@ static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) NS_ERR("invalid badblocks.\n"); return -EINVAL; } - offset = erase_block_no * ns->geom.secsz; + offset = (loff_t)erase_block_no * ns->geom.secsz; if (mtd_block_markbad(mtd, offset)) { NS_ERR("invalid badblocks.\n"); return -EINVAL; -- cgit v0.10.2 From 7a6f43958a53020f85818ff5c895623e88781fd6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:07:56 -0700 Subject: mtd: maps: solutionengine: drop excess dependency Already depends on SOLUTION_ENGINE, so we don't need the SUPERH dependency too. Signed-off-by: Brian Norris diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 21b2874..ba801d2 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -249,7 +249,7 @@ config MTD_CFI_FLAGADM config MTD_SOLUTIONENGINE tristate "CFI Flash device mapped on Hitachi SolutionEngine" - depends on SUPERH && SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS + depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS help This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -- cgit v0.10.2 From 537ab1bd47d6518e8a40207a80dd0c2c4bc43aed Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:08:03 -0700 Subject: mtd: nand: fix integer widening problems chip->pagebuf is a 32-bit type (int), so the shift will only be applied as 32-bit. Fix this for 64-bit safety. Caught by Coverity. Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1a27c2d..ae6e7c4 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2409,8 +2409,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; /* Invalidate the page cache, when we write to the cached page */ - if (to <= (chip->pagebuf << chip->page_shift) && - (chip->pagebuf << chip->page_shift) < (to + ops->len)) + if (to <= ((loff_t)chip->pagebuf << chip->page_shift) && + ((loff_t)chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; /* Don't allow multipage oob writes with offset */ -- cgit v0.10.2 From 1cc8d8413327a684cd5e93cd52ececb0223bb40b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 21 Jul 2014 19:08:13 -0700 Subject: mtd: terminate user-provided string Noticed by Coverity as a potential security issue. Signed-off-by: Brian Norris diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a0f54e8..5356395 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -549,6 +549,9 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd, if (mtd_is_partition(mtd)) return -EINVAL; + /* Sanitize user input */ + p.devname[BLKPG_DEVNAMELTH - 1] = '\0'; + return mtd_add_partition(mtd, p.devname, p.start, p.length); case BLKPG_DEL_PARTITION: -- cgit v0.10.2 From ff0a215438cf7be0a652cb3457f562539bd40b22 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Tue, 5 Aug 2014 18:38:52 +0800 Subject: mtd: atmel_nand: NFC: fix mtd_nandbiterrs.ko test fail when using sram write When enable NFC sram write, it will failed the mtd_nandbiterrs.ko test. As in driver's nfc_sram_write_page(), if ops->mode equal to MTD_OSP_RAW, driver assumes the data buffer contains one page data and one oob data followed. And driver will write the page data and oob data to nand. But this is wrong implementation. Since the data buffer don't contains the oob data to write. We should write the chip->oob_poi to nand's oob. So this patch fix it by writing the oob data from chip->oob_poi. Signed-off-by: Josh Wu Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 0abc965..9c5f717 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1907,15 +1907,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (offset || (data_len < mtd->writesize)) return -EINVAL; - cfg = nfc_readl(host->nfc->hsmc_regs, CFG); len = mtd->writesize; - - if (unlikely(raw)) { - len += mtd->oobsize; - nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE); - } else - nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE); - /* Copy page data to sram that will write to nand via NFC */ if (use_dma) { if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0) @@ -1925,6 +1917,15 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, memcpy32_toio(sram, buf, len); } + cfg = nfc_readl(host->nfc->hsmc_regs, CFG); + if (unlikely(raw) && oob_required) { + memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize); + len += mtd->oobsize; + nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE); + } else { + nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE); + } + if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) /* * When use NFC sram, need set up PMECC before send -- cgit v0.10.2 From bd8898db3e03147d9d7ddd48876fb3f3bcbab6c1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 9 Aug 2014 19:07:53 +0200 Subject: mtd: nand: Use ULL-suffix for big u64 constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mtd/nand/nand_timings.c:45: warning: integer constant is too large for ‘long’ type [ Editorial note: This is a false warning. Looking at ISO draft N1124 (this is approximately C11, the first PDF I had lying around), section 6.4.4.1 (statement 5): "The type of an integer constant is the first of the corresponding list in which its value can be represented." So this should not be an overflow, and any toolchain that says so (e.g., GCC 4.4) is buggy. -Brian ] Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index 8b36253..e81470a 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -42,7 +42,7 @@ static const struct nand_sdr_timings onfi_sdr_timings[] = { .tRHZ_max = 200000, .tRLOH_min = 0, .tRP_min = 50000, - .tRST_max = 250000000000, + .tRST_max = 250000000000ULL, .tWB_max = 200000, .tRR_min = 40000, .tWC_min = 100000, -- cgit v0.10.2 From 02f8a24e7b1c253ee37edc684200c11300de23f9 Mon Sep 17 00:00:00 2001 From: Aaron Wu Date: Thu, 7 Aug 2014 11:43:49 +0800 Subject: mtd: gpio_flash: handle case where offset + len exceeds the window size Fix the bug in handling gpio flash read/write when offset + len from MTD exceeds the window size Signed-off-by: Aaron Wu [Brian: made some commentary edits. Also note that the BUG_ON() was provably false for all non-negative inputs (since x % y <= x), so we dropped it.] Signed-off-by: Brian Norris diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index a4c477b..2fb3460 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -99,22 +99,28 @@ static map_word gf_read(struct map_info *map, unsigned long ofs) * @from: flash offset to copy from * @len: how much to copy * - * We rely on the MTD layer to chunk up copies such that a single request here - * will not cross a window size. This allows us to only wiggle the GPIOs once - * before falling back to a normal memcpy. Reading the higher layer code shows - * that this is indeed the case, but add a BUG_ON() to future proof. + * The "from" region may straddle more than one window, so toggle the GPIOs for + * each window region before reading its data. */ static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { struct async_state *state = gf_map_info_to_state(map); - gf_set_gpios(state, from); + int this_len; - /* BUG if operation crosses the win_size */ - BUG_ON(!((from + len) % state->win_size <= (from + len))); + while (len) { + if ((from % state->win_size) + len > state->win_size) + this_len = state->win_size - (from % state->win_size); + else + this_len = len; - /* operation does not cross the win_size, so one shot it */ - memcpy_fromio(to, map->virt + (from % state->win_size), len); + gf_set_gpios(state, from); + memcpy_fromio(to, map->virt + (from % state->win_size), + this_len); + len -= this_len; + from += this_len; + to += this_len; + } } /** @@ -147,13 +153,21 @@ static void gf_copy_to(struct map_info *map, unsigned long to, { struct async_state *state = gf_map_info_to_state(map); - gf_set_gpios(state, to); + int this_len; + + while (len) { + if ((to % state->win_size) + len > state->win_size) + this_len = state->win_size - (to % state->win_size); + else + this_len = len; - /* BUG if operation crosses the win_size */ - BUG_ON(!((to + len) % state->win_size <= (to + len))); + gf_set_gpios(state, to); + memcpy_toio(map->virt + (to % state->win_size), from, len); - /* operation does not cross the win_size, so one shot it */ - memcpy_toio(map->virt + (to % state->win_size), from, len); + len -= this_len; + to += this_len; + from += this_len; + } } static const char * const part_probe_types[] = { -- cgit v0.10.2 From ab75e89c013d8fff8bd8a6e520d184c3da1a4583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Aug 2014 09:47:01 +0200 Subject: mtd: spi-nor: remove duplicated w25q128 entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Acked-by: Huang Shijie Signed-off-by: Brian Norris diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 4dc0c86..2fea172 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -624,7 +624,6 @@ const struct spi_device_id spi_nor_ids[] = { { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, - { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, -- cgit v0.10.2 From 54ea17a597b00e46b3720e75dd7595cd5dfa5670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 7 Aug 2014 09:47:02 +0200 Subject: mtd: spi-nor: drop jedec_probe /helper/ function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a one-liner doing no magic and its name may be confusing because it does not have to use JEDEC (e.g. when using alternative read_id). Signed-off-by: Rafał Miłecki Acked-by: Huang Shijie Signed-off-by: Brian Norris diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2fea172..03e0ab8 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -671,11 +671,6 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) return ERR_PTR(-ENODEV); } -static const struct spi_device_id *jedec_probe(struct spi_nor *nor) -{ - return nor->read_id(nor); -} - static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -958,7 +953,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (info->jedec_id) { const struct spi_device_id *jid; - jid = jedec_probe(nor); + jid = nor->read_id(nor); if (IS_ERR(jid)) { return PTR_ERR(jid); } else if (jid != id) { -- cgit v0.10.2 From 43914a2dcc8f9fc1c25e6bd2650d8e7ad1a9b04a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Sep 2014 11:01:51 +0900 Subject: mtd: denali: fix the format of comment blocks We should use /* * Blah Blah ... * ... */ for multi-line comment blocks. In addition, refactor some comments where it seems reasonable and remove some comments where the code is clear enough such as: /* clear interrupts */ clear_interrupts(denali); Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4885a0f..766af04 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -29,7 +29,8 @@ MODULE_LICENSE("GPL"); -/* We define a module parameter that allows the user to override +/* + * We define a module parameter that allows the user to override * the hardware and decide what timing mode should be used. */ #define NAND_DEFAULT_TIMINGS -1 @@ -41,8 +42,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define DENALI_NAND_NAME "denali-nand" -/* We define a macro here that combines all interrupts this driver uses into - * a single constant value, for convenience. */ +/* + * We define a macro here that combines all interrupts this driver uses into + * a single constant value, for convenience. + */ #define DENALI_IRQ_ALL (INTR_STATUS__DMA_CMD_COMP | \ INTR_STATUS__ECC_TRANSACTION_DONE | \ INTR_STATUS__ECC_ERR | \ @@ -54,23 +57,30 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." INTR_STATUS__RST_COMP | \ INTR_STATUS__ERASE_COMP) -/* indicates whether or not the internal value for the flash bank is - * valid or not */ +/* + * indicates whether or not the internal value for the flash bank is + * valid or not + */ #define CHIP_SELECT_INVALID -1 #define SUPPORT_8BITECC 1 -/* This macro divides two integers and rounds fractional values up - * to the nearest integer value. */ +/* + * This macro divides two integers and rounds fractional values up + * to the nearest integer value. + */ #define CEIL_DIV(X, Y) (((X)%(Y)) ? ((X)/(Y)+1) : ((X)/(Y))) -/* this macro allows us to convert from an MTD structure to our own +/* + * this macro allows us to convert from an MTD structure to our own * device context (denali) structure. */ #define mtd_to_denali(m) container_of(m, struct denali_nand_info, mtd) -/* These constants are defined by the driver to enable common driver - * configuration options. */ +/* + * These constants are defined by the driver to enable common driver + * configuration options. + */ #define SPARE_ACCESS 0x41 #define MAIN_ACCESS 0x42 #define MAIN_SPARE_ACCESS 0x43 @@ -84,8 +94,10 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." #define ADDR_CYCLE 1 #define STATUS_CYCLE 2 -/* this is a helper macro that allows us to - * format the bank into the proper bits for the controller */ +/* + * this is a helper macro that allows us to + * format the bank into the proper bits for the controller + */ #define BANK(x) ((x) << 24) /* forward declarations */ @@ -96,12 +108,12 @@ static void denali_irq_enable(struct denali_nand_info *denali, uint32_t int_mask); static uint32_t read_interrupt_status(struct denali_nand_info *denali); -/* Certain operations for the denali NAND controller use - * an indexed mode to read/write data. The operation is - * performed by writing the address value of the command - * to the device memory followed by the data. This function +/* + * Certain operations for the denali NAND controller use an indexed mode to + * read/write data. The operation is performed by writing the address value + * of the command to the device memory followed by the data. This function * abstracts this common operation. -*/ + */ static void index_addr(struct denali_nand_info *denali, uint32_t address, uint32_t data) { @@ -117,8 +129,10 @@ static void index_addr_read_data(struct denali_nand_info *denali, *pdata = ioread32(denali->flash_mem + 0x10); } -/* We need to buffer some data for some of the NAND core routines. - * The operations manage buffering that data. */ +/* + * We need to buffer some data for some of the NAND core routines. + * The operations manage buffering that data. + */ static void reset_buf(struct denali_nand_info *denali) { denali->buf.head = denali->buf.tail = 0; @@ -192,7 +206,8 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) return PASS; } -/* this routine calculates the ONFI timing values for a given mode and +/* + * this routine calculates the ONFI timing values for a given mode and * programs the clocking register accordingly. The mode is determined by * the get_onfi_nand_para routine. */ @@ -298,9 +313,11 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) { int i; - /* we needn't to do a reset here because driver has already + + /* + * we needn't to do a reset here because driver has already * reset all the banks before - * */ + */ if (!(ioread32(denali->flash_reg + ONFI_TIMING_MODE) & ONFI_TIMING_MODE__VALUE)) return FAIL; @@ -313,8 +330,10 @@ static uint16_t get_onfi_nand_para(struct denali_nand_info *denali) nand_onfi_timing_set(denali, i); - /* By now, all the ONFI devices we know support the page cache */ - /* rw feature. So here we enable the pipeline_rw_ahead feature */ + /* + * By now, all the ONFI devices we know support the page cache + * rw feature. So here we enable the pipeline_rw_ahead feature + */ /* iowrite32(1, denali->flash_reg + CACHE_WRITE_ENABLE); */ /* iowrite32(1, denali->flash_reg + CACHE_READ_ENABLE); */ @@ -340,8 +359,10 @@ static void get_toshiba_nand_para(struct denali_nand_info *denali) { uint32_t tmp; - /* Workaround to fix a controller bug which reports a wrong */ - /* spare area size for some kind of Toshiba NAND device */ + /* + * Workaround to fix a controller bug which reports a wrong + * spare area size for some kind of Toshiba NAND device + */ if ((ioread32(denali->flash_reg + DEVICE_MAIN_AREA_SIZE) == 4096) && (ioread32(denali->flash_reg + DEVICE_SPARE_AREA_SIZE) == 64)) { iowrite32(216, denali->flash_reg + DEVICE_SPARE_AREA_SIZE); @@ -391,7 +412,8 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, } } -/* determines how many NAND chips are connected to the controller. Note for +/* + * determines how many NAND chips are connected to the controller. Note for * Intel CE4100 devices we don't support more than one device. */ static void find_valid_banks(struct denali_nand_info *denali) @@ -421,7 +443,8 @@ static void find_valid_banks(struct denali_nand_info *denali) } if (denali->platform == INTEL_CE4100) { - /* Platform limitations of the CE4100 device limit + /* + * Platform limitations of the CE4100 device limit * users to a single chip solution for NAND. * Multichip support is not enabled. */ @@ -449,12 +472,13 @@ static void detect_max_banks(struct denali_nand_info *denali) static void detect_partition_feature(struct denali_nand_info *denali) { - /* For MRST platform, denali->fwblks represent the + /* + * For MRST platform, denali->fwblks represent the * number of blocks firmware is taken, * FW is in protect partition and MTD driver has no * permission to access it. So let driver know how many * blocks it can't touch. - * */ + */ if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { @@ -481,11 +505,11 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); - /* Use read id method to get device ID and other - * params. For some NAND chips, controller can't - * report the correct device ID by reading from - * DEVICE_ID register - * */ + /* + * Use read id method to get device ID and other params. + * For some NAND chips, controller can't report the correct + * device ID by reading from DEVICE_ID register + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -524,7 +548,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) detect_partition_feature(denali); - /* If the user specified to override the default timings + /* + * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. */ if (onfi_timing_mode != NAND_DEFAULT_TIMINGS) @@ -545,7 +570,8 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, iowrite32(0, denali->flash_reg + GLOBAL_INT_ENABLE); } -/* validation function to verify that the controlling software is making +/* + * validation function to verify that the controlling software is making * a valid request */ static inline bool is_flash_bank_valid(int flash_bank) @@ -585,7 +611,8 @@ static void denali_irq_enable(struct denali_nand_info *denali, iowrite32(int_mask, denali->flash_reg + INTR_EN(i)); } -/* This function only returns when an interrupt that this driver cares about +/* + * This function only returns when an interrupt that this driver cares about * occurs. This is to reduce the overhead of servicing interrupts */ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) @@ -625,9 +652,9 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) return ioread32(denali->flash_reg + intr_status_reg); } -/* This is the interrupt service routine. It handles all interrupts - * sent to this device. Note that on CE4100, this is a shared - * interrupt. +/* + * This is the interrupt service routine. It handles all interrupts + * sent to this device. Note that on CE4100, this is a shared interrupt. */ static irqreturn_t denali_isr(int irq, void *dev_id) { @@ -637,19 +664,21 @@ static irqreturn_t denali_isr(int irq, void *dev_id) spin_lock(&denali->irq_lock); - /* check to see if a valid NAND chip has - * been selected. - */ + /* check to see if a valid NAND chip has been selected. */ if (is_flash_bank_valid(denali->flash_bank)) { - /* check to see if controller generated - * the interrupt, since this is a shared interrupt */ + /* + * check to see if controller generated the interrupt, + * since this is a shared interrupt + */ irq_status = denali_irq_detected(denali); if (irq_status != 0) { /* handle interrupt */ /* first acknowledge it */ clear_interrupt(denali, irq_status); - /* store the status in the device context for someone - to read */ + /* + * store the status in the device context for someone + * to read + */ denali->irq_status |= irq_status; /* notify anyone who cares that it happened */ complete(&denali->complete); @@ -681,8 +710,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) /* our interrupt was detected */ break; } else { - /* these are not the interrupts you are looking for - - * need to wait again */ + /* + * these are not the interrupts you are looking for - + * need to wait again + */ spin_unlock_irq(&denali->irq_lock); retry = true; } @@ -698,8 +729,10 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) return intr_status; } -/* This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. */ +/* + * This helper function setups the registers for ECC and whether or not + * the spare area will be transferred. + */ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { @@ -715,7 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, denali->flash_reg + TRANSFER_SPARE_REG); } -/* sends a pipeline command operation to the controller. See the Denali NAND +/* + * sends a pipeline command operation to the controller. See the Denali NAND * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, @@ -737,7 +771,6 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, setup_ecc_for_xfer(denali, ecc_en, transfer_spare); - /* clear interrupts */ clear_interrupts(denali); addr = BANK(denali->flash_bank) | denali->page; @@ -757,9 +790,10 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_10 | addr; index_addr(denali, (uint32_t)cmd, access_type); - /* page 33 of the NAND controller spec indicates we should not - use the pipeline commands in Spare area only mode. So we - don't. + /* + * page 33 of the NAND controller spec indicates we should not + * use the pipeline commands in Spare area only mode. + * So we don't. */ if (access_type == SPARE_ACCESS) { cmd = MODE_01 | addr; @@ -768,10 +802,11 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, index_addr(denali, (uint32_t)cmd, PIPELINE_ACCESS | op | page_count); - /* wait for command to be accepted + /* + * wait for command to be accepted * can always use status0 bit as the - * mask is identical for each - * bank. */ + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { @@ -796,8 +831,10 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* verify that the len is a multiple of 4. see comment in - * read_data_from_flash_mem() */ + /* + * verify that the len is a multiple of 4. + * see comment in read_data_from_flash_mem() + */ BUG_ON((len % 4) != 0); /* write the data to the flash memory */ @@ -814,14 +851,12 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, { uint32_t i = 0, *buf32; - /* we assume that len will be a multiple of 4, if not - * it would be nice to know about it ASAP rather than - * have random failures... - * This assumption is based on the fact that this - * function is designed to be used to read flash pages, - * which are typically multiples of 4... + /* + * we assume that len will be a multiple of 4, if not it would be nice + * to know about it ASAP rather than have random failures... + * This assumption is based on the fact that this function is designed + * to be used to read flash pages, which are typically multiples of 4. */ - BUG_ON((len % 4) != 0); /* transfer the data from the flash */ @@ -873,16 +908,19 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) DENALI_READ) == PASS) { read_data_from_flash_mem(denali, buf, mtd->oobsize); - /* wait for command to be accepted - * can always use status0 bit as the mask is identical for each - * bank. */ + /* + * wait for command to be accepted + * can always use status0 bit as the + * mask is identical for each bank. + */ irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) dev_err(denali->dev, "page on OOB timeout %d\n", denali->page); - /* We set the device back to MAIN_ACCESS here as I observed + /* + * We set the device back to MAIN_ACCESS here as I observed * instability with the controller if you do a block erase * and the last transaction was a SPARE_ACCESS. Block erase * is reliable (according to the MTD test infrastructure) @@ -894,7 +932,8 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) } } -/* this function examines buffers to see if they contain data that +/* + * this function examines buffers to see if they contain data that * indicate that the buffer is part of an erased region of flash. */ static bool is_erased(uint8_t *buf, int len) @@ -940,13 +979,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, err_device = ECC_ERR_DEVICE(err_correction_info); if (ECC_ERROR_CORRECTABLE(err_correction_info)) { - /* If err_byte is larger than ECC_SECTOR_SIZE, + /* + * If err_byte is larger than ECC_SECTOR_SIZE, * means error happened in OOB, so we ignore * it. It's no need for us to correct it * err_device is represented the NAND error * bits are happened in if there are more * than one NAND connected. - * */ + */ if (err_byte < ECC_SECTOR_SIZE) { int offset; offset = (err_sector * @@ -960,17 +1000,19 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, bitflips++; } } else { - /* if the error is not correctable, need to + /* + * if the error is not correctable, need to * look at the page to see if it is an erased * page. if so, then it's not a real ECC error - * */ + */ check_erased_page = true; } } while (!ECC_LAST_ERR(err_correction_info)); - /* Once handle all ecc errors, controller will triger + /* + * Once handle all ecc errors, controller will triger * a ECC_TRANSACTION_DONE interrupt, so here just wait * for a while for this interrupt - * */ + */ while (!(read_interrupt_status(denali) & INTR_STATUS__ECC_TRANSACTION_DONE)) cpu_relax(); @@ -1013,12 +1055,14 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) /* 3. set memory low address bits 23:8 */ index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); - /* 4. interrupt when complete, burst len = 64 bytes*/ + /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); } -/* writes a page. user specifies type, and this function handles the - * configuration details. */ +/* + * writes a page. user specifies type, and this function handles the + * configuration details. + */ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { @@ -1031,8 +1075,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; - /* if it is a raw xfer, we want to disable ecc, and send - * the spare area. + /* + * if it is a raw xfer, we want to disable ecc and send the spare area. * !raw_xfer - enable ecc * raw_xfer - transfer spare */ @@ -1073,27 +1117,33 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, /* NAND core entry points */ -/* this is the callback that the NAND core calls to write a page. Since +/* + * this is the callback that the NAND core calls to write a page. Since * writing a page with ECC or without is similar, all the work is done * by write_page above. - * */ + */ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for regular page writes, we let HW handle all the ECC - * data written to the device. */ + /* + * for regular page writes, we let HW handle all the ECC + * data written to the device. + */ return write_page(mtd, chip, buf, false); } -/* This is the callback that the NAND core calls to write a page without ECC. +/* + * This is the callback that the NAND core calls to write a page without ECC. * raw access is similar to ECC page writes, so all the work is done in the * write_page() function above. */ static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { - /* for raw page writes, we want to disable ECC and simply write - whatever data is in the buffer. */ + /* + * for raw page writes, we want to disable ECC and simply write + * whatever data is in the buffer. + */ return write_page(mtd, chip, buf, true); } @@ -1238,7 +1288,6 @@ static int denali_erase(struct mtd_info *mtd, int page) uint32_t cmd = 0x0, irq_status = 0; - /* clear interrupts */ clear_interrupts(denali); /* setup page read request for access type */ @@ -1268,10 +1317,11 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, case NAND_CMD_READID: case NAND_CMD_PARAM: reset_buf(denali); - /*sometimes ManufactureId read from register is not right + /* + * sometimes ManufactureId read from register is not right * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand - * */ + */ addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); index_addr(denali, (uint32_t)addr | 0, 0x90); index_addr(denali, (uint32_t)addr | 1, 0); @@ -1331,11 +1381,12 @@ static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) /* Initialization code to bring the device up to a known good state */ static void denali_hw_init(struct denali_nand_info *denali) { - /* tell driver how many bit controller will skip before + /* + * tell driver how many bit controller will skip before * writing ECC code in OOB, this register may be already * set by firmware. So we read this value out. * if this value is 0, just let it be. - * */ + */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); detect_max_banks(denali); @@ -1353,10 +1404,11 @@ static void denali_hw_init(struct denali_nand_info *denali) denali_irq_init(denali); } -/* Althogh controller spec said SLC ECC is forceb to be 4bit, +/* + * Althogh controller spec said SLC ECC is forceb to be 4bit, * but denali controller in MRST only support 15bit and 8bit ECC * correction - * */ + */ #define ECC_8BITS 14 static struct nand_ecclayout nand_8bit_oob = { .eccbytes = 14, @@ -1396,13 +1448,16 @@ static void denali_drv_init(struct denali_nand_info *denali) denali->idx = 0; /* setup interrupt handler */ - /* the completion object will be used to notify - * the callee that the interrupt is done */ + /* + * the completion object will be used to notify + * the callee that the interrupt is done + */ init_completion(&denali->complete); - /* the spinlock will be used to synchronize the ISR - * with any element that might be access shared - * data (interrupt status) */ + /* + * the spinlock will be used to synchronize the ISR with any + * element that might be access shared data (interrupt status) + */ spin_lock_init(&denali->irq_lock); /* indicate that MTD has not selected a valid bank yet */ @@ -1417,7 +1472,8 @@ int denali_init(struct denali_nand_info *denali) int ret; if (denali->platform == INTEL_CE4100) { - /* Due to a silicon limitation, we can only support + /* + * Due to a silicon limitation, we can only support * ONFI timing mode 1 and below. */ if (onfi_timing_mode < -1 || onfi_timing_mode > 1) { @@ -1436,8 +1492,10 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); - /* denali_isr register is done after all the hardware - * initilization is finished*/ + /* + * denali_isr register is done after all the hardware + * initilization is finished + */ if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { pr_err("Spectra: Unable to allocate IRQ\n"); @@ -1456,9 +1514,11 @@ int denali_init(struct denali_nand_info *denali) denali->nand.read_byte = denali_read_byte; denali->nand.waitfunc = denali_waitfunc; - /* scan for NAND devices attached to the controller + /* + * scan for NAND devices attached to the controller * this is the first stage in a two step process to register - * with the nand subsystem */ + * with the nand subsystem + */ if (nand_scan_ident(&denali->mtd, denali->max_banks, NULL)) { ret = -ENXIO; goto failed_req_irq; @@ -1490,10 +1550,10 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* support for multi nand - * MTD known nothing about multi nand, - * so we should tell it the real pagesize - * and anything necessery + /* + * support for multi nand + * MTD known nothing about multi nand, so we should tell it + * the real pagesize and anything necessery */ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); denali->nand.chipsize <<= (denali->devnum - 1); @@ -1509,9 +1569,11 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.size = denali->nand.numchips * denali->nand.chipsize; denali->bbtskipbytes *= denali->devnum; - /* second stage of the NAND scan + /* + * second stage of the NAND scan * this stage requires information regarding ECC and - * bad block management. */ + * bad block management. + */ /* Bad block management */ denali->nand.bbt_td = &bbt_main_descr; @@ -1522,7 +1584,8 @@ int denali_init(struct denali_nand_info *denali) denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; - /* Denali Controller only support 15bit and 8bit ECC in MRST, + /* + * Denali Controller only support 15bit and 8bit ECC in MRST, * so just let controller do 15bit ECC for MLC and 8bit ECC for * SLC if possible. * */ @@ -1558,18 +1621,20 @@ int denali_init(struct denali_nand_info *denali) denali->mtd.oobsize - denali->nand.ecc.layout->eccbytes - denali->bbtskipbytes; - /* Let driver know the total blocks number and - * how many blocks contained by each nand chip. - * blksperchip will help driver to know how many - * blocks is taken by FW. - * */ + /* + * Let driver know the total blocks number and how many blocks + * contained by each nand chip. blksperchip will help driver to + * know how many blocks is taken by FW. + */ denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; - /* These functions are required by the NAND core framework, otherwise, + /* + * These functions are required by the NAND core framework, otherwise, * the NAND core will assert. However, we don't need them, so we'll stub - * them out. */ + * them out. + */ denali->nand.ecc.calculate = denali_ecc_calculate; denali->nand.ecc.correct = denali_ecc_correct; denali->nand.ecc.hwctl = denali_ecc_hwctl; -- cgit v0.10.2 From 5637b69d1c489d4585c94a2a1d0a38f4e6b1a705 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Sep 2014 11:01:52 +0900 Subject: mtd: denali: remove unnecessary variable initializations All of these variables are initialized to zero and then set to a different value below. Zero-initializing is redundant. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 766af04..20823df 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -146,7 +146,7 @@ static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) /* reads the status of the device */ static void read_status(struct denali_nand_info *denali) { - uint32_t cmd = 0x0; + uint32_t cmd; /* initialize the data buffer to store status */ reset_buf(denali); @@ -161,7 +161,7 @@ static void read_status(struct denali_nand_info *denali) /* resets a specific device connected to the core */ static void reset_bank(struct denali_nand_info *denali) { - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; @@ -581,7 +581,7 @@ static inline bool is_flash_bank_valid(int flash_bank) static void denali_irq_init(struct denali_nand_info *denali) { - uint32_t int_mask = 0; + uint32_t int_mask; int i; /* Disable global interrupts */ @@ -624,7 +624,7 @@ static inline uint32_t denali_irq_detected(struct denali_nand_info *denali) static inline void clear_interrupt(struct denali_nand_info *denali, uint32_t irq_mask) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -633,7 +633,8 @@ static inline void clear_interrupt(struct denali_nand_info *denali, static void clear_interrupts(struct denali_nand_info *denali) { - uint32_t status = 0x0; + uint32_t status; + spin_lock_irq(&denali->irq_lock); status = read_interrupt_status(denali); @@ -645,7 +646,7 @@ static void clear_interrupts(struct denali_nand_info *denali) static uint32_t read_interrupt_status(struct denali_nand_info *denali) { - uint32_t intr_status_reg = 0; + uint32_t intr_status_reg; intr_status_reg = INTR_STATUS(denali->flash_bank); @@ -659,7 +660,7 @@ static uint32_t read_interrupt_status(struct denali_nand_info *denali) static irqreturn_t denali_isr(int irq, void *dev_id) { struct denali_nand_info *denali = dev_id; - uint32_t irq_status = 0x0; + uint32_t irq_status; irqreturn_t result = IRQ_NONE; spin_lock(&denali->irq_lock); @@ -693,8 +694,8 @@ static irqreturn_t denali_isr(int irq, void *dev_id) static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { - unsigned long comp_res = 0; - uint32_t intr_status = 0; + unsigned long comp_res; + uint32_t intr_status; bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); @@ -736,7 +737,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { - int ecc_en_flag = 0, transfer_spare_flag = 0; + int ecc_en_flag, transfer_spare_flag; /* set ECC, transfer spare bits if needed */ ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; @@ -759,8 +760,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, int op) { int status = PASS; - uint32_t addr = 0x0, cmd = 0x0, page_count = 1, irq_status = 0, - irq_mask = 0; + uint32_t page_count = 1; + uint32_t addr, cmd, irq_status, irq_mask; if (op == DENALI_READ) irq_mask = INTR_STATUS__LOAD_COMP; @@ -829,7 +830,7 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * verify that the len is a multiple of 4. @@ -849,7 +850,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i = 0, *buf32; + uint32_t i, *buf32; /* * we assume that len will be a multiple of 4, if not it would be nice @@ -870,7 +871,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__PROGRAM_COMP | INTR_STATUS__PROGRAM_FAIL; int status = 0; @@ -899,8 +900,8 @@ static int write_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t irq_mask = INTR_STATUS__LOAD_COMP, - irq_status = 0, addr = 0x0, cmd = 0x0; + uint32_t irq_mask = INTR_STATUS__LOAD_COMP; + uint32_t irq_status, addr, cmd; denali->page = page; @@ -938,7 +939,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ static bool is_erased(uint8_t *buf, int len) { - int i = 0; + int i; for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -961,9 +962,8 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, if (irq_status & INTR_STATUS__ECC_ERR) { /* read the ECC errors. we'll ignore them for now */ - uint32_t err_address = 0, err_correction_info = 0; - uint32_t err_byte = 0, err_sector = 0, err_device = 0; - uint32_t err_correction_value = 0; + uint32_t err_address, err_correction_info, err_byte, + err_sector, err_device, err_correction_value; denali_set_intr_modes(denali, false); do { @@ -1026,19 +1026,14 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, /* programs the controller to either enable/disable DMA transfers */ static void denali_enable_dma(struct denali_nand_info *denali, bool en) { - uint32_t reg_val = 0x0; - - if (en) - reg_val = DMA_ENABLE__FLAG; - - iowrite32(reg_val, denali->flash_reg + DMA_ENABLE); + iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->flash_reg + DMA_ENABLE); ioread32(denali->flash_reg + DMA_ENABLE); } /* setups the HW to perform the data DMA */ static void denali_setup_dma(struct denali_nand_info *denali, int op) { - uint32_t mode = 0x0; + uint32_t mode; const int page_count = 1; dma_addr_t addr = denali->buf.dma_buf; @@ -1071,7 +1066,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1170,7 +1165,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR; bool check_erased_page = false; @@ -1222,7 +1217,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status = 0; + uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1286,7 +1281,7 @@ static int denali_erase(struct mtd_info *mtd, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - uint32_t cmd = 0x0, irq_status = 0; + uint32_t cmd, irq_status; clear_interrupts(denali); -- cgit v0.10.2 From 3157d1ed23098e3b004e78bc342af10d62f820f7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Sep 2014 11:01:53 +0900 Subject: mtd: denali: remove unnecessary casts Useless casts result in unreadable source code. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 20823df..6013439 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -423,10 +423,10 @@ static void find_valid_banks(struct denali_nand_info *denali) denali->total_used_banks = 1; for (i = 0; i < denali->max_banks; i++) { - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 0), 0x90); - index_addr(denali, (uint32_t)(MODE_11 | (i << 24) | 1), 0); + index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); + index_addr(denali, MODE_11 | (i << 24) | 1, 0); index_addr_read_data(denali, - (uint32_t)(MODE_11 | (i << 24) | 2), &id[i]); + MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -510,9 +510,9 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) * For some NAND chips, controller can't report the correct * device ID by reading from DEVICE_ID register */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) index_addr_read_data(denali, addr | 2, &id_bytes[i]); maf_id = id_bytes[0]; @@ -782,14 +782,14 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, } else if (op == DENALI_WRITE && access_type == SPARE_ACCESS) { /* read spare area */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else if (op == DENALI_READ) { /* setup page read request for access type */ cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, access_type); + index_addr(denali, cmd, access_type); /* * page 33 of the NAND controller spec indicates we should not @@ -800,7 +800,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, cmd = MODE_01 | addr; iowrite32(cmd, denali->flash_mem); } else { - index_addr(denali, (uint32_t)cmd, + index_addr(denali, cmd, PIPELINE_ACCESS | op | page_count); /* @@ -929,7 +929,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) */ addr = BANK(denali->flash_bank) | denali->page; cmd = MODE_10 | addr; - index_addr(denali, (uint32_t)cmd, MAIN_ACCESS); + index_addr(denali, cmd, MAIN_ACCESS); } } @@ -1035,7 +1035,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) { uint32_t mode; const int page_count = 1; - dma_addr_t addr = denali->buf.dma_buf; + uint32_t addr = denali->buf.dma_buf; mode = MODE_10 | BANK(denali->flash_bank); @@ -1045,10 +1045,10 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op) index_addr(denali, mode | denali->page, 0x2000 | op | page_count); /* 2. set memory high address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)(addr >> 16) << 8), 0x2200); + index_addr(denali, mode | ((addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - index_addr(denali, mode | ((uint16_t)addr << 8), 0x2300); + index_addr(denali, mode | ((addr & 0xff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ index_addr(denali, mode | 0x14000, 0x2400); @@ -1287,7 +1287,7 @@ static int denali_erase(struct mtd_info *mtd, int page) /* setup page read request for access type */ cmd = MODE_10 | BANK(denali->flash_bank) | page; - index_addr(denali, (uint32_t)cmd, 0x1); + index_addr(denali, cmd, 0x1); /* wait for erase to complete or failure to occur */ irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | @@ -1317,12 +1317,12 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, * e.g. some of Micron MT29F32G08QAA MLC NAND chips * So here we send READID cmd to NAND insteand */ - addr = (uint32_t)MODE_11 | BANK(denali->flash_bank); - index_addr(denali, (uint32_t)addr | 0, 0x90); - index_addr(denali, (uint32_t)addr | 1, 0); + addr = MODE_11 | BANK(denali->flash_bank); + index_addr(denali, addr | 0, 0x90); + index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { index_addr_read_data(denali, - (uint32_t)addr | 2, + addr | 2, &id); write_byte_to_buf(denali, id); } -- cgit v0.10.2 From 93e3c8adf6fcf2204ca334237b92c7f8cdafce6f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Sep 2014 11:01:54 +0900 Subject: mtd: denali: change the type of iterators to int We should rathar use "int" type for loop iterators. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 6013439..4cb1497 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -178,7 +178,7 @@ static void reset_bank(struct denali_nand_info *denali) /* Reset the flash controller */ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { - uint32_t i; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); @@ -499,7 +499,8 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) { uint16_t status = PASS; uint32_t id_bytes[8], addr; - uint8_t i, maf_id, device_id; + uint8_t maf_id, device_id; + int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", @@ -830,7 +831,8 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, const uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * verify that the len is a multiple of 4. @@ -850,7 +852,8 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, uint8_t *buf, int len) { - uint32_t i, *buf32; + uint32_t *buf32; + int i; /* * we assume that len will be a multiple of 4, if not it would be nice -- cgit v0.10.2 From 55ab9ec99bbfb4450dfa9bc0fd9e2c5052f4c3f7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 9 Sep 2014 11:01:55 +0900 Subject: mtd: denali: remove a set-but-unused variable The variable "retry" in wait_for_irq() is set, but not used. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4cb1497..cd58601 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -697,7 +697,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) { unsigned long comp_res; uint32_t intr_status; - bool retry = false; unsigned long timeout = msecs_to_jiffies(1000); do { @@ -717,7 +716,6 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) * need to wait again */ spin_unlock_irq(&denali->irq_lock); - retry = true; } } while (comp_res != 0); -- cgit v0.10.2 From 2d405ec5fdd5b6848beb820301d4fcaa3e2c4159 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Sat, 13 Sep 2014 01:23:59 +0200 Subject: mtd: nand: atmel_nand: retrieve NFC clock Retrieve the NFC clock to make sure it is enabled. Make that optional to ensure compatibility with previous device trees but document it as mandatory so newer device trees will include it. Signed-off-by: Boris BREZILLON Signed-off-by: Alexandre Belloni Acked-by: Josh Wu Signed-off-by: Brian Norris diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt index c472883..6edc3b6 100644 --- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt +++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt @@ -36,6 +36,7 @@ Optional properties: - reg : should specify the address and size used for NFC command registers, NFC registers and NFC Sram. NFC Sram address and size can be absent if don't want to use it. + - clocks: phandle to the peripheral clock - Optional properties: - atmel,write-by-sram: boolean to enable NFC write by sram. @@ -98,6 +99,7 @@ nand0: nand@40000000 { compatible = "atmel,sama5d3-nfc"; #address-cells = <1>; #size-cells = <1>; + clocks = <&hsmc_clk> reg = < 0x70000000 0x10000000 /* NFC Command Registers */ 0xffffc000 0x00000070 /* NFC HSMC regs */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 9c5f717..d1e502f 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -27,6 +27,7 @@ * */ +#include #include #include #include @@ -96,6 +97,8 @@ struct atmel_nfc { bool use_nfc_sram; bool write_by_sram; + struct clk *clk; + bool is_initialized; struct completion comp_ready; struct completion comp_cmd_done; @@ -2248,6 +2251,7 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) { struct atmel_nfc *nfc = &nand_nfc; struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram; + int ret; nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs); @@ -2279,8 +2283,28 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ + nfc->clk = devm_clk_get(&pdev->dev, NULL); + if (!IS_ERR(nfc->clk)) { + ret = clk_prepare_enable(nfc->clk); + if (ret) + return ret; + } else { + dev_warn(&pdev->dev, "NFC clock missing, update your Device Tree"); + } + nfc->is_initialized = true; dev_info(&pdev->dev, "NFC is probed.\n"); + + return 0; +} + +static int atmel_nand_nfc_remove(struct platform_device *pdev) +{ + struct atmel_nfc *nfc = &nand_nfc; + + if (!IS_ERR(nfc->clk)) + clk_disable_unprepare(nfc->clk); + return 0; } @@ -2297,6 +2321,7 @@ static struct platform_driver atmel_nand_nfc_driver = { .of_match_table = of_match_ptr(atmel_nand_nfc_match), }, .probe = atmel_nand_nfc_probe, + .remove = atmel_nand_nfc_remove, }; static struct platform_driver atmel_nand_driver = { -- cgit v0.10.2 From fef775caa705255358cdf7bbaf9bbc2fd1111761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= Date: Thu, 11 Sep 2014 12:02:08 -0300 Subject: nand: omap2: Add support for flash-based bad block table This commit adds a new platform-data boolean property that enables use of a flash-based bad block table. This can also be enabled by setting the 'nand-on-flash-bbt' devicetree property. If the flash BBT is not enabled, the driver falls back to use OOB bad block markers only, as before. If the flash BBT is enabled the kernel will keep track of bad blocks using a BBT, in addition to the OOB markers. As explained by Brian Norris the reasons for using a BBT are: "" The primary reason would be that NAND datasheets specify it these days. A better argument is that nobody guarantees that you can write a bad block marker to a worn out block; you may just get program failures. This has been acknowledged by several developers over the last several years. Additionally, you get a boot-time performance improvement if you only have to read a few pages, instead of a page or two from every block on the flash. "" Signed-off-by: Ezequiel Garcia Acked-by: Roger Quadros Signed-off-by: Brian Norris diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 2f97228..b55a225 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1440,6 +1440,8 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, break; } + gpmc_nand_data->flash_bbt = of_get_nand_on_flash_bbt(child); + val = of_get_nand_bus_width(child); if (val == 16) gpmc_nand_data->devsize = NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5967b38..e1a9b31 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1663,7 +1663,6 @@ static int omap_nand_probe(struct platform_device *pdev) mtd->owner = THIS_MODULE; nand_chip = &info->nand; nand_chip->ecc.priv = NULL; - nand_chip->options |= NAND_SKIP_BBTSCAN; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); @@ -1692,6 +1691,11 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 50; } + if (pdata->flash_bbt) + nand_chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; + else + nand_chip->options |= NAND_SKIP_BBTSCAN; + /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { diff --git a/include/linux/platform_data/mtd-nand-omap2.h b/include/linux/platform_data/mtd-nand-omap2.h index 16ec262..090bbab 100644 --- a/include/linux/platform_data/mtd-nand-omap2.h +++ b/include/linux/platform_data/mtd-nand-omap2.h @@ -71,6 +71,7 @@ struct omap_nand_platform_data { struct mtd_partition *parts; int nr_parts; bool dev_ready; + bool flash_bbt; enum nand_io xfer_type; int devsize; enum omap_ecc ecc_opt; -- cgit v0.10.2 From c9447fff34aacc04f2e7df39612d2d6e234643f3 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 8 Aug 2014 17:12:34 +0800 Subject: mtd: atmel_nand: remove pmecc_sector_number, use ecc.steps instead For PMECC, the pmecc_sector_number has same meaning as ecc.steps. So use ecc.steps to replace the pmecc_sector_number. Signed-off-by: Josh Wu Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d1e502f..5c76704 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -132,7 +132,6 @@ struct atmel_nand_host { u32 pmecc_lookup_table_offset_1024; int pmecc_bytes_per_sector; - int pmecc_sector_number; int pmecc_degree; /* Degree of remainders */ int pmecc_cw_len; /* Length of codeword */ @@ -877,7 +876,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, return 0; normal_check: - for (i = 0; i < host->pmecc_sector_number; i++) { + for (i = 0; i < nand_chip->ecc.steps; i++) { err_nbr = 0; if (pmecc_stat & 0x1) { buf_pos = buf + i * host->pmecc_sector_size; @@ -987,7 +986,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, cpu_relax(); } - for (i = 0; i < host->pmecc_sector_number; i++) { + for (i = 0; i < chip->ecc.steps; i++) { for (j = 0; j < host->pmecc_bytes_per_sector; j++) { int pos; @@ -1034,7 +1033,7 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) else if (host->pmecc_sector_size == 1024) val |= PMECC_CFG_SECTOR1024; - switch (host->pmecc_sector_number) { + switch (nand_chip->ecc.steps) { case 1: val |= PMECC_CFG_PAGE_1SECTOR; break; @@ -1187,18 +1186,17 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, host->pmecc_degree = (sector_size == 512) ? PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; - host->pmecc_sector_number = mtd->writesize / sector_size; host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( cap, sector_size); host->pmecc_alpha_to = pmecc_get_alpha_to(host); host->pmecc_index_of = host->pmecc_rom_base + host->pmecc_lookup_table_offset; - nand_chip->ecc.steps = host->pmecc_sector_number; nand_chip->ecc.strength = cap; nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; - nand_chip->ecc.total = host->pmecc_bytes_per_sector * - host->pmecc_sector_number; + nand_chip->ecc.steps = mtd->writesize / sector_size; + nand_chip->ecc.total = nand_chip->ecc.bytes * + nand_chip->ecc.steps; if (nand_chip->ecc.total > mtd->oobsize - 2) { dev_err(host->dev, "No room for ECC bytes\n"); err_no = -EINVAL; -- cgit v0.10.2 From 022a478ce650f5c36d2a9badfd805368a90fb506 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 8 Aug 2014 17:12:35 +0800 Subject: mtd: atmel_nand: remove pmecc_bytes_per_sector, use chip->ecc.bytes instead For PMECC, the pmecc_bytes_per_sector has same meaning as ecc.bytes. So remove pmecc_bytes_per_sector and use ecc.bytes instead. Signed-off-by: Josh Wu Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 5c76704..19d1e9d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -131,7 +131,6 @@ struct atmel_nand_host { u32 pmecc_lookup_table_offset_512; u32 pmecc_lookup_table_offset_1024; - int pmecc_bytes_per_sector; int pmecc_degree; /* Degree of remainders */ int pmecc_cw_len; /* Length of codeword */ @@ -843,7 +842,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, pos, bit_pos, err_byte, *(buf + byte_pos)); } else { /* Bit flip in OOB area */ - tmp = sector_num * host->pmecc_bytes_per_sector + tmp = sector_num * nand_chip->ecc.bytes + (byte_pos - sector_size); err_byte = ecc[tmp]; ecc[tmp] ^= (1 << bit_pos); @@ -892,7 +891,7 @@ normal_check: return -EIO; } else { pmecc_correct_data(mtd, buf_pos, ecc, i, - host->pmecc_bytes_per_sector, err_nbr); + nand_chip->ecc.bytes, err_nbr); mtd->ecc_stats.corrected += err_nbr; total_err += err_nbr; } @@ -987,10 +986,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, } for (i = 0; i < chip->ecc.steps; i++) { - for (j = 0; j < host->pmecc_bytes_per_sector; j++) { + for (j = 0; j < chip->ecc.bytes; j++) { int pos; - pos = i * host->pmecc_bytes_per_sector + j; + pos = i * chip->ecc.bytes + j; chip->oob_poi[eccpos[pos]] = pmecc_readb_ecc_relaxed(host->ecc, i, j); } @@ -1186,14 +1185,12 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, host->pmecc_degree = (sector_size == 512) ? PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14; host->pmecc_cw_len = (1 << host->pmecc_degree) - 1; - host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes( - cap, sector_size); host->pmecc_alpha_to = pmecc_get_alpha_to(host); host->pmecc_index_of = host->pmecc_rom_base + host->pmecc_lookup_table_offset; nand_chip->ecc.strength = cap; - nand_chip->ecc.bytes = host->pmecc_bytes_per_sector; + nand_chip->ecc.bytes = pmecc_get_ecc_bytes(cap, sector_size); nand_chip->ecc.steps = mtd->writesize / sector_size; nand_chip->ecc.total = nand_chip->ecc.bytes * nand_chip->ecc.steps; -- cgit v0.10.2 From 024629fdca1bbb44a25d40c2362a878a7a67ce3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 18 Aug 2014 20:20:27 +0200 Subject: mtd: bcm47xxpart: find NVRAM partitions in middle blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Old devices used to have NVRAM at the very end of flash and they could be unaligned (starting at some offset in a block). In new devices NVRAM can be located quite randomly, however it seems to always start at the beginning of a block. For example Netgear R6250 has NVRAM located right after the bootloader, before the kernel partition. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index adfa74c..8057f52 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -199,6 +199,17 @@ static int bcm47xxpart_parse(struct mtd_info *master, continue; } + /* + * New (ARM?) devices may have NVRAM in some middle block. Last + * block will be checked later, so skip it. + */ + if (offset != master->size - blocksize && + buf[0x000 / 4] == NVRAM_HEADER) { + bcm47xxpart_add_part(&parts[curr_part++], "nvram", + offset, 0); + continue; + } + /* Read middle of the block */ if (mtd_read(master, offset + 0x8000, 0x4, &bytes_read, (uint8_t *)buf) < 0) { -- cgit v0.10.2 From 785e5e111f2187ea3e6f4035f6009da62dd5c043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 09:14:13 +0200 Subject: mtd: bcm47xxnflash: fix typo in freq calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are supposed to mask value, not multiply it. Add some comments btw. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index b2ab373..dc204f3 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -364,11 +364,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) /* Configure wait counters */ if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { - freq = 100000000; + /* 400 MHz */ + freq = 400000000 / 4; } else { freq = bcma_chipco_pll_read(b47n->cc, 4); - freq = (freq * 0xFFF) >> 3; - freq = (freq * 25000000) >> 3; + freq = (freq & 0xFFF) >> 3; + /* Fixed reference clock 25 MHz and m = 2 */ + freq = (freq * 25000000 / 2) / 4; } clock = freq / 1000000; w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); -- cgit v0.10.2 From 5282a3acbfa5295f331696e603a9fd6be3bd4094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 09:14:14 +0200 Subject: mtd: bcm47xxnflash: add dev_ready and fill chip_delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index dc204f3..1ea5e77 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -174,6 +174,14 @@ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, return; } +static int bcm47xxnflash_ops_bcm4706_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + + return !!(bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_CTL) & NCTL_READY); +} + /* * Default nand_command and nand_command_lp don't match BCM4706 hardware layout. * For example, reading chip id is performed in a non-standard way. @@ -341,6 +349,7 @@ static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd, int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) { + struct nand_chip *nand_chip = (struct nand_chip *)&b47n->nand_chip; int err; u32 freq; u16 clock; @@ -351,10 +360,13 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) u32 val; b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; + nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf; b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf; + + nand_chip->chip_delay = 50; b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH; b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ -- cgit v0.10.2 From 90de63324f0abc84f8c1ba56b2848c338cfda1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 09:14:15 +0200 Subject: mtd: bcm47xxnflash: add cmd_ctrl handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This won't be used by NAND subsystem as we implement cmdfunc on our own, but will allow us to write a bit cleaner code. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 1ea5e77..30df67a 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -167,6 +167,26 @@ static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd, * NAND chip ops **************************************************/ +static void bcm47xxnflash_ops_bcm4706_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv; + struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv; + u32 code = 0; + + if (cmd == NAND_CMD_NONE) + return; + + if (cmd & NAND_CTRL_CLE) + code = cmd | NCTL_CMD0; + + /* nCS is not needed for reset command */ + if (cmd != NAND_CMD_RESET) + code |= NCTL_CSA; + + bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, code); +} + /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, int chip) @@ -360,6 +380,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) u32 val; b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; + nand_chip->cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl; nand_chip->dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte; -- cgit v0.10.2 From dfbd7dda0b8dc0bb2b255d173f4e8ffbe24c5764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 09:14:16 +0200 Subject: mtd: bcm47xxnflash: NAND_CMD_RESET support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 30df67a..82844ef 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -14,6 +14,7 @@ #include #include #include +#include #include /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has @@ -226,7 +227,10 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, switch (command) { case NAND_CMD_RESET: - pr_warn("Chip reset not implemented yet\n"); + nand_chip->cmd_ctrl(mtd, command, NAND_CTRL_CLE); + + ndelay(100); + nand_wait_ready(mtd); break; case NAND_CMD_READID: ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0; -- cgit v0.10.2 From b7ab610f628a381a1029d214476742d8589f1e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 11:28:24 +0200 Subject: mtd: bcm47xxnflash: replace some magic numbers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c index 82844ef..592befc 100644 --- a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c @@ -24,6 +24,8 @@ #define NFLASH_SECTOR_SIZE 512 #define NCTL_CMD0 0x00010000 +#define NCTL_COL 0x00020000 /* Update column with value from BCMA_CC_NFLASH_COL_ADDR */ +#define NCTL_ROW 0x00040000 /* Update row (page) with value from BCMA_CC_NFLASH_ROW_ADDR */ #define NCTL_CMD1W 0x00080000 #define NCTL_READ 0x00100000 #define NCTL_WRITE 0x00200000 @@ -110,7 +112,7 @@ static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf, b47n->curr_page_addr); /* Prepare to read */ - ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 | + ctlcode = NCTL_CSA | NCTL_CMD1W | NCTL_ROW | NCTL_COL | NCTL_CMD0; ctlcode |= NAND_CMD_READSTART << 8; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) @@ -274,7 +276,7 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, case NAND_CMD_ERASE1: bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR, b47n->curr_page_addr); - ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 | + ctlcode = NCTL_ROW | NCTL_CMD1W | NCTL_CMD0 | NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8); if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("ERASE1 failed\n"); @@ -289,13 +291,13 @@ static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd, b47n->curr_page_addr); /* Prepare to write */ - ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000; + ctlcode = 0x40000000 | NCTL_ROW | NCTL_COL | NCTL_CMD0; ctlcode |= NAND_CMD_SEQIN; if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) pr_err("SEQIN failed\n"); break; case NAND_CMD_PAGEPROG: - if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 | + if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_CMD0 | NAND_CMD_PAGEPROG)) pr_err("PAGEPROG failed\n"); if (bcm47xxnflash_ops_bcm4706_poll(cc)) -- cgit v0.10.2 From 2ac63d901b1170fba509ae135d5f5f4472b84819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Aug 2014 13:55:34 +0200 Subject: mtd: nand: don't break long print messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This follows Chapter 2 of Linux's CodingStyle: > However, never break user-visible strings such as printk messages, > because that breaks the ability to grep for them. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ae6e7c4..801cad1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3936,8 +3936,7 @@ int nand_scan_tail(struct mtd_info *mtd) case NAND_ECC_HW_OOB_FIRST: /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { - pr_warn("No ECC functions supplied; " - "hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; hardware ECC not possible\n"); BUG(); } if (!ecc->read_page) @@ -3968,8 +3967,7 @@ int nand_scan_tail(struct mtd_info *mtd) ecc->read_page == nand_read_page_hwecc || !ecc->write_page || ecc->write_page == nand_write_page_hwecc)) { - pr_warn("No ECC functions supplied; " - "hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; hardware ECC not possible\n"); BUG(); } /* Use standard syndrome read/write page function? */ @@ -3993,9 +3991,8 @@ int nand_scan_tail(struct mtd_info *mtd) } break; } - pr_warn("%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - ecc->size, mtd->writesize); + pr_warn("%d byte HW ECC not possible on %d byte page size, fallback to SW ECC\n", + ecc->size, mtd->writesize); ecc->mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: @@ -4048,8 +4045,7 @@ int nand_scan_tail(struct mtd_info *mtd) break; case NAND_ECC_NONE: - pr_warn("NAND_ECC_NONE selected by board driver. " - "This is not recommended!\n"); + pr_warn("NAND_ECC_NONE selected by board driver. This is not recommended!\n"); ecc->read_page = nand_read_page_raw; ecc->write_page = nand_write_page_raw; ecc->read_oob = nand_read_oob_std; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 443fa82..9bb8453 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -201,12 +201,12 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, res = mtd_read(mtd, from, len, &retlen, buf); if (res < 0) { if (mtd_is_eccerr(res)) { - pr_info("nand_bbt: ECC error in BBT at " - "0x%012llx\n", from & ~mtd->writesize); + pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n", + from & ~mtd->writesize); return res; } else if (mtd_is_bitflip(res)) { - pr_info("nand_bbt: corrected error in BBT at " - "0x%012llx\n", from & ~mtd->writesize); + pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n", + from & ~mtd->writesize); ret = res; } else { pr_info("nand_bbt: error reading BBT\n"); @@ -580,8 +580,8 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr if (td->pages[i] == -1) pr_warn("Bad block table not found for chip %d\n", i); else - pr_info("Bad block table found at page %d, version " - "0x%02X\n", td->pages[i], td->version[i]); + pr_info("Bad block table found at page %d, version 0x%02X\n", + td->pages[i], td->version[i]); } return 0; } @@ -725,12 +725,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, res = mtd_read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - pr_info("nand_bbt: error reading block " - "for writing the bad block table\n"); + pr_info("nand_bbt: error reading block for writing the bad block table\n"); return res; } - pr_warn("nand_bbt: ECC error while reading " - "block for writing bad block table\n"); + pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; @@ -1338,9 +1336,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int)(offs >> this->bbt_erase_shift); res = bbt_get_entry(this, block); - pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " - "(block %d) 0x%02x\n", - (unsigned int)offs, block, res); + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block, res); switch (res) { case BBT_BLOCK_GOOD: -- cgit v0.10.2 From a81b4708838261784fa473582607a6c687c39d00 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 29 Aug 2014 20:00:51 +0900 Subject: mtd: denali: fix include guard and license block of denali.h It looks like this header file is a concatenation of two headers. Anyway, the include guard should be renamed and placed at the correct postion and the license block in the middle should be deleted. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 9668174..145bf88 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -17,6 +17,9 @@ * */ +#ifndef __DENALI_H__ +#define __DENALI_H__ + #include #define DEVICE_RESET 0x0 @@ -400,28 +403,6 @@ #define ONFI_BLOOM_TIME 1 #define MODE5_WORKAROUND 0 -/* lld_nand.h */ -/* - * NAND Flash Controller Device Driver - * Copyright (c) 2009, Intel Corporation and its suppliers. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#ifndef _LLD_NAND_ -#define _LLD_NAND_ #define MODE_00 0x00000000 #define MODE_01 0x04000000 @@ -499,4 +480,4 @@ struct denali_nand_info { extern int denali_init(struct denali_nand_info *denali); extern void denali_remove(struct denali_nand_info *denali); -#endif /*_LLD_NAND_*/ +#endif /* __DENALI_H__ */ -- cgit v0.10.2 From ba5f2bc2afbf598aa2efb35542cd0d40fce76c45 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 19 Sep 2014 09:37:19 -0700 Subject: mtd: denali: remove another set-but-unused variable The variable "irq_status" in denali_read_page_raw() is set, but not used. Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index cd58601..e5c39d2 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1218,7 +1218,6 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { @@ -1237,7 +1236,7 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ - irq_status = wait_for_irq(denali, irq_mask); + wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); -- cgit v0.10.2 From 7d14ecd050a43ff80ad284027a521390af1c29be Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 16 Sep 2014 20:04:24 +0900 Subject: mtd: denali: remove unnecessary parentheses We should use parentheses only when they are necessary or they really improve the readability. Signed-off-by: Masahiro Yamada Reviewed-by: Josh Triplett Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e5c39d2..945943e 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -267,10 +267,10 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, acc_clks = CEIL_DIV(Trea[mode], CLK_X); - while (((acc_clks * CLK_X) - Trea[mode]) < 3) + while (acc_clks * CLK_X - Trea[mode] < 3) acc_clks++; - if ((data_invalid - acc_clks * CLK_X) < 2) + if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", __FILE__, __LINE__); @@ -285,7 +285,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, cs_cnt = 1; if (Tcea[mode]) { - while (((cs_cnt * CLK_X) + Trea[mode]) < Tcea[mode]) + while (cs_cnt * CLK_X + Trea[mode] < Tcea[mode]) cs_cnt++; } @@ -295,8 +295,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, #endif /* Sighting 3462430: Temporary hack for MT29F128G08CJABAWP:B */ - if ((ioread32(denali->flash_reg + MANUFACTURER_ID) == 0) && - (ioread32(denali->flash_reg + DEVICE_ID) == 0x88)) + if (ioread32(denali->flash_reg + MANUFACTURER_ID) == 0 && + ioread32(denali->flash_reg + DEVICE_ID) == 0x88) acc_clks = 6; iowrite32(acc_clks, denali->flash_reg + ACC_CLKS); @@ -577,7 +577,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, */ static inline bool is_flash_bank_valid(int flash_bank) { - return (flash_bank >= 0 && flash_bank < 4); + return flash_bank >= 0 && flash_bank < 4; } static void denali_irq_init(struct denali_nand_info *denali) @@ -1293,7 +1293,7 @@ static int denali_erase(struct mtd_info *mtd, int page) irq_status = wait_for_irq(denali, INTR_STATUS__ERASE_COMP | INTR_STATUS__ERASE_FAIL); - return (irq_status & INTR_STATUS__ERASE_FAIL) ? NAND_STATUS_FAIL : PASS; + return irq_status & INTR_STATUS__ERASE_FAIL ? NAND_STATUS_FAIL : PASS; } static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, -- cgit v0.10.2 From 8125450cd855839c2f6d0eec86c560ffd02db374 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 16 Sep 2014 20:04:25 +0900 Subject: mtd: denali: fix indents and other trivial things - Fix indents - Do not break a line unless it is longer than 80 columns - Do not insert a whitespace before ';' - Use whitespaces around operators - Use braces for a "else" block where the "if" block uses ones. Besides, eliminate all the warnings reported by checkpatch.pl: - WARNING: quoted string split across lines - WARNING: else is not generally useful after a break or return - WARNING: Missing a blank line after declarations - WARNING: Avoid line continuations in quoted strings Signed-off-by: Masahiro Yamada Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 945943e..b3b7ca1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -37,8 +37,8 @@ MODULE_LICENSE("GPL"); static int onfi_timing_mode = NAND_DEFAULT_TIMINGS; module_param(onfi_timing_mode, int, S_IRUGO); -MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting." - " -1 indicates use default timings"); +MODULE_PARM_DESC(onfi_timing_mode, + "Overrides default ONFI setting. -1 indicates use default timings"); #define DENALI_NAND_NAME "denali-nand" @@ -162,8 +162,7 @@ static void read_status(struct denali_nand_info *denali) static void reset_bank(struct denali_nand_info *denali) { uint32_t irq_status; - uint32_t irq_mask = INTR_STATUS__RST_COMP | - INTR_STATUS__TIME_OUT; + uint32_t irq_mask = INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT; clear_interrupts(denali); @@ -181,16 +180,15 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) int i; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); - for (i = 0 ; i < denali->max_banks; i++) + for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, denali->flash_reg + INTR_STATUS(i)); - for (i = 0 ; i < denali->max_banks; i++) { + for (i = 0; i < denali->max_banks; i++) { iowrite32(1 << i, denali->flash_reg + DEVICE_RESET); - while (!(ioread32(denali->flash_reg + - INTR_STATUS(i)) & + while (!(ioread32(denali->flash_reg + INTR_STATUS(i)) & (INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT))) cpu_relax(); if (ioread32(denali->flash_reg + INTR_STATUS(i)) & @@ -201,7 +199,7 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, - denali->flash_reg + INTR_STATUS(i)); + denali->flash_reg + INTR_STATUS(i)); return PASS; } @@ -235,7 +233,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); en_lo = CEIL_DIV(Trp[mode], CLK_X); en_hi = CEIL_DIV(Treh[mode], CLK_X); @@ -255,9 +253,8 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, data_invalid_rloh = (en_lo + en_hi) * CLK_X + Trloh[mode]; - data_invalid = - data_invalid_rhoh < - data_invalid_rloh ? data_invalid_rhoh : data_invalid_rloh; + data_invalid = data_invalid_rhoh < data_invalid_rloh ? + data_invalid_rhoh : data_invalid_rloh; dv_window = data_invalid - Trea[mode]; @@ -272,7 +269,7 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, if (data_invalid - acc_clks * CLK_X < 2) dev_warn(denali->dev, "%s, Line %d: Warning!\n", - __FILE__, __LINE__); + __FILE__, __LINE__); addr_2_data = CEIL_DIV(Tadl[mode], CLK_X); re_2_we = CEIL_DIV(Trhw[mode], CLK_X); @@ -406,9 +403,9 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, break; default: dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x)." - "Will use default parameter values instead.\n", - device_id); + "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" + "Will use default parameter values instead.\n", + device_id); } } @@ -425,8 +422,7 @@ static void find_valid_banks(struct denali_nand_info *denali) for (i = 0; i < denali->max_banks; i++) { index_addr(denali, MODE_11 | (i << 24) | 0, 0x90); index_addr(denali, MODE_11 | (i << 24) | 1, 0); - index_addr_read_data(denali, - MODE_11 | (i << 24) | 2, &id[i]); + index_addr_read_data(denali, MODE_11 | (i << 24) | 2, &id[i]); dev_dbg(denali->dev, "Return 1st ID for bank[%d]: %x\n", i, id[i]); @@ -450,8 +446,7 @@ static void find_valid_banks(struct denali_nand_info *denali) */ if (denali->total_used_banks != 1) { dev_err(denali->dev, - "Sorry, Intel CE4100 only supports " - "a single NAND device.\n"); + "Sorry, Intel CE4100 only supports a single NAND device.\n"); BUG(); } } @@ -489,10 +484,12 @@ static void detect_partition_feature(struct denali_nand_info *denali) + (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & MIN_BLK_ADDR__VALUE); - } else + } else { denali->fwblks = SPECTRA_START_BLOCK; - } else + } + } else { denali->fwblks = SPECTRA_START_BLOCK; + } } static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) @@ -502,8 +499,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) uint8_t maf_id, device_id; int i; - dev_dbg(denali->dev, - "%s, Line %d, Function: %s\n", + dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", __FILE__, __LINE__, __func__); /* @@ -532,7 +528,7 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) } dev_info(denali->dev, - "Dump timing register values:" + "Dump timing register values:\n" "acc_clks: %d, re_2_we: %d, re_2_re: %d\n" "we_2_re: %d, addr_2_data: %d, rdwr_en_lo_cnt: %d\n" "rdwr_en_hi_cnt: %d, cs_setup_cnt: %d\n", @@ -563,7 +559,7 @@ static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); + __FILE__, __LINE__, __func__); if (INT_ENABLE) iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); @@ -710,13 +706,13 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) spin_unlock_irq(&denali->irq_lock); /* our interrupt was detected */ break; - } else { - /* - * these are not the interrupts you are looking for - - * need to wait again - */ - spin_unlock_irq(&denali->irq_lock); } + + /* + * these are not the interrupts you are looking for - + * need to wait again + */ + spin_unlock_irq(&denali->irq_lock); } while (comp_res != 0); if (comp_res == 0) { @@ -744,8 +740,7 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, /* Enable spare area/ECC per user's request. */ iowrite32(ecc_en_flag, denali->flash_reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, - denali->flash_reg + TRANSFER_SPARE_REG); + iowrite32(transfer_spare_flag, denali->flash_reg + TRANSFER_SPARE_REG); } /* @@ -753,10 +748,8 @@ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, * controller's user guide for more information (section 4.2.3.6). */ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, - bool ecc_en, - bool transfer_spare, - int access_type, - int op) + bool ecc_en, bool transfer_spare, + int access_type, int op) { int status = PASS; uint32_t page_count = 1; @@ -811,9 +804,8 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, if (irq_status == 0) { dev_err(denali->dev, - "cmd, page, addr on timeout " - "(0x%x, 0x%x, 0x%x)\n", - cmd, denali->page, addr); + "cmd, page, addr on timeout (0x%x, 0x%x, 0x%x)\n", + cmd, denali->page, addr); status = FAIL; } else { cmd = MODE_01 | addr; @@ -826,8 +818,7 @@ static int denali_send_pipeline_cmd(struct denali_nand_info *denali, /* helper function that simply writes a buffer to the flash */ static int write_data_to_flash_mem(struct denali_nand_info *denali, - const uint8_t *buf, - int len) + const uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -842,13 +833,12 @@ static int write_data_to_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) iowrite32(*buf32++, denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* helper function that simply reads a buffer from the flash */ static int read_data_from_flash_mem(struct denali_nand_info *denali, - uint8_t *buf, - int len) + uint8_t *buf, int len) { uint32_t *buf32; int i; @@ -865,7 +855,7 @@ static int read_data_from_flash_mem(struct denali_nand_info *denali, buf32 = (uint32_t *)buf; for (i = 0; i < len / 4; i++) *buf32++ = ioread32(denali->flash_mem + 0x10); - return i*4; /* intent is to return the number of bytes read */ + return i * 4; /* intent is to return the number of bytes read */ } /* writes OOB data to the device */ @@ -941,6 +931,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) static bool is_erased(uint8_t *buf, int len) { int i; + for (i = 0; i < len; i++) if (buf[i] != 0xFF) return false; @@ -990,6 +981,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, */ if (err_byte < ECC_SECTOR_SIZE) { int offset; + offset = (err_sector * ECC_SECTOR_SIZE + err_byte) * @@ -1063,10 +1055,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, bool raw_xfer) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_status; uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP | INTR_STATUS__PROGRAM_FAIL; @@ -1099,9 +1089,8 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip, irq_status = wait_for_irq(denali, irq_mask); if (irq_status == 0) { - dev_err(denali->dev, - "timeout on write_page (type = %d)\n", - raw_xfer); + dev_err(denali->dev, "timeout on write_page (type = %d)\n", + raw_xfer); denali->status = NAND_STATUS_FAIL; } @@ -1172,9 +1161,9 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, bool check_erased_page = false; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1214,16 +1203,14 @@ static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; - uint32_t irq_mask = INTR_STATUS__DMA_CMD_COMP; if (page != denali->page) { - dev_err(denali->dev, "IN %s: page %d is not" - " equal to denali->page %d, investigate!!", - __func__, page, denali->page); + dev_err(denali->dev, + "IN %s: page %d is not equal to denali->page %d", + __func__, page, denali->page); BUG(); } @@ -1272,6 +1259,7 @@ static int denali_waitfunc(struct mtd_info *mtd, struct nand_chip *chip) { struct denali_nand_info *denali = mtd_to_denali(mtd); int status = denali->status; + denali->status = 0; return status; @@ -1321,9 +1309,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col, index_addr(denali, addr | 0, 0x90); index_addr(denali, addr | 1, 0); for (i = 0; i < 8; i++) { - index_addr_read_data(denali, - addr | 2, - &id); + index_addr_read_data(denali, addr | 2, &id); write_byte_to_buf(denali, id); } break; @@ -1348,8 +1334,8 @@ static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data, uint8_t *ecc_code) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_calculate called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n"); BUG(); return -EIO; } @@ -1358,8 +1344,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, uint8_t *read_ecc, uint8_t *calc_ecc) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_correct called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n"); BUG(); return -EIO; } @@ -1367,8 +1353,8 @@ static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data, static void denali_ecc_hwctl(struct mtd_info *mtd, int mode) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dev_err(denali->dev, - "denali_ecc_hwctl called unexpectedly\n"); + + dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n"); BUG(); } /* end NAND core entry points */ @@ -1596,8 +1582,7 @@ int denali_init(struct denali_nand_info *denali) } else if (denali->mtd.oobsize < (denali->bbtskipbytes + ECC_8BITS * (denali->mtd.writesize / ECC_SECTOR_SIZE))) { - pr_err("Your NAND chip OOB is not large enough to \ - contain 8bit ECC correction codes"); + pr_err("Your NAND chip OOB is not large enough to contain 8bit ECC correction codes"); goto failed_req_irq; } else { denali->nand.ecc.strength = 8; @@ -1621,8 +1606,7 @@ int denali_init(struct denali_nand_info *denali) * contained by each nand chip. blksperchip will help driver to * know how many blocks is taken by FW. */ - denali->totalblks = denali->mtd.size >> - denali->nand.phys_erase_shift; + denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift; denali->blksperchip = denali->totalblks / denali->nand.numchips; /* @@ -1669,7 +1653,7 @@ void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); dma_unmap_single(denali->dev, denali->buf.dma_buf, - denali->mtd.writesize + denali->mtd.oobsize, - DMA_BIDIRECTIONAL); + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); -- cgit v0.10.2 From ab95eac99c1714ede92800a9c33f4c96ce8d558c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 15 Sep 2014 21:56:17 -0700 Subject: MAINTAINERS: add l2-mtd.git, 'next' tree for MTD We've been semi-officially queueing patches here for a while, and it's in linux-next, so let's advertise it in MAINTAINERS. Signed-off-by: Brian Norris Acked-by: Artem Bityutskiy diff --git a/MAINTAINERS b/MAINTAINERS index 809ecd6..55a61f2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5898,6 +5898,7 @@ L: linux-mtd@lists.infradead.org W: http://www.linux-mtd.infradead.org/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ T: git git://git.infradead.org/linux-mtd.git +T: git git://git.infradead.org/l2-mtd.git S: Maintained F: drivers/mtd/ F: include/linux/mtd/ -- cgit v0.10.2 From 9b07a8d1ab85ccacaceb9f704c361119348aabab Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 17 Sep 2014 13:08:18 -0500 Subject: mtd: physmap_of: Fix ROM support via OF The "ROM" and unknown probe types within the obsolete "direct-mapped" probe function used the nonexistent "mtd_rom" probe instead of the intended "map_rom". Signed-off-by: Aaron Sierra Signed-off-by: Brian Norris diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 217c25d..63d82da 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -103,7 +103,7 @@ static struct mtd_info *obsolete_probe(struct platform_device *dev, if (strcmp(of_probe, "ROM") != 0) dev_warn(&dev->dev, "obsolete_probe: don't know probe " "type '%s', mapping as rom\n", of_probe); - return do_map_probe("mtd_rom", map); + return do_map_probe("map_rom", map); } } -- cgit v0.10.2 From e5bffb59cfbb3371ff00a165a5a48c1f3fdf125a Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 17 Sep 2014 13:08:28 -0500 Subject: mtd: physmap_of: Add non-obsolete map_rom probe Previously, the only way to map a NOR device as a simple ROM was to use the obsolete "direct-mapped" compatible binding (which further requires device_type = "nor" and probe-type = "NOR" properties). This patch adds an "mtd-rom" compatible binding to the "map_rom" probe type. Signed-off-by: Aaron Sierra Signed-off-by: Brian Norris diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index 61c5ec8..6b9f680 100644 --- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -4,8 +4,8 @@ Flash chips (Memory Technology Devices) are often used for solid state file systems on embedded devices. - compatible : should contain the specific model of mtd chip(s) - used, if known, followed by either "cfi-flash", "jedec-flash" - or "mtd-ram". + used, if known, followed by either "cfi-flash", "jedec-flash", + "mtd-ram" or "mtd-rom". - reg : Address range(s) of the mtd chip(s) It's possible to (optionally) define multiple "reg" tuples so that non-identical chips can be described in one node. diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 63d82da..c1d21cb 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -340,6 +340,10 @@ static struct of_device_id of_flash_match[] = { .data = (void *)"map_ram", }, { + .compatible = "mtd-rom", + .data = (void *)"map_rom", + }, + { .type = "rom", .compatible = "direct-mapped" }, -- cgit v0.10.2 From 57a94e24bc927f642f7f48ca1bf5476aa5be269d Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 22 Sep 2014 20:11:50 +0200 Subject: mtd: nand: support ONFI timing mode retrieval for non-ONFI NANDs Add an onfi_timing_mode_default field to nand_chip and nand_flash_dev in order to support NAND timings definition for non-ONFI NAND. NAND that support better timings mode than the default one have to define a new entry in the nand_ids table. The default timing mode should be deduced from timings description from the datasheet and the ONFI specification (www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf, chapter 4.15 "Timing Parameters"). You should choose the closest mode that fit the timings requirements of your NAND chip. Signed-off-by: Boris BREZILLON Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 801cad1..5b5c627 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3594,6 +3594,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, chip->options |= type->options; chip->ecc_strength_ds = NAND_ECC_STRENGTH(type); chip->ecc_step_ds = NAND_ECC_STEP(type); + chip->onfi_timing_mode_default = + type->onfi_timing_mode_default; *busw = type->options & NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8acb307..e4d451e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -587,6 +587,11 @@ struct nand_buffers { * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, * also from the datasheet. It is the recommended ECC step * size, if known; if unknown, set to zero. + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is + * either deduced from the datasheet if the NAND + * chip is not ONFI compliant or set to 0 if it is + * (an ONFI chip is always configured in mode 0 + * after a NAND reset) * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 @@ -671,6 +676,7 @@ struct nand_chip { uint8_t bits_per_cell; uint16_t ecc_strength_ds; uint16_t ecc_step_ds; + int onfi_timing_mode_default; int badblockpos; int badblockbits; @@ -773,6 +779,10 @@ struct nand_chip { * @ecc_step_ds in nand_chip{}, also from the datasheet. * For example, the "4bit ECC for each 512Byte" can be set with * NAND_ECC_INFO(4, 512). + * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND + * reset. Should be deduced from timings described + * in the datasheet. + * */ struct nand_flash_dev { char *name; @@ -793,6 +803,7 @@ struct nand_flash_dev { uint16_t strength_ds; uint16_t step_ds; } ecc; + int onfi_timing_mode_default; }; /** -- cgit v0.10.2 From 2a960cce03d1dbd3dba54e660c479f64674eb5e3 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 22 Sep 2014 16:25:11 +0200 Subject: mtd: nand: add Hynix's H27UCG8T2ATR-BC to nand_ids table Add the full description of the Hynix H27UCG8T2ATR-BC NAND chip in the nand_ids table so that we can later use the NAND ECC infos and ONFI timings mode in controller drivers. Signed-off-by: Boris BREZILLON Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 3d7c89f..fbde8910 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -46,6 +46,10 @@ struct nand_flash_dev nand_flash_ids[] = { {"SDTNRGAMA 64G 3.3V 8-bit", { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} }, SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, + {"H27UCG8T2ATR-BC 64G 3.3V 8-bit", + { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, + SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K), + 4 }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), -- cgit v0.10.2 From 93af53b8633c4cb474585158512182b21219d743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= Date: Sat, 20 Sep 2014 17:53:12 +0100 Subject: nand: omap2: Remove horrible ifdefs to fix module probe The current code abuses ifdefs to determine if the selected ECC scheme is supported by the running kernel. As a result the code is hard to read, and it also fails to load as a module. This commit removes all the ifdefs and instead introduces a function omap2_nand_ecc_check() to check if the ECC is supported by using IS_ENABLED(CONFIG_xxx). Since IS_ENABLED() is true when a config is =y or =m, this change fixes the module so it can be loaded with no issues. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index e1a9b31..f97a4ff 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -136,7 +136,6 @@ #define BADBLOCK_MARKER_LENGTH 2 -#ifdef CONFIG_MTD_NAND_OMAP_BCH static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, 0x2e, 0x2c, 0x86, 0xa3, 0xed, 0x36, 0x1b, 0x78, 0x48, 0x76, 0xa9, 0x3b, 0x97, 0xd1, 0x7a, 0x93, @@ -144,7 +143,6 @@ static u_char bch16_vector[] = {0xf5, 0x24, 0x1c, 0xd0, 0x61, 0xb3, 0xf1, 0x55, static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, 0xac, 0x6b, 0xff, 0x99, 0x7b}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; -#endif /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; @@ -1292,7 +1290,6 @@ static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * erased_sector_bitflips - count bit flips * @data: data sector buffer @@ -1593,33 +1590,71 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, /** * is_elm_present - checks for presence of ELM module by scanning DT nodes * @omap_nand_info: NAND device structure containing platform data - * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 */ -static int is_elm_present(struct omap_nand_info *info, - struct device_node *elm_node, enum bch_ecc bch_type) +static bool is_elm_present(struct omap_nand_info *info, + struct device_node *elm_node) { struct platform_device *pdev; - struct nand_ecc_ctrl *ecc = &info->nand.ecc; - int err; + /* check whether elm-id is passed via DT */ if (!elm_node) { pr_err("nand: error: ELM DT node not found\n"); - return -ENODEV; + return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { pr_err("nand: error: ELM device not found\n"); - return -ENODEV; + return false; } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - err = elm_config(info->elm_dev, bch_type, - (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + return true; +} - return err; +static bool omap2_nand_ecc_check(struct omap_nand_info *info, + struct omap_nand_platform_data *pdata) +{ + bool ecc_needs_bch, ecc_needs_omap_bch, ecc_needs_elm; + + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + ecc_needs_omap_bch = false; + ecc_needs_bch = true; + ecc_needs_elm = false; + break; + case OMAP_ECC_BCH4_CODE_HW: + case OMAP_ECC_BCH8_CODE_HW: + case OMAP_ECC_BCH16_CODE_HW: + ecc_needs_omap_bch = true; + ecc_needs_bch = false; + ecc_needs_elm = true; + break; + default: + ecc_needs_omap_bch = false; + ecc_needs_bch = false; + ecc_needs_elm = false; + break; + } + + if (ecc_needs_bch && !IS_ENABLED(CONFIG_MTD_NAND_ECC_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_ECC_BCH not enabled\n"); + return false; + } + if (ecc_needs_omap_bch && !IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH)) { + dev_err(&info->pdev->dev, + "CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); + return false; + } + if (ecc_needs_elm && !is_elm_present(info, pdata->elm_of_node)) { + dev_err(&info->pdev->dev, "ELM not available\n"); + return false; + } + + return true; } -#endif /* CONFIG_MTD_NAND_ECC_BCH */ static int omap_nand_probe(struct platform_device *pdev) { @@ -1797,6 +1832,11 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } + if (!omap2_nand_ecc_check(info, pdata)) { + err = -EINVAL; + goto return_error; + } + /* populate MTD interface based on ECC scheme */ ecclayout = &omap_oobinfo; switch (info->ecc_opt) { @@ -1829,7 +1869,6 @@ static int omap_nand_probe(struct platform_device *pdev) break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1861,14 +1900,8 @@ static int omap_nand_probe(struct platform_device *pdev) err = -EINVAL; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH4_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1890,21 +1923,15 @@ static int omap_nand_probe(struct platform_device *pdev) /* reserved marker already included in ecclayout->eccbytes */ ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; - /* This ECC scheme requires ELM H/W block */ - if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { - pr_err("nand: error: could not initialize ELM\n"); - err = -ENODEV; + + err = elm_config(info->elm_dev, BCH4_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: -#ifdef CONFIG_MTD_NAND_ECC_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1937,14 +1964,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH8_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1956,12 +1977,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); - if (err < 0) { - pr_err("nand: error: could not initialize ELM\n"); + + err = elm_config(info->elm_dev, BCH8_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1973,14 +1995,8 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif case OMAP_ECC_BCH16_CODE_HW: -#ifdef CONFIG_MTD_NAND_OMAP_BCH pr_info("using OMAP_ECC_BCH16_CODE_HW ECC scheme\n"); nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.size = 512; @@ -1991,12 +2007,13 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; - /* This ECC scheme requires ELM H/W block */ - err = is_elm_present(info, pdata->elm_of_node, BCH16_ECC); - if (err < 0) { - pr_err("ELM is required for this ECC scheme\n"); + + err = elm_config(info->elm_dev, BCH16_ECC, + info->mtd.writesize / nand_chip->ecc.size, + nand_chip->ecc.size, nand_chip->ecc.bytes); + if (err < 0) goto return_error; - } + /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -2008,11 +2025,6 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->offset = ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; -#else - pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); - err = -EINVAL; - goto return_error; -#endif default: pr_err("nand: error: invalid or unsupported ECC scheme\n"); err = -EINVAL; diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h index 780d1e9..b8686c0 100644 --- a/include/linux/platform_data/elm.h +++ b/include/linux/platform_data/elm.h @@ -42,8 +42,24 @@ struct elm_errorvec { int error_loc[16]; }; +#if IS_ENABLED(CONFIG_MTD_NAND_OMAP_BCH) void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, struct elm_errorvec *err_vec); int elm_config(struct device *dev, enum bch_ecc bch_type, int ecc_steps, int ecc_step_size, int ecc_syndrome_size); +#else +static inline void +elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ +} + +static inline int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, + int ecc_syndrome_size) +{ + return -ENOSYS; +} +#endif /* CONFIG_MTD_NAND_ECC_BCH */ + #endif /* __ELM_H */ -- cgit v0.10.2 From d2f08c7521cd67bc5f3c990af87add7b02f46ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= Date: Sat, 20 Sep 2014 17:53:13 +0100 Subject: nand: omap2: Replace pr_err with dev_err Usage of pr_err is frowned upon, so replace it with dev_err. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f97a4ff..3b357e9 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1375,7 +1375,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, erased_ecc_vec = bch16_vector; break; default: - pr_err("invalid driver configuration\n"); + dev_err(&info->pdev->dev, "invalid driver configuration\n"); return -EINVAL; } @@ -1446,7 +1446,8 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, err = 0; for (i = 0; i < eccsteps; i++) { if (err_vec[i].error_uncorrectable) { - pr_err("nand: uncorrectable bit-flips found\n"); + dev_err(&info->pdev->dev, + "uncorrectable bit-flips found\n"); err = -EBADMSG; } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { @@ -1483,8 +1484,9 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, 1 << bit_pos; } } else { - pr_err("invalid bit-flip @ %d:%d\n", - byte_pos, bit_pos); + dev_err(&info->pdev->dev, + "invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); err = -EBADMSG; } } @@ -1598,13 +1600,13 @@ static bool is_elm_present(struct omap_nand_info *info, /* check whether elm-id is passed via DT */ if (!elm_node) { - pr_err("nand: error: ELM DT node not found\n"); + dev_err(&info->pdev->dev, "ELM devicetree node not found\n"); return false; } pdev = of_find_device_by_node(elm_node); /* check whether ELM device is registered */ if (!pdev) { - pr_err("nand: error: ELM device not found\n"); + dev_err(&info->pdev->dev, "ELM device not found\n"); return false; } /* ELM module available, now configure it */ @@ -1734,14 +1736,14 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; if (nand_scan_ident(mtd, 1, NULL)) { - pr_err("nand device scan failed, may be bus-width mismatch\n"); + dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); err = -ENXIO; goto return_error; } /* check for small page devices */ if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { - pr_err("small page devices are not supported\n"); + dev_err(&info->pdev->dev, "small page devices are not supported\n"); err = -EINVAL; goto return_error; } @@ -1896,8 +1898,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; + goto return_error; } break; @@ -1959,7 +1962,7 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.bytes, &ecclayout); if (!nand_chip->ecc.priv) { - pr_err("nand: error: unable to use s/w BCH library\n"); + dev_err(&info->pdev->dev, "unable to use BCH library\n"); err = -EINVAL; goto return_error; } @@ -2026,7 +2029,7 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; default: - pr_err("nand: error: invalid or unsupported ECC scheme\n"); + dev_err(&info->pdev->dev, "invalid or unsupported ECC scheme\n"); err = -EINVAL; goto return_error; } @@ -2038,8 +2041,9 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { - pr_err("not enough OOB bytes required = %d, available=%d\n", - ecclayout->eccbytes, mtd->oobsize); + dev_err(&info->pdev->dev, + "not enough OOB bytes required = %d, available=%d\n", + ecclayout->eccbytes, mtd->oobsize); err = -EINVAL; goto return_error; } -- cgit v0.10.2 From 6d178ef2fd5e4a7f601874a6e641090e706da3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ezequiel=20Garc=C3=ADa?= Date: Sat, 20 Sep 2014 17:53:14 +0100 Subject: mtd: nand: Move ELM driver and rename as omap_elm The ELM driver is only used by the OMAP NAND driver, so let's move it to the nand/ directory. Additionally, let's rename it to a less confusing name, so the module is built with a meaningful name, instead of the previous 'elm.ko'. Acked-by: Roger Quadros Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index c68868f..f0b0e61 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += elm.o obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o obj-$(CONFIG_MTD_SST25L) += sst25l.o obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c deleted file mode 100644 index b4f61c7..0000000 --- a/drivers/mtd/devices/elm.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Error Location Module - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define DRIVER_NAME "omap-elm" - -#include -#include -#include -#include -#include -#include -#include -#include - -#define ELM_SYSCONFIG 0x010 -#define ELM_IRQSTATUS 0x018 -#define ELM_IRQENABLE 0x01c -#define ELM_LOCATION_CONFIG 0x020 -#define ELM_PAGE_CTRL 0x080 -#define ELM_SYNDROME_FRAGMENT_0 0x400 -#define ELM_SYNDROME_FRAGMENT_1 0x404 -#define ELM_SYNDROME_FRAGMENT_2 0x408 -#define ELM_SYNDROME_FRAGMENT_3 0x40c -#define ELM_SYNDROME_FRAGMENT_4 0x410 -#define ELM_SYNDROME_FRAGMENT_5 0x414 -#define ELM_SYNDROME_FRAGMENT_6 0x418 -#define ELM_LOCATION_STATUS 0x800 -#define ELM_ERROR_LOCATION_0 0x880 - -/* ELM Interrupt Status Register */ -#define INTR_STATUS_PAGE_VALID BIT(8) - -/* ELM Interrupt Enable Register */ -#define INTR_EN_PAGE_MASK BIT(8) - -/* ELM Location Configuration Register */ -#define ECC_BCH_LEVEL_MASK 0x3 - -/* ELM syndrome */ -#define ELM_SYNDROME_VALID BIT(16) - -/* ELM_LOCATION_STATUS Register */ -#define ECC_CORRECTABLE_MASK BIT(8) -#define ECC_NB_ERRORS_MASK 0x1f - -/* ELM_ERROR_LOCATION_0-15 Registers */ -#define ECC_ERROR_LOCATION_MASK 0x1fff - -#define ELM_ECC_SIZE 0x7ff - -#define SYNDROME_FRAGMENT_REG_SIZE 0x40 -#define ERROR_LOCATION_SIZE 0x100 - -struct elm_registers { - u32 elm_irqenable; - u32 elm_sysconfig; - u32 elm_location_config; - u32 elm_page_ctrl; - u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX]; - u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX]; -}; - -struct elm_info { - struct device *dev; - void __iomem *elm_base; - struct completion elm_completion; - struct list_head list; - enum bch_ecc bch_type; - struct elm_registers elm_regs; - int ecc_steps; - int ecc_syndrome_size; -}; - -static LIST_HEAD(elm_devices); - -static void elm_write_reg(struct elm_info *info, int offset, u32 val) -{ - writel(val, info->elm_base + offset); -} - -static u32 elm_read_reg(struct elm_info *info, int offset) -{ - return readl(info->elm_base + offset); -} - -/** - * elm_config - Configure ELM module - * @dev: ELM device - * @bch_type: Type of BCH ecc - */ -int elm_config(struct device *dev, enum bch_ecc bch_type, - int ecc_steps, int ecc_step_size, int ecc_syndrome_size) -{ - u32 reg_val; - struct elm_info *info = dev_get_drvdata(dev); - - if (!info) { - dev_err(dev, "Unable to configure elm - device not probed?\n"); - return -ENODEV; - } - /* ELM cannot detect ECC errors for chunks > 1KB */ - if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) { - dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size); - return -EINVAL; - } - /* ELM support 8 error syndrome process */ - if (ecc_steps > ERROR_VECTOR_MAX) { - dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps); - return -EINVAL; - } - - reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); - elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); - info->bch_type = bch_type; - info->ecc_steps = ecc_steps; - info->ecc_syndrome_size = ecc_syndrome_size; - - return 0; -} -EXPORT_SYMBOL(elm_config); - -/** - * elm_configure_page_mode - Enable/Disable page mode - * @info: elm info - * @index: index number of syndrome fragment vector - * @enable: enable/disable flag for page mode - * - * Enable page mode for syndrome fragment index - */ -static void elm_configure_page_mode(struct elm_info *info, int index, - bool enable) -{ - u32 reg_val; - - reg_val = elm_read_reg(info, ELM_PAGE_CTRL); - if (enable) - reg_val |= BIT(index); /* enable page mode */ - else - reg_val &= ~BIT(index); /* disable page mode */ - - elm_write_reg(info, ELM_PAGE_CTRL, reg_val); -} - -/** - * elm_load_syndrome - Load ELM syndrome reg - * @info: elm info - * @err_vec: elm error vectors - * @ecc: buffer with calculated ecc - * - * Load syndrome fragment registers with calculated ecc in reverse order. - */ -static void elm_load_syndrome(struct elm_info *info, - struct elm_errorvec *err_vec, u8 *ecc) -{ - int i, offset; - u32 val; - - for (i = 0; i < info->ecc_steps; i++) { - - /* Check error reported */ - if (err_vec[i].error_reported) { - elm_configure_page_mode(info, i, true); - offset = ELM_SYNDROME_FRAGMENT_0 + - SYNDROME_FRAGMENT_REG_SIZE * i; - switch (info->bch_type) { - case BCH8_ECC: - /* syndrome fragment 0 = ecc[9-12B] */ - val = cpu_to_be32(*(u32 *) &ecc[9]); - elm_write_reg(info, offset, val); - - /* syndrome fragment 1 = ecc[5-8B] */ - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[5]); - elm_write_reg(info, offset, val); - - /* syndrome fragment 2 = ecc[1-4B] */ - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[1]); - elm_write_reg(info, offset, val); - - /* syndrome fragment 3 = ecc[0B] */ - offset += 4; - val = ecc[0]; - elm_write_reg(info, offset, val); - break; - case BCH4_ECC: - /* syndrome fragment 0 = ecc[20-52b] bits */ - val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) | - ((ecc[2] & 0xf) << 28); - elm_write_reg(info, offset, val); - - /* syndrome fragment 1 = ecc[0-20b] bits */ - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12; - elm_write_reg(info, offset, val); - break; - case BCH16_ECC: - val = cpu_to_be32(*(u32 *) &ecc[22]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[18]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[14]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[10]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[6]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[2]); - elm_write_reg(info, offset, val); - offset += 4; - val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16; - elm_write_reg(info, offset, val); - break; - default: - pr_err("invalid config bch_type\n"); - } - } - - /* Update ecc pointer with ecc byte size */ - ecc += info->ecc_syndrome_size; - } -} - -/** - * elm_start_processing - start elm syndrome processing - * @info: elm info - * @err_vec: elm error vectors - * - * Set syndrome valid bit for syndrome fragment registers for which - * elm syndrome fragment registers are loaded. This enables elm module - * to start processing syndrome vectors. - */ -static void elm_start_processing(struct elm_info *info, - struct elm_errorvec *err_vec) -{ - int i, offset; - u32 reg_val; - - /* - * Set syndrome vector valid, so that ELM module - * will process it for vectors error is reported - */ - for (i = 0; i < info->ecc_steps; i++) { - if (err_vec[i].error_reported) { - offset = ELM_SYNDROME_FRAGMENT_6 + - SYNDROME_FRAGMENT_REG_SIZE * i; - reg_val = elm_read_reg(info, offset); - reg_val |= ELM_SYNDROME_VALID; - elm_write_reg(info, offset, reg_val); - } - } -} - -/** - * elm_error_correction - locate correctable error position - * @info: elm info - * @err_vec: elm error vectors - * - * On completion of processing by elm module, error location status - * register updated with correctable/uncorrectable error information. - * In case of correctable errors, number of errors located from - * elm location status register & read the positions from - * elm error location register. - */ -static void elm_error_correction(struct elm_info *info, - struct elm_errorvec *err_vec) -{ - int i, j, errors = 0; - int offset; - u32 reg_val; - - for (i = 0; i < info->ecc_steps; i++) { - - /* Check error reported */ - if (err_vec[i].error_reported) { - offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i; - reg_val = elm_read_reg(info, offset); - - /* Check correctable error or not */ - if (reg_val & ECC_CORRECTABLE_MASK) { - offset = ELM_ERROR_LOCATION_0 + - ERROR_LOCATION_SIZE * i; - - /* Read count of correctable errors */ - err_vec[i].error_count = reg_val & - ECC_NB_ERRORS_MASK; - - /* Update the error locations in error vector */ - for (j = 0; j < err_vec[i].error_count; j++) { - - reg_val = elm_read_reg(info, offset); - err_vec[i].error_loc[j] = reg_val & - ECC_ERROR_LOCATION_MASK; - - /* Update error location register */ - offset += 4; - } - - errors += err_vec[i].error_count; - } else { - err_vec[i].error_uncorrectable = true; - } - - /* Clearing interrupts for processed error vectors */ - elm_write_reg(info, ELM_IRQSTATUS, BIT(i)); - - /* Disable page mode */ - elm_configure_page_mode(info, i, false); - } - } -} - -/** - * elm_decode_bch_error_page - Locate error position - * @dev: device pointer - * @ecc_calc: calculated ECC bytes from GPMC - * @err_vec: elm error vectors - * - * Called with one or more error reported vectors & vectors with - * error reported is updated in err_vec[].error_reported - */ -void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, - struct elm_errorvec *err_vec) -{ - struct elm_info *info = dev_get_drvdata(dev); - u32 reg_val; - - /* Enable page mode interrupt */ - reg_val = elm_read_reg(info, ELM_IRQSTATUS); - elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID); - elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK); - - /* Load valid ecc byte to syndrome fragment register */ - elm_load_syndrome(info, err_vec, ecc_calc); - - /* Enable syndrome processing for which syndrome fragment is updated */ - elm_start_processing(info, err_vec); - - /* Wait for ELM module to finish locating error correction */ - wait_for_completion(&info->elm_completion); - - /* Disable page mode interrupt */ - reg_val = elm_read_reg(info, ELM_IRQENABLE); - elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK); - elm_error_correction(info, err_vec); -} -EXPORT_SYMBOL(elm_decode_bch_error_page); - -static irqreturn_t elm_isr(int this_irq, void *dev_id) -{ - u32 reg_val; - struct elm_info *info = dev_id; - - reg_val = elm_read_reg(info, ELM_IRQSTATUS); - - /* All error vectors processed */ - if (reg_val & INTR_STATUS_PAGE_VALID) { - elm_write_reg(info, ELM_IRQSTATUS, - reg_val & INTR_STATUS_PAGE_VALID); - complete(&info->elm_completion); - return IRQ_HANDLED; - } - - return IRQ_NONE; -} - -static int elm_probe(struct platform_device *pdev) -{ - int ret = 0; - struct resource *res, *irq; - struct elm_info *info; - - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->dev = &pdev->dev; - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "no irq resource defined\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->elm_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(info->elm_base)) - return PTR_ERR(info->elm_base); - - ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0, - pdev->name, info); - if (ret) { - dev_err(&pdev->dev, "failure requesting irq %i\n", irq->start); - return ret; - } - - pm_runtime_enable(&pdev->dev); - if (pm_runtime_get_sync(&pdev->dev) < 0) { - ret = -EINVAL; - pm_runtime_disable(&pdev->dev); - dev_err(&pdev->dev, "can't enable clock\n"); - return ret; - } - - init_completion(&info->elm_completion); - INIT_LIST_HEAD(&info->list); - list_add(&info->list, &elm_devices); - platform_set_drvdata(pdev, info); - return ret; -} - -static int elm_remove(struct platform_device *pdev) -{ - pm_runtime_put_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -/** - * elm_context_save - * saves ELM configurations to preserve them across Hardware powered-down - */ -static int elm_context_save(struct elm_info *info) -{ - struct elm_registers *regs = &info->elm_regs; - enum bch_ecc bch_type = info->bch_type; - u32 offset = 0, i; - - regs->elm_irqenable = elm_read_reg(info, ELM_IRQENABLE); - regs->elm_sysconfig = elm_read_reg(info, ELM_SYSCONFIG); - regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG); - regs->elm_page_ctrl = elm_read_reg(info, ELM_PAGE_CTRL); - for (i = 0; i < ERROR_VECTOR_MAX; i++) { - offset = i * SYNDROME_FRAGMENT_REG_SIZE; - switch (bch_type) { - case BCH16_ECC: - regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_6 + offset); - regs->elm_syndrome_fragment_5[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_5 + offset); - regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_4 + offset); - case BCH8_ECC: - regs->elm_syndrome_fragment_3[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_3 + offset); - regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_2 + offset); - case BCH4_ECC: - regs->elm_syndrome_fragment_1[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_1 + offset); - regs->elm_syndrome_fragment_0[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_0 + offset); - break; - default: - return -EINVAL; - } - /* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs - * to be saved for all BCH schemes*/ - regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, - ELM_SYNDROME_FRAGMENT_6 + offset); - } - return 0; -} - -/** - * elm_context_restore - * writes configurations saved duing power-down back into ELM registers - */ -static int elm_context_restore(struct elm_info *info) -{ - struct elm_registers *regs = &info->elm_regs; - enum bch_ecc bch_type = info->bch_type; - u32 offset = 0, i; - - elm_write_reg(info, ELM_IRQENABLE, regs->elm_irqenable); - elm_write_reg(info, ELM_SYSCONFIG, regs->elm_sysconfig); - elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config); - elm_write_reg(info, ELM_PAGE_CTRL, regs->elm_page_ctrl); - for (i = 0; i < ERROR_VECTOR_MAX; i++) { - offset = i * SYNDROME_FRAGMENT_REG_SIZE; - switch (bch_type) { - case BCH16_ECC: - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, - regs->elm_syndrome_fragment_6[i]); - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset, - regs->elm_syndrome_fragment_5[i]); - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, - regs->elm_syndrome_fragment_4[i]); - case BCH8_ECC: - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset, - regs->elm_syndrome_fragment_3[i]); - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, - regs->elm_syndrome_fragment_2[i]); - case BCH4_ECC: - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset, - regs->elm_syndrome_fragment_1[i]); - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset, - regs->elm_syndrome_fragment_0[i]); - break; - default: - return -EINVAL; - } - /* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */ - elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, - regs->elm_syndrome_fragment_6[i] & - ELM_SYNDROME_VALID); - } - return 0; -} - -static int elm_suspend(struct device *dev) -{ - struct elm_info *info = dev_get_drvdata(dev); - elm_context_save(info); - pm_runtime_put_sync(dev); - return 0; -} - -static int elm_resume(struct device *dev) -{ - struct elm_info *info = dev_get_drvdata(dev); - pm_runtime_get_sync(dev); - elm_context_restore(info); - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume); - -#ifdef CONFIG_OF -static const struct of_device_id elm_of_match[] = { - { .compatible = "ti,am3352-elm" }, - {}, -}; -MODULE_DEVICE_TABLE(of, elm_of_match); -#endif - -static struct platform_driver elm_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(elm_of_match), - .pm = &elm_pm_ops, - }, - .probe = elm_probe, - .remove = elm_remove, -}; - -module_platform_driver(elm_driver); - -MODULE_DESCRIPTION("ELM driver for BCH error correction"); -MODULE_AUTHOR("Texas Instruments"); -MODULE_ALIAS("platform: elm"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a035e7c..b3237b7 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c new file mode 100644 index 0000000..b4f61c7 --- /dev/null +++ b/drivers/mtd/nand/omap_elm.c @@ -0,0 +1,579 @@ +/* + * Error Location Module + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define DRIVER_NAME "omap-elm" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ELM_SYSCONFIG 0x010 +#define ELM_IRQSTATUS 0x018 +#define ELM_IRQENABLE 0x01c +#define ELM_LOCATION_CONFIG 0x020 +#define ELM_PAGE_CTRL 0x080 +#define ELM_SYNDROME_FRAGMENT_0 0x400 +#define ELM_SYNDROME_FRAGMENT_1 0x404 +#define ELM_SYNDROME_FRAGMENT_2 0x408 +#define ELM_SYNDROME_FRAGMENT_3 0x40c +#define ELM_SYNDROME_FRAGMENT_4 0x410 +#define ELM_SYNDROME_FRAGMENT_5 0x414 +#define ELM_SYNDROME_FRAGMENT_6 0x418 +#define ELM_LOCATION_STATUS 0x800 +#define ELM_ERROR_LOCATION_0 0x880 + +/* ELM Interrupt Status Register */ +#define INTR_STATUS_PAGE_VALID BIT(8) + +/* ELM Interrupt Enable Register */ +#define INTR_EN_PAGE_MASK BIT(8) + +/* ELM Location Configuration Register */ +#define ECC_BCH_LEVEL_MASK 0x3 + +/* ELM syndrome */ +#define ELM_SYNDROME_VALID BIT(16) + +/* ELM_LOCATION_STATUS Register */ +#define ECC_CORRECTABLE_MASK BIT(8) +#define ECC_NB_ERRORS_MASK 0x1f + +/* ELM_ERROR_LOCATION_0-15 Registers */ +#define ECC_ERROR_LOCATION_MASK 0x1fff + +#define ELM_ECC_SIZE 0x7ff + +#define SYNDROME_FRAGMENT_REG_SIZE 0x40 +#define ERROR_LOCATION_SIZE 0x100 + +struct elm_registers { + u32 elm_irqenable; + u32 elm_sysconfig; + u32 elm_location_config; + u32 elm_page_ctrl; + u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX]; + u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX]; +}; + +struct elm_info { + struct device *dev; + void __iomem *elm_base; + struct completion elm_completion; + struct list_head list; + enum bch_ecc bch_type; + struct elm_registers elm_regs; + int ecc_steps; + int ecc_syndrome_size; +}; + +static LIST_HEAD(elm_devices); + +static void elm_write_reg(struct elm_info *info, int offset, u32 val) +{ + writel(val, info->elm_base + offset); +} + +static u32 elm_read_reg(struct elm_info *info, int offset) +{ + return readl(info->elm_base + offset); +} + +/** + * elm_config - Configure ELM module + * @dev: ELM device + * @bch_type: Type of BCH ecc + */ +int elm_config(struct device *dev, enum bch_ecc bch_type, + int ecc_steps, int ecc_step_size, int ecc_syndrome_size) +{ + u32 reg_val; + struct elm_info *info = dev_get_drvdata(dev); + + if (!info) { + dev_err(dev, "Unable to configure elm - device not probed?\n"); + return -ENODEV; + } + /* ELM cannot detect ECC errors for chunks > 1KB */ + if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) { + dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size); + return -EINVAL; + } + /* ELM support 8 error syndrome process */ + if (ecc_steps > ERROR_VECTOR_MAX) { + dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps); + return -EINVAL; + } + + reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16); + elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val); + info->bch_type = bch_type; + info->ecc_steps = ecc_steps; + info->ecc_syndrome_size = ecc_syndrome_size; + + return 0; +} +EXPORT_SYMBOL(elm_config); + +/** + * elm_configure_page_mode - Enable/Disable page mode + * @info: elm info + * @index: index number of syndrome fragment vector + * @enable: enable/disable flag for page mode + * + * Enable page mode for syndrome fragment index + */ +static void elm_configure_page_mode(struct elm_info *info, int index, + bool enable) +{ + u32 reg_val; + + reg_val = elm_read_reg(info, ELM_PAGE_CTRL); + if (enable) + reg_val |= BIT(index); /* enable page mode */ + else + reg_val &= ~BIT(index); /* disable page mode */ + + elm_write_reg(info, ELM_PAGE_CTRL, reg_val); +} + +/** + * elm_load_syndrome - Load ELM syndrome reg + * @info: elm info + * @err_vec: elm error vectors + * @ecc: buffer with calculated ecc + * + * Load syndrome fragment registers with calculated ecc in reverse order. + */ +static void elm_load_syndrome(struct elm_info *info, + struct elm_errorvec *err_vec, u8 *ecc) +{ + int i, offset; + u32 val; + + for (i = 0; i < info->ecc_steps; i++) { + + /* Check error reported */ + if (err_vec[i].error_reported) { + elm_configure_page_mode(info, i, true); + offset = ELM_SYNDROME_FRAGMENT_0 + + SYNDROME_FRAGMENT_REG_SIZE * i; + switch (info->bch_type) { + case BCH8_ECC: + /* syndrome fragment 0 = ecc[9-12B] */ + val = cpu_to_be32(*(u32 *) &ecc[9]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 1 = ecc[5-8B] */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[5]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 2 = ecc[1-4B] */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[1]); + elm_write_reg(info, offset, val); + + /* syndrome fragment 3 = ecc[0B] */ + offset += 4; + val = ecc[0]; + elm_write_reg(info, offset, val); + break; + case BCH4_ECC: + /* syndrome fragment 0 = ecc[20-52b] bits */ + val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) | + ((ecc[2] & 0xf) << 28); + elm_write_reg(info, offset, val); + + /* syndrome fragment 1 = ecc[0-20b] bits */ + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12; + elm_write_reg(info, offset, val); + break; + case BCH16_ECC: + val = cpu_to_be32(*(u32 *) &ecc[22]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[18]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[14]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[10]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[6]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[2]); + elm_write_reg(info, offset, val); + offset += 4; + val = cpu_to_be32(*(u32 *) &ecc[0]) >> 16; + elm_write_reg(info, offset, val); + break; + default: + pr_err("invalid config bch_type\n"); + } + } + + /* Update ecc pointer with ecc byte size */ + ecc += info->ecc_syndrome_size; + } +} + +/** + * elm_start_processing - start elm syndrome processing + * @info: elm info + * @err_vec: elm error vectors + * + * Set syndrome valid bit for syndrome fragment registers for which + * elm syndrome fragment registers are loaded. This enables elm module + * to start processing syndrome vectors. + */ +static void elm_start_processing(struct elm_info *info, + struct elm_errorvec *err_vec) +{ + int i, offset; + u32 reg_val; + + /* + * Set syndrome vector valid, so that ELM module + * will process it for vectors error is reported + */ + for (i = 0; i < info->ecc_steps; i++) { + if (err_vec[i].error_reported) { + offset = ELM_SYNDROME_FRAGMENT_6 + + SYNDROME_FRAGMENT_REG_SIZE * i; + reg_val = elm_read_reg(info, offset); + reg_val |= ELM_SYNDROME_VALID; + elm_write_reg(info, offset, reg_val); + } + } +} + +/** + * elm_error_correction - locate correctable error position + * @info: elm info + * @err_vec: elm error vectors + * + * On completion of processing by elm module, error location status + * register updated with correctable/uncorrectable error information. + * In case of correctable errors, number of errors located from + * elm location status register & read the positions from + * elm error location register. + */ +static void elm_error_correction(struct elm_info *info, + struct elm_errorvec *err_vec) +{ + int i, j, errors = 0; + int offset; + u32 reg_val; + + for (i = 0; i < info->ecc_steps; i++) { + + /* Check error reported */ + if (err_vec[i].error_reported) { + offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i; + reg_val = elm_read_reg(info, offset); + + /* Check correctable error or not */ + if (reg_val & ECC_CORRECTABLE_MASK) { + offset = ELM_ERROR_LOCATION_0 + + ERROR_LOCATION_SIZE * i; + + /* Read count of correctable errors */ + err_vec[i].error_count = reg_val & + ECC_NB_ERRORS_MASK; + + /* Update the error locations in error vector */ + for (j = 0; j < err_vec[i].error_count; j++) { + + reg_val = elm_read_reg(info, offset); + err_vec[i].error_loc[j] = reg_val & + ECC_ERROR_LOCATION_MASK; + + /* Update error location register */ + offset += 4; + } + + errors += err_vec[i].error_count; + } else { + err_vec[i].error_uncorrectable = true; + } + + /* Clearing interrupts for processed error vectors */ + elm_write_reg(info, ELM_IRQSTATUS, BIT(i)); + + /* Disable page mode */ + elm_configure_page_mode(info, i, false); + } + } +} + +/** + * elm_decode_bch_error_page - Locate error position + * @dev: device pointer + * @ecc_calc: calculated ECC bytes from GPMC + * @err_vec: elm error vectors + * + * Called with one or more error reported vectors & vectors with + * error reported is updated in err_vec[].error_reported + */ +void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc, + struct elm_errorvec *err_vec) +{ + struct elm_info *info = dev_get_drvdata(dev); + u32 reg_val; + + /* Enable page mode interrupt */ + reg_val = elm_read_reg(info, ELM_IRQSTATUS); + elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID); + elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK); + + /* Load valid ecc byte to syndrome fragment register */ + elm_load_syndrome(info, err_vec, ecc_calc); + + /* Enable syndrome processing for which syndrome fragment is updated */ + elm_start_processing(info, err_vec); + + /* Wait for ELM module to finish locating error correction */ + wait_for_completion(&info->elm_completion); + + /* Disable page mode interrupt */ + reg_val = elm_read_reg(info, ELM_IRQENABLE); + elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK); + elm_error_correction(info, err_vec); +} +EXPORT_SYMBOL(elm_decode_bch_error_page); + +static irqreturn_t elm_isr(int this_irq, void *dev_id) +{ + u32 reg_val; + struct elm_info *info = dev_id; + + reg_val = elm_read_reg(info, ELM_IRQSTATUS); + + /* All error vectors processed */ + if (reg_val & INTR_STATUS_PAGE_VALID) { + elm_write_reg(info, ELM_IRQSTATUS, + reg_val & INTR_STATUS_PAGE_VALID); + complete(&info->elm_completion); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int elm_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res, *irq; + struct elm_info *info; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = &pdev->dev; + + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource defined\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->elm_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->elm_base)) + return PTR_ERR(info->elm_base); + + ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0, + pdev->name, info); + if (ret) { + dev_err(&pdev->dev, "failure requesting irq %i\n", irq->start); + return ret; + } + + pm_runtime_enable(&pdev->dev); + if (pm_runtime_get_sync(&pdev->dev) < 0) { + ret = -EINVAL; + pm_runtime_disable(&pdev->dev); + dev_err(&pdev->dev, "can't enable clock\n"); + return ret; + } + + init_completion(&info->elm_completion); + INIT_LIST_HEAD(&info->list); + list_add(&info->list, &elm_devices); + platform_set_drvdata(pdev, info); + return ret; +} + +static int elm_remove(struct platform_device *pdev) +{ + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/** + * elm_context_save + * saves ELM configurations to preserve them across Hardware powered-down + */ +static int elm_context_save(struct elm_info *info) +{ + struct elm_registers *regs = &info->elm_regs; + enum bch_ecc bch_type = info->bch_type; + u32 offset = 0, i; + + regs->elm_irqenable = elm_read_reg(info, ELM_IRQENABLE); + regs->elm_sysconfig = elm_read_reg(info, ELM_SYSCONFIG); + regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG); + regs->elm_page_ctrl = elm_read_reg(info, ELM_PAGE_CTRL); + for (i = 0; i < ERROR_VECTOR_MAX; i++) { + offset = i * SYNDROME_FRAGMENT_REG_SIZE; + switch (bch_type) { + case BCH16_ECC: + regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_6 + offset); + regs->elm_syndrome_fragment_5[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_5 + offset); + regs->elm_syndrome_fragment_4[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_4 + offset); + case BCH8_ECC: + regs->elm_syndrome_fragment_3[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_3 + offset); + regs->elm_syndrome_fragment_2[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_2 + offset); + case BCH4_ECC: + regs->elm_syndrome_fragment_1[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_1 + offset); + regs->elm_syndrome_fragment_0[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_0 + offset); + break; + default: + return -EINVAL; + } + /* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs + * to be saved for all BCH schemes*/ + regs->elm_syndrome_fragment_6[i] = elm_read_reg(info, + ELM_SYNDROME_FRAGMENT_6 + offset); + } + return 0; +} + +/** + * elm_context_restore + * writes configurations saved duing power-down back into ELM registers + */ +static int elm_context_restore(struct elm_info *info) +{ + struct elm_registers *regs = &info->elm_regs; + enum bch_ecc bch_type = info->bch_type; + u32 offset = 0, i; + + elm_write_reg(info, ELM_IRQENABLE, regs->elm_irqenable); + elm_write_reg(info, ELM_SYSCONFIG, regs->elm_sysconfig); + elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config); + elm_write_reg(info, ELM_PAGE_CTRL, regs->elm_page_ctrl); + for (i = 0; i < ERROR_VECTOR_MAX; i++) { + offset = i * SYNDROME_FRAGMENT_REG_SIZE; + switch (bch_type) { + case BCH16_ECC: + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, + regs->elm_syndrome_fragment_6[i]); + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_5 + offset, + regs->elm_syndrome_fragment_5[i]); + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_4 + offset, + regs->elm_syndrome_fragment_4[i]); + case BCH8_ECC: + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset, + regs->elm_syndrome_fragment_3[i]); + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset, + regs->elm_syndrome_fragment_2[i]); + case BCH4_ECC: + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset, + regs->elm_syndrome_fragment_1[i]); + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset, + regs->elm_syndrome_fragment_0[i]); + break; + default: + return -EINVAL; + } + /* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */ + elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset, + regs->elm_syndrome_fragment_6[i] & + ELM_SYNDROME_VALID); + } + return 0; +} + +static int elm_suspend(struct device *dev) +{ + struct elm_info *info = dev_get_drvdata(dev); + elm_context_save(info); + pm_runtime_put_sync(dev); + return 0; +} + +static int elm_resume(struct device *dev) +{ + struct elm_info *info = dev_get_drvdata(dev); + pm_runtime_get_sync(dev); + elm_context_restore(info); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume); + +#ifdef CONFIG_OF +static const struct of_device_id elm_of_match[] = { + { .compatible = "ti,am3352-elm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, elm_of_match); +#endif + +static struct platform_driver elm_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(elm_of_match), + .pm = &elm_pm_ops, + }, + .probe = elm_probe, + .remove = elm_remove, +}; + +module_platform_driver(elm_driver); + +MODULE_DESCRIPTION("ELM driver for BCH error correction"); +MODULE_AUTHOR("Texas Instruments"); +MODULE_ALIAS("platform: elm"); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 57cf26c1b28572976c57f6dec9818be38bf37cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 17 Aug 2014 11:27:26 +0200 Subject: mtd: spi-nor: add Kconfig option to disable 4K sectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current situation with 4K sectors is quite messy. First of all, some MTD "users" don't work with such small size. An example may be UBIFS which requires 15 KiB erase blocks as a minimum. In theory spi-nor should provide multiple erase regions and MTD "users" should use the one they need. Unforunately that is not implemented. In the result our flashes database in spi-nor is hackish. For some flashes we pretend they don't support 4K sectors just because some distribution uses UBIFS on it. This ofc leads to conflicts, like Samsung using w25q128 with 4K sectors vs. OpenWrt requiring it to pretend it's 64 KiB blocks only. My idea (plan?) for fixing this situation: 1) Use real hw info (this requires a way for disabling 4K for now) 2) Provide detailed info about erase regions 3) Make UBIFS work with devices that support 4K sectors Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index f8acfa4..64a4f0e 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -7,6 +7,20 @@ menuconfig MTD_SPI_NOR if MTD_SPI_NOR +config MTD_SPI_NOR_USE_4K_SECTORS + bool "Use small 4096 B erase sectors" + default y + help + Many flash memories support erasing small (4096 B) sectors. Depending + on the usage this feature may provide performance gain in comparison + to erasing whole blocks (32/64 KiB). + Changing a small part of the flash's contents is usually faster with + small sectors. On the other hand erasing should be faster when using + 64 KiB block instead of 16 × 4 KiB sectors. + + Please note that some tools/drivers/filesystems may not work with + 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). + config SPI_FSL_QUADSPI tristate "Freescale Quad SPI controller" depends on ARCH_MXC diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 03e0ab8..11459f6 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1013,6 +1013,7 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, nor->wait_till_ready == spi_nor_wait_till_ready) nor->wait_till_ready = spi_nor_wait_till_fsr_ready; +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { nor->erase_opcode = SPINOR_OP_BE_4K; @@ -1020,7 +1021,9 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, } else if (info->flags & SECT_4K_PMC) { nor->erase_opcode = SPINOR_OP_BE_4K_PMC; mtd->erasesize = 4096; - } else { + } else +#endif + { nor->erase_opcode = SPINOR_OP_SE; mtd->erasesize = info->sector_size; } -- cgit v0.10.2 From 32f1b7c8352fd33d41bcec3cfb054ccdcfd40a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 28 Sep 2014 22:36:54 +0200 Subject: mtd: move support for struct flash_platform_data into m25p80 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This "type" seems to be an extra hint for m25p80 about the flash. Some archs register flash_platform_data with "name" set to "m25p80" and then with a real flash name set in "type". It seems to be a trick specific to the m25p80 so let's move it out of spi-nor. Btw switch to the spi_nor_match_id instead of iterating spi_nor_ids. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index ed7e0a1b..dcda628 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -193,11 +193,14 @@ static int m25p_probe(struct spi_device *spi) { struct mtd_part_parser_data ppdata; struct flash_platform_data *data; + const struct spi_device_id *id = NULL; struct m25p *flash; struct spi_nor *nor; enum read_mode mode = SPI_NOR_NORMAL; int ret; + data = dev_get_platdata(&spi->dev); + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); if (!flash) return -ENOMEM; @@ -223,11 +226,26 @@ static int m25p_probe(struct spi_device *spi) mode = SPI_NOR_QUAD; else if (spi->mode & SPI_RX_DUAL) mode = SPI_NOR_DUAL; - ret = spi_nor_scan(nor, spi_get_device_id(spi), mode); + + if (data && data->name) + flash->mtd.name = data->name; + + /* For some (historical?) reason many platforms provide two different + * names in flash_platform_data: "name" and "type". Quite often name is + * set to "m25p80" and then "type" provides a real chip name. + * If that's the case, respect "type" and ignore a "name". + */ + if (data && data->type) + id = spi_nor_match_id(data->type); + + /* If we didn't get name from platform, simply use "modalias". */ + if (!id) + id = spi_get_device_id(spi); + + ret = spi_nor_scan(nor, id, mode); if (ret) return ret; - data = dev_get_platdata(&spi->dev); ppdata.of_node = spi->dev.of_node; return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 11459f6..ae16aa2 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -915,7 +915,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, enum read_mode mode) { struct flash_info *info; - struct flash_platform_data *data; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; struct device_node *np = dev->of_node; @@ -926,28 +925,6 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, if (ret) return ret; - /* Platform data helps sort out which chip type we have, as - * well as how this board partitions it. If we don't have - * a chip ID, try the JEDEC id commands; they'll work for most - * newer chips, even if we don't recognize the particular chip. - */ - data = dev_get_platdata(dev); - if (data && data->type) { - const struct spi_device_id *plat_id; - - for (i = 0; i < ARRAY_SIZE(spi_nor_ids) - 1; i++) { - plat_id = &spi_nor_ids[i]; - if (strcmp(data->type, plat_id->name)) - continue; - break; - } - - if (i < ARRAY_SIZE(spi_nor_ids) - 1) - id = plat_id; - else - dev_warn(dev, "unrecognized id %s\n", data->type); - } - info = (void *)id->driver_data; if (info->jedec_id) { @@ -985,11 +962,8 @@ int spi_nor_scan(struct spi_nor *nor, const struct spi_device_id *id, write_sr(nor, 0); } - if (data && data->name) - mtd->name = data->name; - else + if (!mtd->name) mtd->name = dev_name(dev); - mtd->type = MTD_NORFLASH; mtd->writesize = 1; mtd->flags = MTD_CAP_NORFLASH; -- cgit v0.10.2 From e7cd6824fd4105ff164aabc3767f195d1f6e4025 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 1 Oct 2014 14:33:29 +0300 Subject: mtd: nand: Force omap_elm to be built as a module if omap2_nand is a module This commit adds a hidden option to build the omap_elm as a module, if omap2_nand is a module (and similarly in the built-in case). This fixes the following build error when omap2_nand is chosen built-in, and omap_elm is chosen as a module: drivers/built-in.o: In function `omap_nand_probe': drivers/mtd/nand/omap2.c:2010: undefined reference to `elm_config' drivers/mtd/nand/omap2.c:1980: undefined reference to `elm_config' drivers/mtd/nand/omap2.c:1927: undefined reference to `elm_config' drivers/built-in.o: In function `omap_elm_correct_data': drivers/mtd/nand/omap2.c:1444: undefined reference to `elm_decode_bch_error_page' Reported-by: Arnd Bergmann Signed-off-by: Ezequiel Garcia Signed-off-by: Roger Quadros Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f1cf503..1cb4b1b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -96,7 +96,7 @@ config MTD_NAND_OMAP2 config MTD_NAND_OMAP_BCH depends on MTD_NAND_OMAP2 - tristate "Support hardware based BCH error correction" + bool "Support hardware based BCH error correction" default n select BCH help @@ -106,6 +106,9 @@ config MTD_NAND_OMAP_BCH legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine so they should not enable this config symbol. +config MTD_NAND_OMAP_BCH_BUILD + def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH + config MTD_NAND_IDS tristate diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b3237b7..9c847e4 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o -obj-$(CONFIG_MTD_NAND_OMAP_BCH) += omap_elm.o +obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o -- cgit v0.10.2 From 8b3d58e554453ab858bbb169d93b7321bdc628d4 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 1 Oct 2014 14:33:30 +0300 Subject: mtd: nand: omap: Correct CONFIG_MTD_NAND_OMAP_BCH help message The MTD_NAND_OMAP_BCH doesn't harm on legacy OMAP platforms so don't state that it should be disabled for them. Signed-off-by: Roger Quadros Signed-off-by: Brian Norris diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1cb4b1b..dd10646 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -104,7 +104,7 @@ config MTD_NAND_OMAP_BCH locate and correct errors when using BCH ECC scheme. This offloads the cpu from doing ECC error searching and correction. However some legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine - so they should not enable this config symbol. + so this is optional for them. config MTD_NAND_OMAP_BCH_BUILD def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH -- cgit v0.10.2