From 8552b439aba7f32063755d23f79ca27b4d0a3115 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 6 Nov 2013 20:05:34 +0530 Subject: drivers: mtd: m25p80: convert "bool" read check into an enum This is a cleanup prior to adding quad read support. This will facilitate easy addition of more read commands check under an enum rather that defining a separate bool for it. Signed-off-by: Sourav Poddar Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 71 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7eda71dbc183..04f8a245ffef 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -84,6 +84,11 @@ /****************************************************************************/ +enum read_type { + M25P80_NORMAL = 0, + M25P80_FAST, +}; + struct m25p { struct spi_device *spi; struct mutex lock; @@ -94,7 +99,7 @@ struct m25p { u8 read_opcode; u8 program_opcode; u8 *command; - bool fast_read; + enum read_type flash_read; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -349,6 +354,24 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) return 0; } +/* + * Dummy Cycle calculation for different type of read. + * It can be used to support more commands with + * different dummy cycle requirements. + */ +static inline int m25p80_dummy_cycles_read(struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_FAST: + return 1; + case M25P80_NORMAL: + return 0; + default: + dev_err(&flash->spi->dev, "No valid read type supported\n"); + return -1; + } +} + /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. @@ -360,6 +383,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; uint8_t opcode; + int dummy; pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, (u32)from, len); @@ -367,8 +391,14 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_message_init(&m); memset(t, 0, (sizeof t)); + dummy = m25p80_dummy_cycles_read(flash); + if (dummy < 0) { + dev_err(&flash->spi->dev, "No valid read command supported\n"); + return -EINVAL; + } + t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); + t[0].len = m25p_cmdsz(flash) + dummy; spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; @@ -391,8 +421,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_sync(flash->spi, &m); - *retlen = m.actual_length - m25p_cmdsz(flash) - - (flash->fast_read ? 1 : 0); + *retlen = m.actual_length - m25p_cmdsz(flash) - dummy; mutex_unlock(&flash->lock); @@ -1051,22 +1080,31 @@ static int m25p_probe(struct spi_device *spi) flash->page_size = info->page_size; flash->mtd.writebufsize = flash->page_size; - if (np) + if (np) { /* If we were instantiated by DT, use it */ - flash->fast_read = of_property_read_bool(np, "m25p,fast-read"); - else + if (of_property_read_bool(np, "m25p,fast-read")) + flash->flash_read = M25P80_FAST; + } else { /* If we weren't instantiated by DT, default to fast-read */ - flash->fast_read = true; + flash->flash_read = M25P80_FAST; + } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & M25P_NO_FR) - flash->fast_read = false; + flash->flash_read = M25P80_NORMAL; /* Default commands */ - if (flash->fast_read) + switch (flash->flash_read) { + case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ; - else + break; + case M25P80_NORMAL: flash->read_opcode = OPCODE_NORM_READ; + break; + default: + dev_err(&flash->spi->dev, "No Read opcode defined\n"); + return -EINVAL; + } flash->program_opcode = OPCODE_PP; @@ -1077,9 +1115,14 @@ static int m25p_probe(struct spi_device *spi) flash->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ - flash->read_opcode = flash->fast_read ? - OPCODE_FAST_READ_4B : - OPCODE_NORM_READ_4B; + switch (flash->flash_read) { + case M25P80_FAST: + flash->read_opcode = OPCODE_FAST_READ_4B; + break; + case M25P80_NORMAL: + flash->read_opcode = OPCODE_NORM_READ_4B; + break; + } flash->program_opcode = OPCODE_PP_4B; /* No small sector erase for 4-byte command set */ flash->erase_opcode = OPCODE_SE_4B; -- cgit v1.2.3 From 3487a63955c34ea508bcf4ca5131ddd953876e2d Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Wed, 6 Nov 2013 20:05:35 +0530 Subject: drivers: mtd: m25p80: add quad read support Some flash also support quad read mode. Adding support for quad read mode in m25p80 for Spansion and Macronix flash. [Tweaked by Brian] With this patch, quad-read support will override fast-read and normal-read, if the SPI controller and flash chip both support it. Signed-off-by: Sourav Poddar Tested-by: Sourav Poddar Reviewed-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 139 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 04f8a245ffef..7dc2c147720a 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -41,6 +41,7 @@ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ 0x6b /* Read data bytes */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ @@ -48,10 +49,12 @@ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ +#define OPCODE_RDCR 0x35 /* Read configuration register */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ @@ -76,6 +79,11 @@ #define SR_BP2 0x10 /* Block protect 2 */ #define SR_SRWD 0x80 /* SR write protect */ +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ + /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 @@ -87,6 +95,7 @@ enum read_type { M25P80_NORMAL = 0, M25P80_FAST, + M25P80_QUAD, }; struct m25p { @@ -135,6 +144,26 @@ static int read_sr(struct m25p *flash) return val; } +/* + * Read configuration register, returning its value in the + * location. Return the configuration register value. + * Returns negative if error occured. + */ +static int read_cr(struct m25p *flash) +{ + u8 code = OPCODE_RDCR; + int ret; + u8 val; + + ret = spi_write_then_read(flash->spi, &code, 1, &val, 1); + if (ret < 0) { + dev_err(&flash->spi->dev, "error %d reading CR\n", ret); + return ret; + } + + return val; +} + /* * Write status register 1 byte * Returns negative if error occurred. @@ -224,6 +253,93 @@ static int wait_till_ready(struct m25p *flash) return 1; } +/* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occured. + */ +static int write_sr_cr(struct m25p *flash, u16 val) +{ + flash->command[0] = OPCODE_WRSR; + flash->command[1] = val & 0xff; + flash->command[2] = (val >> 8); + + return spi_write(flash->spi, flash->command, 3); +} + +static int macronix_quad_enable(struct m25p *flash) +{ + int ret, val; + u8 cmd[2]; + cmd[0] = OPCODE_WRSR; + + val = read_sr(flash); + cmd[1] = val | SR_QUAD_EN_MX; + write_enable(flash); + + spi_write(flash->spi, &cmd, 2); + + if (wait_till_ready(flash)) + return 1; + + ret = read_sr(flash); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(&flash->spi->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int spansion_quad_enable(struct m25p *flash) +{ + int ret; + int quad_en = CR_QUAD_EN_SPAN << 8; + + write_enable(flash); + + ret = write_sr_cr(flash, quad_en); + if (ret < 0) { + dev_err(&flash->spi->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* read back and check it */ + ret = read_cr(flash); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(&flash->spi->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int set_quad_mode(struct m25p *flash, u32 jedec_id) +{ + int status; + + switch (JEDEC_MFR(jedec_id)) { + case CFI_MFR_MACRONIX: + status = macronix_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Macronix quad-read not enabled\n"); + return -EINVAL; + } + return status; + default: + status = spansion_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Spansion quad-read not enabled\n"); + return -EINVAL; + } + return status; + } +} + /* * Erase the whole flash memory * @@ -363,6 +479,7 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash) { switch (flash->flash_read) { case M25P80_FAST: + case M25P80_QUAD: return 1; case M25P80_NORMAL: return 0; @@ -727,6 +844,7 @@ struct flash_info { #define SST_WRITE 0x04 /* use SST byte programming */ #define M25P_NO_FR 0x08 /* Can't do fastread */ #define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ +#define M25P80_QUAD_READ 0x20 /* Flash supports Quad Read */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -804,7 +922,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) }, /* Micron */ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, @@ -824,7 +942,7 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, @@ -966,6 +1084,7 @@ static int m25p_probe(struct spi_device *spi) unsigned i; struct mtd_part_parser_data ppdata; struct device_node *np = spi->dev.of_node; + int ret; /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -1093,8 +1212,21 @@ static int m25p_probe(struct spi_device *spi) if (info->flags & M25P_NO_FR) flash->flash_read = M25P80_NORMAL; + /* Quad-read mode takes precedence over fast/normal */ + if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) { + ret = set_quad_mode(flash, info->jedec_id); + if (ret) { + dev_err(&flash->spi->dev, "quad mode not supported\n"); + return ret; + } + flash->flash_read = M25P80_QUAD; + } + /* Default commands */ switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ; + break; case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ; break; @@ -1116,6 +1248,9 @@ static int m25p_probe(struct spi_device *spi) if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ; + break; case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ_4B; break; -- cgit v1.2.3 From 43b77693be6d222561283adfcd06ec3813770ea4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 25 Oct 2013 07:17:55 -0300 Subject: mtd: nand: omap2: Fix OMAP_BCH option dependency This option does not need to depend in MTD_NAND, for it's enclosed under it. Also, it's wrong to make it depend in ARCH_OMAP3 only since the controller is used in a wider range of SoCs. Instead, just leave the dependency on the OMAP2 driver option. Signed-off-by: Ezequiel Garcia Acked-by: Pekon Gupta Signed-off-by: Brian Norris --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 93ae6a6d94f7..8dd72b420dd2 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -95,7 +95,7 @@ config MTD_NAND_OMAP2 platforms. config MTD_NAND_OMAP_BCH - depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3 + depends on MTD_NAND_OMAP2 tristate "Support hardware based BCH error correction" default n select BCH -- cgit v1.2.3 From 89b59e6cc15db8cea20a0c0aac18548bccfcb5f9 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 7 Nov 2013 18:07:38 +0800 Subject: mtd: gpmi: add a new DT property to use the datasheet's minimum required ECC In default way, we use the ecc_strength/ecc_step size calculated by ourselves and use all the OOB area. This patch adds a new property : "fsl,use-minimum-ecc" If we enable it, we will firstly try to use the datasheet's minimum required ECC provided by the MTD layer (the ecc_strength_ds/ecc_step_ds fields in the nand_chip{}). So we may have free space in the OOB area by using the minimum ECC, and we may support JFFS2 with some SLC NANDs, such as Micron's SLC NAND. If we fail to use the minimum ECC, we will use the legacy method to calculate the ecc_strength and ecc_step size. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/gpmi-nand.txt | 8 ++++++++ drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 3 +++ 2 files changed, 11 insertions(+) (limited to 'drivers/mtd') diff --git a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt index 551b2a179d01..458d59634688 100644 --- a/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpmi-nand.txt @@ -17,6 +17,14 @@ Required properties: Optional properties: - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC + strength required. The required ECC strength is + automatically discoverable for some flash + (e.g., according to the ONFI standard). + However, note that if this strength is not + discoverable or this property is not enabled, + the software may chooses an implementation-defined + ECC scheme. The device tree may optionally contain sub-nodes describing partitions of the address space. See partition.txt for more detail. diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index dabbc14db563..9c5911616a07 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -352,6 +352,9 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) int common_nfc_set_geometry(struct gpmi_nand_data *this) { + if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc") + && set_geometry_by_ecc_info(this)) + return 0; return legacy_set_geometry(this); } -- cgit v1.2.3 From 554cbc509f4ef95b0f06d04d94f0b0c2019dee26 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 7 Nov 2013 22:32:38 -0200 Subject: mtd: gpmi: Use devm_clk_get() Using devm_clk_get() can make the code smaller and cleaner. Signed-off-by: Fabio Estevam Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 9c5911616a07..739f131e572c 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -582,21 +582,6 @@ acquire_err: return -EINVAL; } -static void gpmi_put_clks(struct gpmi_nand_data *this) -{ - struct resources *r = &this->resources; - struct clk *clk; - int i; - - for (i = 0; i < GPMI_CLK_MAX; i++) { - clk = r->clock[i]; - if (clk) { - clk_put(clk); - r->clock[i] = NULL; - } - } -} - static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = { "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch", }; @@ -609,7 +594,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) int err, i; /* The main clock is stored in the first. */ - r->clock[0] = clk_get(this->dev, "gpmi_io"); + r->clock[0] = devm_clk_get(this->dev, "gpmi_io"); if (IS_ERR(r->clock[0])) { err = PTR_ERR(r->clock[0]); goto err_clock; @@ -625,7 +610,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) if (extra_clks[i - 1] == NULL) break; - clk = clk_get(this->dev, extra_clks[i - 1]); + clk = devm_clk_get(this->dev, extra_clks[i - 1]); if (IS_ERR(clk)) { err = PTR_ERR(clk); goto err_clock; @@ -647,7 +632,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) err_clock: dev_dbg(this->dev, "failed in finding the clocks.\n"); - gpmi_put_clks(this); return err; } @@ -687,7 +671,6 @@ exit_regs: static void release_resources(struct gpmi_nand_data *this) { - gpmi_put_clks(this); release_register_block(this); release_bch_irq(this); release_dma_channels(this); -- cgit v1.2.3 From 76c930be3d4831b52d04aadc2522cfeeb7a6c789 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 7 Nov 2013 23:28:43 -0200 Subject: mtd: gpmi-lib: Make checkpatch happy Fix the following checkpatch warnings: WARNING: line over 80 characters #268: FILE: mtd/nand/gpmi-nand/gpmi-lib.c:268: + * consecutive reboots. The latter case has not been seen on the MX23 yet, WARNING: space prohibited before semicolon #356: FILE: mtd/nand/gpmi-nand/gpmi-lib.c:356: + (target.tRHOH_in_ns >= 0) ; WARNING: space prohibited before semicolon #1006: FILE: mtd/nand/gpmi-nand/gpmi-lib.c:1006: + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; Signed-off-by: Fabio Estevam Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index aaced29727fb..c7a578c954fb 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -265,8 +265,8 @@ int bch_set_geometry(struct gpmi_nand_data *this) * chip, otherwise it will lock up. So we skip resetting BCH on the MX23. * On the other hand, the MX28 needs the reset, because one case has been * seen where the BCH produced ECC errors constantly after 10000 - * consecutive reboots. The latter case has not been seen on the MX23 yet, - * still we don't know if it could happen there as well. + * consecutive reboots. The latter case has not been seen on the MX23 + * yet, still we don't know if it could happen there as well. */ ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this)); if (ret) @@ -353,7 +353,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, improved_timing_is_available = (target.tREA_in_ns >= 0) && (target.tRLOH_in_ns >= 0) && - (target.tRHOH_in_ns >= 0) ; + (target.tRHOH_in_ns >= 0); /* Inspect the clock. */ nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]); @@ -1003,7 +1003,7 @@ void gpmi_begin(struct gpmi_nand_data *this) /* [1] Set HW_GPMI_TIMING0 */ reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | - BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles); writel(reg, gpmi_regs + HW_GPMI_TIMING0); -- cgit v1.2.3 From 7c4bb4f8f8ad6d3cc338d59c00f674a571ae7ca6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 20:07:15 +0100 Subject: mtd: remove superfluous name casts map_info.name is "const char *" Signed-off-by: Geert Uytterhoeven Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris --- drivers/mtd/maps/pxa2xx-flash.c | 2 +- drivers/mtd/maps/sun_uflash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index d210d131fef2..63b52f7080fa 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -61,7 +61,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - info->map.name = (char *) flash->name; + info->map.name = flash->name; info->map.bankwidth = flash->width; info->map.phys = res->start; info->map.size = resource_size(res); diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index d467f3b11c96..39cc4181f025 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -75,7 +75,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp) up->name = of_get_property(dp, "model", NULL); if (up->name && 0 < strlen(up->name)) - up->map.name = (char *)up->name; + up->map.name = up->name; up->map.phys = op->resource[0].start; -- cgit v1.2.3 From 8ca14e12a75216060e5dfbfe28a5efc5c230e08c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 20:07:16 +0100 Subject: mtd: pasemi_nand.c: remove superfluous name cast device_driver.name is "const char *" Signed-off-by: Geert Uytterhoeven Acked-by: Olof Johansson Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris --- drivers/mtd/nand/pasemi_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 4d174366a0f0..90f871acb0ef 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match); static struct platform_driver pasemi_nand_driver = { .driver = { - .name = (char*)driver_name, + .name = driver_name, .owner = THIS_MODULE, .of_match_table = pasemi_nand_match, }, -- cgit v1.2.3 From da6fcf0e3720b94197432510f3d455ed9243773f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 20:07:23 +0100 Subject: mtd: ms02-nv: remove superfluous name cast mtd_info.name is "const char *" Signed-off-by: Geert Uytterhoeven Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Brian Norris --- drivers/mtd/devices/ms02-nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 182849d39c61..5c8b322ba904 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr) mtd->type = MTD_RAM; mtd->flags = MTD_CAP_RAM; mtd->size = fixsize; - mtd->name = (char *)ms02nv_name; + mtd->name = ms02nv_name; mtd->owner = THIS_MODULE; mtd->_read = ms02nv_read; mtd->_write = ms02nv_write; -- cgit v1.2.3 From 26a6d240e2a1480a33d76ac4db8855b6a7f2bd89 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 12 Nov 2013 20:11:26 +0100 Subject: mtd: make mtd_partition.name const This allows to drop a few casts. Signed-off-by: Geert Uytterhoeven Signed-off-by: Brian Norris --- drivers/mtd/mtdpart.c | 2 +- drivers/mtd/ofpart.c | 4 ++-- include/linux/mtd/partitions.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6e732c3820c1..67a89bb45943 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -534,7 +534,7 @@ out_register: return slave; } -int mtd_add_partition(struct mtd_info *master, char *name, +int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length) { struct mtd_partition part; diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index d64f8c30945f..f0a708bf9b0e 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -81,7 +81,7 @@ static int parse_ofpart_partitions(struct mtd_info *master, partname = of_get_property(pp, "label", &len); if (!partname) partname = of_get_property(pp, "name", &len); - (*pparts)[i].name = (char *)partname; + (*pparts)[i].name = partname; if (of_get_property(pp, "read-only", &len)) (*pparts)[i].mask_flags |= MTD_WRITEABLE; @@ -152,7 +152,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, if (names && (plen > 0)) { int len = strlen(names) + 1; - (*pparts)[i].name = (char *)names; + (*pparts)[i].name = names; plen -= len; names += len; } else { diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 1f8d24bdafda..335ffca10c10 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -37,7 +37,7 @@ */ struct mtd_partition { - char *name; /* identifier string */ + const char *name; /* identifier string */ uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ @@ -80,7 +80,7 @@ extern int register_mtd_parser(struct mtd_part_parser *parser); extern int deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); -int mtd_add_partition(struct mtd_info *master, char *name, +int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length); int mtd_del_partition(struct mtd_info *master, int partno); uint64_t mtd_get_device_size(const struct mtd_info *mtd); -- cgit v1.2.3 From de484a381c4e7df5587febb16b727212b2da597c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:10 -0300 Subject: mtd: nand: pxa3xx: Add documentation about the controller Given there's no public specification to this date, and in order to capture some important details and singularities about the controller let's document them once and for good. Cc: linux-doc@vger.kernel.org Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- Documentation/mtd/nand/pxa3xx-nand.txt | 113 +++++++++++++++++++++++++++++++++ drivers/mtd/nand/pxa3xx_nand.c | 2 + 2 files changed, 115 insertions(+) create mode 100644 Documentation/mtd/nand/pxa3xx-nand.txt (limited to 'drivers/mtd') diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt new file mode 100644 index 000000000000..840fd41c181b --- /dev/null +++ b/Documentation/mtd/nand/pxa3xx-nand.txt @@ -0,0 +1,113 @@ + +About this document +=================== + +Some notes about Marvell's NAND controller available in PXA and Armada 370/XP +SoC (aka NFCv1 and NFCv2), with an emphasis on the latter. + +NFCv2 controller background +=========================== + +The controller has a 2176 bytes FIFO buffer. Therefore, in order to support +larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of +chunked transfers. + +For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below) +we'll have this layout in the pages: + + ------------------------------------------------------------------------------ + | 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... | + ------------------------------------------------------------------------------ + +The driver reads the data and spare portions independently and builds an internal +buffer with this layout (in the 4 KiB page case): + + ------------------------------------------ + | 4096B data | 64B spare | + ------------------------------------------ + +Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC' +OOB, one per chunk read. + + ------------------------------------------------------------------- + | 4096B data | 32B spare | 30B ECC | 32B spare | 30B ECC | + ------------------------------------------------------------------- + +So, in order to achieve reading (for instance), we issue several READ0 commands +(with some additional controller-specific magic) and read two chunks of 2080B +(2048 data + 32 spare) each. +The driver accommodates this data to expose the NAND core a contiguous buffer +(4096 data + spare) or (4096 + spare + ECC + spare + ECC). + +ECC +=== + +The controller has built-in hardware ECC capabilities. In addition it is +configurable between two modes: 1) Hamming, 2) BCH. + +Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way +the controller is configured to transfer the data. + +In the BCH mode the ECC code will be calculated for each transfered chunk +and expected to be located (when reading/programming) right after the spare +bytes as the figure above shows. + +So, repeating the above scheme, a 2048B data chunk will be followed by 32B +spare, and then the ECC controller will read/write the ECC code (30B in +this case): + + ------------------------------------ + | 2048B data | 32B spare | 30B ECC | + ------------------------------------ + +If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long. +If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block. +So in Hamming mode, a 2048B page will have a 24B ECC. + +Despite all of the above, the controller requires the driver to only read or +write in multiples of 8-bytes, because the data buffer is 64-bits. + +OOB +=== + +Because of the above scheme, and because the "spare" OOB is really located in +the middle of a page, spare OOB cannot be read or write independently of the +data area. In other words, in order to read the OOB (aka READOOB), the entire +page (aka READ0) has to be read. + +In the same sense, in order to write to the spare OOB the driver has to write +an *entire* page. + +Factory bad blocks handling +=========================== + +Given the ECC BCH requires to layout the device's pages in a split +data/OOB/data/OOB way, the controller has a view of the flash page that's +different from the specified (aka the manufacturer's) view. In other words, + +Factory view: + + ----------------------------------------------- + | Data |x OOB | + ----------------------------------------------- + +Driver's view: + + ----------------------------------------------- + | Data | OOB | Data x | OOB | + ----------------------------------------------- + +It can be seen from the above, that the factory bad block marker must be +searched within the 'data' region, and not in the usual OOB region. + +In addition, this means under regular usage the driver will write such +position (since it belongs to the data region) and every used block is +likely to be marked as bad. + +For this reason, marking the block as bad in the OOB is explicitly +disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale +for this is that there's no point in marking a block as bad, because good +blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage. + +Instead, the driver relies on the bad block table alone, and should only perform +the bad block scan on the very first time (when the device hasn't been used). diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4b3aaa898a8b..f7c004d7cf4f 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -7,6 +7,8 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * See Documentation/mtd/nand/pxa3xx-nand.txt for more details. */ #include -- cgit v1.2.3 From c5f99677a4cdfbc63b3944cb897dd5a8ab2e19ea Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:11 -0300 Subject: mtd: nand: pxa3xx: Make config menu show supported platforms Since we have now support for the NFCv2 controller found on Armada 370/XP platforms. Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 8dd72b420dd2..691f5a05ecf3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -326,11 +326,11 @@ config MTD_NAND_ATMEL on Atmel AT91 and AVR32 processors. config MTD_NAND_PXA3xx - tristate "Support for NAND flash devices on PXA3xx" + tristate "NAND support on PXA3xx and Armada 370/XP" depends on PXA3xx || ARCH_MMP || PLAT_ORION help This enables the driver for the NAND flash device found on - PXA3xx processors + PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). config MTD_NAND_SLC_LPC32XX tristate "NXP LPC32xx SLC Controller" -- cgit v1.2.3 From 664c7f5e81df12b5cac873a25fa9ac9cc90c13c3 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:12 -0300 Subject: mtd: nand: pxa3xx: Prevent sub-page writes The current driver doesn't support sub-page writing, so report that to the NAND core. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f7c004d7cf4f..c10cb06884f9 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1145,6 +1145,7 @@ static int alloc_nand_resource(struct platform_device *pdev) chip->read_byte = pxa3xx_nand_read_byte; chip->read_buf = pxa3xx_nand_read_buf; chip->write_buf = pxa3xx_nand_write_buf; + chip->options |= NAND_NO_SUBPAGE_WRITE; } spin_lock_init(&chip->controller->lock); -- cgit v1.2.3 From 4e86fd22af2c930e741536e8637bca9355fa8bb5 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:13 -0300 Subject: mtd: nand: pxa3xx: read_page() returns max_bitflips As per the ecc.read_page() prototype, we must return the maximum number of bitflips that were corrected on any one region covering an ecc step. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index c10cb06884f9..f25d71b20931 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -751,6 +751,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; + int max_bitflips = 0; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -758,6 +759,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, if (info->retcode == ERR_SBERR) { switch (info->use_ecc) { case 1: + max_bitflips = 1; mtd->ecc_stats.corrected++; break; case 0: @@ -776,7 +778,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, mtd->ecc_stats.failed++; } - return 0; + return max_bitflips; } static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) -- cgit v1.2.3 From c7e9c7e71b5a76adf42bf10e059ae1d63bcd5e1a Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:14 -0300 Subject: mtd: nand: pxa3xx: Early variant detection In order to customize early settings depending on the detected SoC variant, move the detection to be before the nand_chip struct filling. In a follow-up patch, this change is needed to detect the variant *before* the call to alloc_nand_resource(), which allows to set a different cmdfunc() for each variant. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f25d71b20931..64e01cfe1a9b 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -258,6 +258,25 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) +static struct of_device_id pxa3xx_nand_dt_ids[] = { + { + .compatible = "marvell,pxa3xx-nand", + .data = (void *)PXA3XX_NAND_VARIANT_PXA, + }, + {} +}; +MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); + +static enum pxa3xx_nand_variant +pxa3xx_nand_get_variant(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); + if (!of_id) + return PXA3XX_NAND_VARIANT_PXA; + return (enum pxa3xx_nand_variant)of_id->data; +} + static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, const struct pxa3xx_nand_timing *t) { @@ -1125,6 +1144,7 @@ static int alloc_nand_resource(struct platform_device *pdev) return -ENOMEM; info->pdev = pdev; + info->variant = pxa3xx_nand_get_variant(pdev); for (cs = 0; cs < pdata->num_cs; cs++) { mtd = (struct mtd_info *)((unsigned int)&info[1] + (sizeof(*mtd) + sizeof(*host)) * cs); @@ -1259,25 +1279,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) return 0; } -static struct of_device_id pxa3xx_nand_dt_ids[] = { - { - .compatible = "marvell,pxa3xx-nand", - .data = (void *)PXA3XX_NAND_VARIANT_PXA, - }, - {} -}; -MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); - -static enum pxa3xx_nand_variant -pxa3xx_nand_get_variant(struct platform_device *pdev) -{ - const struct of_device_id *of_id = - of_match_device(pxa3xx_nand_dt_ids, &pdev->dev); - if (!of_id) - return PXA3XX_NAND_VARIANT_PXA; - return (enum pxa3xx_nand_variant)of_id->data; -} - static int pxa3xx_nand_probe_dt(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; @@ -1334,7 +1335,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } info = platform_get_drvdata(pdev); - info->variant = pxa3xx_nand_get_variant(pdev); probe_success = 0; for (cs = 0; cs < pdata->num_cs; cs++) { struct mtd_info *mtd = info->host[cs]->mtd; -- cgit v1.2.3 From 2d79ab16f592f07f21d666a86682684ab2d135f8 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:15 -0300 Subject: mtd: nand: pxa3xx: Use chip->cmdfunc instead of the internal Whenever possible, it's always better to use the generic chip->cmdfunc instead of the internal pxa3xx_nand_cmdfunc(). In this particular case, this will allow to have multiple cmdfunc() implementations for different SoC variants. Reviewed-by: Huang Shijie Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 64e01cfe1a9b..5f0265de22bc 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1011,14 +1011,18 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { struct mtd_info *mtd; + struct nand_chip *chip; int ret; + mtd = info->host[info->cs]->mtd; + chip = mtd->priv; + /* use the common timing to make a try */ ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); if (ret) return ret; - pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); if (info->is_ready) return 0; -- cgit v1.2.3 From 2128b08c7c3aaf8b81fb76a0ce9ba37b5492f0db Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:16 -0300 Subject: mtd: nand: pxa3xx: Split FIFO size from to-be-read FIFO count Introduce a fifo_size field to represent the size of the controller's FIFO buffer, and use it to distinguish that size from the amount of data bytes to be read from the FIFO. This is important to support devices with pages larger than the controller's internal FIFO, that need to read the pages in FIFO-sized chunks. In particular, the current code is at least confusing, for it mixes all the different sizes involved: FIFO size, page size and data size. This commit starts the cleaning by removing the info->page_size field that is not currently used. The host->page_size field should also be removed and use always mtd->writesize instead. Follow up commits will clean this up. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5f0265de22bc..d6e96210c251 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -201,8 +201,8 @@ struct pxa3xx_nand_info { int use_spare; /* use spare ? */ int is_ready; - unsigned int page_size; /* page size of attached chip */ - unsigned int data_size; /* data size in FIFO */ + unsigned int fifo_size; /* max. data size in the FIFO */ + unsigned int data_size; /* data to be read from FIFO */ unsigned int oob_size; int retcode; @@ -303,16 +303,15 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - struct pxa3xx_nand_host *host = info->host[info->cs]; int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - info->data_size = host->page_size; + info->data_size = info->fifo_size; if (!oob_enable) { info->oob_size = 0; return; } - switch (host->page_size) { + switch (info->fifo_size) { case 2048: info->oob_size = (info->use_ecc) ? 40 : 64; break; @@ -929,9 +928,12 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) uint32_t ndcr = nand_readl(info, NDCR); if (ndcr & NDCR_PAGE_SZ) { + /* Controller's FIFO size */ + info->fifo_size = 2048; host->page_size = 2048; host->read_id_bytes = 4; } else { + info->fifo_size = 512; host->page_size = 512; host->read_id_bytes = 2; } -- cgit v1.2.3 From 0a3f3a1916bcac44a86ca89c874cdcad5e7746e9 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:17 -0300 Subject: mtd: nand: pxa3xx: Replace host->page_size by mtd->writesize There's no need to privately store the device page size as it's available in mtd structure field mtd->writesize. Also, this removes the hardcoded page size value, leaving the auto-detected value only. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index d6e96210c251..3779b70623a0 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -151,7 +151,6 @@ struct pxa3xx_nand_host { void *info_data; /* page size of attached chip */ - unsigned int page_size; int use_ecc; int cs; @@ -610,12 +609,12 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->buf_start += mtd->writesize; /* Second command setting for large pages */ - if (host->page_size >= PAGE_CHUNK_SIZE) + if (mtd->writesize >= PAGE_CHUNK_SIZE) info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); case NAND_CMD_SEQIN: /* small page addr setting */ - if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { + if (unlikely(mtd->writesize < PAGE_CHUNK_SIZE)) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); @@ -891,7 +890,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, } /* calculate flash information */ - host->page_size = f->page_size; host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ @@ -930,11 +928,9 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) if (ndcr & NDCR_PAGE_SZ) { /* Controller's FIFO size */ info->fifo_size = 2048; - host->page_size = 2048; host->read_id_bytes = 4; } else { info->fifo_size = 512; - host->page_size = 512; host->read_id_bytes = 2; } @@ -1102,7 +1098,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) def = pxa3xx_flash_ids; KEEP_CONFIG: chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = host->page_size; + chip->ecc.size = info->fifo_size; chip->ecc.strength = 1; if (info->reg_ndcr & NDCR_DWIDTH_M) -- cgit v1.2.3 From 6a3e48651fc6ce02aac08bc419cffa74f306ee32 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 7 Nov 2013 12:17:18 -0300 Subject: mtd: nand: pxa3xx: Add a nice comment to pxa3xx_set_datasize() Add a comment clarifying the use of pxa3xx_set_datasize() which is only applicable on data read/write commands (i.e. commands with a data cycle, such as READID, READ0, STATUS, etc.) Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 3779b70623a0..9f8c58f55c75 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -300,6 +300,11 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, nand_writel(info, NDTR1CS0, ndtr1); } +/* + * Set the data and OOB size, depending on the selected + * spare and ECC configuration. + * Only applicable to READ0, READOOB and PAGEPROG commands. + */ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; -- cgit v1.2.3 From 55d9fd6e94caf5f30d027f49bd0a4955bc6b3a8c Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:26 -0300 Subject: mtd: nand: pxa3xx: Use a completion to signal device ready The expected behavior of the waitfunc() NAND chip call is to wait for the device to be READY (this is a standard chip line). However, the current implementation does almost nothing, which opens the possibility of issuing a command to a non-ready device. Fix this by adding a new completion to wait for the ready event to arrive. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 9f8c58f55c75..b3c5c69269bc 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -37,6 +37,7 @@ #include +#define NAND_DEV_READY_TIMEOUT 50 #define CHIP_DELAY_TIMEOUT (2 * HZ/10) #define NAND_STOP_DELAY (2 * HZ/50) #define PAGE_CHUNK_SIZE (2048) @@ -168,7 +169,7 @@ struct pxa3xx_nand_info { struct clk *clk; void __iomem *mmio_base; unsigned long mmio_phys; - struct completion cmd_complete; + struct completion cmd_complete, dev_ready; unsigned int buf_start; unsigned int buf_count; @@ -198,7 +199,7 @@ struct pxa3xx_nand_info { int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ int use_spare; /* use spare ? */ - int is_ready; + int need_wait; unsigned int fifo_size; /* max. data size in the FIFO */ unsigned int data_size; /* data to be read from FIFO */ @@ -476,7 +477,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; - unsigned int status, is_completed = 0; + unsigned int status, is_completed = 0, is_ready = 0; unsigned int ready, cmd_done; if (info->cs == 0) { @@ -512,8 +513,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) is_completed = 1; } if (status & ready) { - info->is_ready = 1; info->state = STATE_READY; + is_ready = 1; } if (status & NDSR_WRCMDREQ) { @@ -542,6 +543,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) nand_writel(info, NDSR, status); if (is_completed) complete(&info->cmd_complete); + if (is_ready) + complete(&info->dev_ready); NORMAL_IRQ_EXIT: return IRQ_HANDLED; } @@ -572,7 +575,6 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->oob_size = 0; info->use_ecc = 0; info->use_spare = 1; - info->is_ready = 0; info->retcode = ERR_NONE; if (info->cs != 0) info->ndcb0 = NDCB0_CSEL; @@ -745,6 +747,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); + init_completion(&info->dev_ready); + info->need_wait = 1; pxa3xx_nand_start(info); ret = wait_for_completion_timeout(&info->cmd_complete, @@ -859,21 +863,27 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; + int ret; + + if (info->need_wait) { + ret = wait_for_completion_timeout(&info->dev_ready, + CHIP_DELAY_TIMEOUT); + info->need_wait = 0; + if (!ret) { + dev_err(&info->pdev->dev, "Ready time out!!!\n"); + return NAND_STATUS_FAIL; + } + } /* pxa3xx_nand_send_command has waited for command complete */ if (this->state == FL_WRITING || this->state == FL_ERASING) { if (info->retcode == ERR_NONE) return 0; - else { - /* - * any error make it return 0x01 which will tell - * the caller the erase and write fail - */ - return 0x01; - } + else + return NAND_STATUS_FAIL; } - return 0; + return NAND_STATUS_READY; } static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, @@ -1026,7 +1036,7 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) return ret; chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); - if (info->is_ready) + if (!info->need_wait) return 0; return -ENODEV; -- cgit v1.2.3 From 56704d857ac9a1044ec58cfe0ff95dc6bdbd9d58 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:27 -0300 Subject: mtd: nand: pxa3xx: Use waitfunc() to wait for the device to be ready In pxa3xx_nand_sensing() instead of simply using info->is_ready after issuing a command, the correct way of checking is to wait for the device to be ready through the chip's waitfunc(). Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b3c5c69269bc..a30116bfff4d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1036,10 +1036,11 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) return ret; chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); - if (!info->need_wait) - return 0; + ret = chip->waitfunc(mtd, chip); + if (ret & NAND_STATUS_FAIL) + return -ENODEV; - return -ENODEV; + return 0; } static int pxa3xx_nand_scan(struct mtd_info *mtd) -- cgit v1.2.3 From 776f265e279744e3f327ccd3e7eb378046311373 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:28 -0300 Subject: mtd: nand: pxa3xx: Add bad block handling Add support for flash-based bad block table using Marvell's custom in-flash bad block table layout. The support is enabled a 'flash_bbt' platform data or device tree parameter. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/pxa3xx-nand.txt | 2 ++ drivers/mtd/nand/pxa3xx_nand.c | 37 ++++++++++++++++++++++ include/linux/platform_data/mtd-nand-pxa3xx.h | 3 ++ 3 files changed, 42 insertions(+) (limited to 'drivers/mtd') diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index bed83908edfe..86e0a5601ff5 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -15,6 +15,8 @@ Optional properties: - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader - num-cs: Number of chipselect lines to usw + - nand-on-flash-bbt: boolean to enable on flash bbt option if + not present false Example: diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index a30116bfff4d..84a6c649100c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) #define ARCH_HAS_DMA @@ -241,6 +242,29 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { { "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, }; +static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' }; +static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION, + .offs = 8, + .len = 6, + .veroffs = 14, + .maxblocks = 8, /* Last 8 blocks in each chip */ + .pattern = bbt_mirror_pattern +}; + /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) @@ -1122,6 +1146,18 @@ KEEP_CONFIG: if (nand_scan_ident(mtd, 1, def)) return -ENODEV; + + if (pdata->flash_bbt) { + /* + * We'll use a bad block table stored in-flash and don't + * allow writing the bad block marker to the flash. + */ + chip->bbt_options |= NAND_BBT_USE_FLASH | + NAND_BBT_NO_OOB_BBM; + chip->bbt_td = &bbt_main_descr; + chip->bbt_md = &bbt_mirror_descr; + } + /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2; @@ -1316,6 +1352,7 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev) if (of_get_property(np, "marvell,nand-keep-config", NULL)) pdata->keep_config = 1; of_property_read_u32(np, "num-cs", &pdata->num_cs); + pdata->flash_bbt = of_get_nand_on_flash_bbt(np); pdev->dev.platform_data = pdata; diff --git a/include/linux/platform_data/mtd-nand-pxa3xx.h b/include/linux/platform_data/mtd-nand-pxa3xx.h index ffb801998e5d..a94147124929 100644 --- a/include/linux/platform_data/mtd-nand-pxa3xx.h +++ b/include/linux/platform_data/mtd-nand-pxa3xx.h @@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data { /* indicate how many chip selects will be used */ int num_cs; + /* use an flash-based bad block table */ + bool flash_bbt; + const struct mtd_partition *parts[NUM_CHIP_SELECT]; unsigned int nr_parts[NUM_CHIP_SELECT]; -- cgit v1.2.3 From 43bcfd2bb24abf7307634bc7194386b38d6f264f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:29 -0300 Subject: mtd: nand: pxa3xx: Add driver-specific ECC BCH support This commit adds the BCH ECC support available in NFCv2 controller. Depending on the detected required strength the respective ECC layout is selected. This commit adds an empty ECC layout, since support to access large pages is first required. Once that support is added, a proper ECC layout will be added as well. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 86 +++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 84a6c649100c..5062eddad834 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -58,6 +58,7 @@ #define NDPCR (0x18) /* Page Count Register */ #define NDBDR0 (0x1C) /* Bad Block Register 0 */ #define NDBDR1 (0x20) /* Bad Block Register 1 */ +#define NDECCCTRL (0x28) /* ECC control */ #define NDDB (0x40) /* Data Buffer */ #define NDCB0 (0x48) /* Command Buffer0 */ #define NDCB1 (0x4C) /* Command Buffer1 */ @@ -198,6 +199,7 @@ struct pxa3xx_nand_info { int cs; int use_ecc; /* use HW ECC ? */ + int ecc_bch; /* using BCH ECC? */ int use_dma; /* use DMA ? */ int use_spare; /* use spare ? */ int need_wait; @@ -205,6 +207,8 @@ struct pxa3xx_nand_info { unsigned int fifo_size; /* max. data size in the FIFO */ unsigned int data_size; /* data to be read from FIFO */ unsigned int oob_size; + unsigned int spare_size; + unsigned int ecc_size; int retcode; /* cached register value */ @@ -335,19 +339,12 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; info->data_size = info->fifo_size; - if (!oob_enable) { - info->oob_size = 0; + if (!oob_enable) return; - } - switch (info->fifo_size) { - case 2048: - info->oob_size = (info->use_ecc) ? 40 : 64; - break; - case 512: - info->oob_size = (info->use_ecc) ? 8 : 16; - break; - } + info->oob_size = info->spare_size; + if (!info->use_ecc) + info->oob_size += info->ecc_size; } /** @@ -362,10 +359,15 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) ndcr = info->reg_ndcr; - if (info->use_ecc) + if (info->use_ecc) { ndcr |= NDCR_ECC_EN; - else + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x1); + } else { ndcr &= ~NDCR_ECC_EN; + if (info->ecc_bch) + nand_writel(info, NDECCCTRL, 0x0); + } if (info->use_dma) ndcr |= NDCR_DMA_EN; @@ -1067,6 +1069,41 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) return 0; } +static int pxa_ecc_init(struct pxa3xx_nand_info *info, + struct nand_ecc_ctrl *ecc, + int strength, int page_size) +{ + /* + * We don't use strength here as the PXA variant + * is used with non-ONFI compliant devices. + */ + if (page_size == 2048) { + info->spare_size = 40; + info->ecc_size = 24; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + return 1; + + } else if (page_size == 512) { + info->spare_size = 8; + info->ecc_size = 8; + ecc->mode = NAND_ECC_HW; + ecc->size = 512; + ecc->strength = 1; + return 1; + } + return 0; +} + +static int armada370_ecc_init(struct pxa3xx_nand_info *info, + struct nand_ecc_ctrl *ecc, + int strength, int page_size) +{ + /* Unimplemented yet */ + return 0; +} + static int pxa3xx_nand_scan(struct mtd_info *mtd) { struct pxa3xx_nand_host *host = mtd->priv; @@ -1137,13 +1174,13 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[1].name = NULL; def = pxa3xx_flash_ids; KEEP_CONFIG: - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = info->fifo_size; - chip->ecc.strength = 1; - if (info->reg_ndcr & NDCR_DWIDTH_M) chip->options |= NAND_BUSWIDTH_16; + /* Device detection must be done with ECC disabled */ + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + nand_writel(info, NDECCCTRL, 0x0); + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; @@ -1158,6 +1195,21 @@ KEEP_CONFIG: chip->bbt_md = &bbt_mirror_descr; } + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + ret = armada370_ecc_init(info, &chip->ecc, + chip->ecc_strength_ds, + mtd->writesize); + else + ret = pxa_ecc_init(info, &chip->ecc, + chip->ecc_strength_ds, + mtd->writesize); + if (!ret) { + dev_err(&info->pdev->dev, + "ECC strength %d at page size %d is not supported\n", + chip->ecc_strength_ds, mtd->writesize); + return -ENODEV; + } + /* calculate addressing information */ if (mtd->writesize >= 2048) host->col_addr_cycles = 2; -- cgit v1.2.3 From f0e6a32e9af51e2a65c3cbedbad4cbc6b1479330 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:30 -0300 Subject: mtd: nand: pxa3xx: Clear cmd buffer #3 (NDCB3) on command start Command buffer #3 is not properly cleared and it keeps the last set value. Fix this by clearing when a command is setup. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 5062eddad834..2962614899ea 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -602,6 +602,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->use_ecc = 0; info->use_spare = 1; info->retcode = ERR_NONE; + info->ndcb3 = 0; if (info->cs != 0) info->ndcb0 = NDCB0_CSEL; else @@ -623,7 +624,6 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, default: info->ndcb1 = 0; info->ndcb2 = 0; - info->ndcb3 = 0; break; } -- cgit v1.2.3 From 86beebae3acf531b75e63d88b7ec9b3804ce895e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:31 -0300 Subject: mtd: nand: pxa3xx: Add helper function to set page address Let's simplify the code by first introducing a helper function to set the page address, as done by the READ0, READOOB and SEQIN commands. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 2962614899ea..446916377401 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -583,6 +583,26 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) return 1; } +static void set_command_address(struct pxa3xx_nand_info *info, + unsigned int page_size, uint16_t column, int page_addr) +{ + /* small page addr setting */ + if (page_size < PAGE_CHUNK_SIZE) { + info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + | (column & 0xFF); + + info->ndcb2 = 0; + } else { + info->ndcb1 = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + + if (page_addr & 0xFF0000) + info->ndcb2 = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2 = 0; + } +} + static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, uint16_t column, int page_addr) { @@ -646,22 +666,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); case NAND_CMD_SEQIN: - /* small page addr setting */ - if (unlikely(mtd->writesize < PAGE_CHUNK_SIZE)) { - info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) - | (column & 0xFF); - - info->ndcb2 = 0; - } else { - info->ndcb1 = ((page_addr & 0xFFFF) << 16) - | (column & 0xFFFF); - - if (page_addr & 0xFF0000) - info->ndcb2 = (page_addr & 0xFF0000) >> 16; - else - info->ndcb2 = 0; - } + set_command_address(info, mtd->writesize, column, page_addr); info->buf_count = mtd->writesize + mtd->oobsize; memset(info->data_buff, 0xFF, info->buf_count); -- cgit v1.2.3 From 01d9947e04fe16ab5891c932f47a171db5607bb5 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:32 -0300 Subject: mtd: nand: pxa3xx: Remove READ0 switch/case falltrough READ0 and READOOB command preparation has a falltrough to SEQIN case, where the command address is specified. This is certainly confusing and makes the code less readable with no added value. Let's remove it. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 446916377401..0fdcc91af1e2 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -665,6 +665,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, if (mtd->writesize >= PAGE_CHUNK_SIZE) info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); + set_command_address(info, mtd->writesize, column, page_addr); + info->buf_count = mtd->writesize + mtd->oobsize; + memset(info->data_buff, 0xFF, info->buf_count); + break; + case NAND_CMD_SEQIN: set_command_address(info, mtd->writesize, column, page_addr); -- cgit v1.2.3 From c39ff03a402e354eb73c61cb732f9bc881d76879 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:33 -0300 Subject: mtd: nand: pxa3xx: Split prepare_command_pool() in two stages This commit splits the prepare_command_pool() function into two stages: prepare_start_command() / prepare_set_command(). This is a preparation patch without any functionality changes, and is meant to allow support for multiple page reading/writing operations. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 44 ++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 0fdcc91af1e2..db96a7fe04a1 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -603,18 +603,8 @@ static void set_command_address(struct pxa3xx_nand_info *info, } } -static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, - uint16_t column, int page_addr) +static void prepare_start_command(struct pxa3xx_nand_info *info, int command) { - int addr_cycle, exec_cmd; - struct pxa3xx_nand_host *host; - struct mtd_info *mtd; - - host = info->host[info->cs]; - mtd = host->mtd; - addr_cycle = 0; - exec_cmd = 1; - /* reset data and oob column point to handle data */ info->buf_start = 0; info->buf_count = 0; @@ -623,10 +613,6 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->use_spare = 1; info->retcode = ERR_NONE; info->ndcb3 = 0; - if (info->cs != 0) - info->ndcb0 = NDCB0_CSEL; - else - info->ndcb0 = 0; switch (command) { case NAND_CMD_READ0: @@ -638,14 +624,32 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, case NAND_CMD_PARAM: info->use_spare = 0; break; - case NAND_CMD_SEQIN: - exec_cmd = 0; - break; default: info->ndcb1 = 0; info->ndcb2 = 0; break; } +} + +static int prepare_set_command(struct pxa3xx_nand_info *info, int command, + uint16_t column, int page_addr) +{ + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; + + host = info->host[info->cs]; + mtd = host->mtd; + addr_cycle = 0; + exec_cmd = 1; + + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; + + if (command == NAND_CMD_SEQIN) + exec_cmd = 0; addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + host->col_addr_cycles); @@ -780,8 +784,10 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, nand_writel(info, NDTR1CS0, info->ndtr1cs0); } + prepare_start_command(info, command); + info->state = STATE_PREPARED; - exec_cmd = prepare_command_pool(info, command, column, page_addr); + exec_cmd = prepare_set_command(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); init_completion(&info->dev_ready); -- cgit v1.2.3 From 39f83d15df36fa2d50de677e0743438df2ed4cf4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:34 -0300 Subject: mtd: nand: pxa3xx: Move the data buffer clean to prepare_start_command() To allow future support of multiple page reading/writing, move the data buffer clean out of prepare_set_command(). This is done to prevent the data buffer from being cleaned on every command preparation, when a multiple command sequence is implemented to read/write pages larger than the FIFO size (2 KiB). Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index db96a7fe04a1..7a164fbd7a18 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -605,6 +605,9 @@ static void set_command_address(struct pxa3xx_nand_info *info, static void prepare_start_command(struct pxa3xx_nand_info *info, int command) { + struct pxa3xx_nand_host *host = info->host[info->cs]; + struct mtd_info *mtd = host->mtd; + /* reset data and oob column point to handle data */ info->buf_start = 0; info->buf_count = 0; @@ -629,6 +632,19 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) info->ndcb2 = 0; break; } + + /* + * If we are about to issue a read command, or about to set + * the write address, then clean the data buffer. + */ + if (command == NAND_CMD_READ0 || + command == NAND_CMD_READOOB || + command == NAND_CMD_SEQIN) { + + info->buf_count = mtd->writesize + mtd->oobsize; + memset(info->data_buff, 0xFF, info->buf_count); + } + } static int prepare_set_command(struct pxa3xx_nand_info *info, int command, @@ -670,16 +686,11 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); set_command_address(info, mtd->writesize, column, page_addr); - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); break; case NAND_CMD_SEQIN: set_command_address(info, mtd->writesize, column, page_addr); - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); - break; case NAND_CMD_PAGEPROG: -- cgit v1.2.3 From e7f9a6a4628d0db43970fa3d2ba57be745416927 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:35 -0300 Subject: mtd: nand: pxa3xx: Fix SEQIN column address set This commit adds support page programming with a non-zero "column" address setting. This is important to support OOB writing, through command sequences such as: cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, ofs); write_buf(mtd, oob_buf, 6); cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 7a164fbd7a18..579347bc254d 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -690,7 +690,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, case NAND_CMD_SEQIN: - set_command_address(info, mtd->writesize, column, page_addr); + info->buf_start = column; + set_command_address(info, mtd->writesize, 0, page_addr); break; case NAND_CMD_PAGEPROG: -- cgit v1.2.3 From fa543bef72d62c14f25c6f48f5981f7ecc5402f2 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:36 -0300 Subject: mtd: nand: pxa3xx: Add a read/write buffers markers In preparation to support multiple (aka chunked, aka splitted) page I/O, this commit adds 'data_buff_pos' and 'oob_buff_pos' fields to keep track of where the next read (or write) should be done. This will allow multiple calls to handle_data_pio() to continue the read (or write) operation. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 579347bc254d..c17c28594a29 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -176,6 +176,8 @@ struct pxa3xx_nand_info { unsigned int buf_start; unsigned int buf_count; unsigned int buf_size; + unsigned int data_buff_pos; + unsigned int oob_buff_pos; /* DMA information */ int drcmr_dat; @@ -334,11 +336,12 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, * spare and ECC configuration. * Only applicable to READ0, READOOB and PAGEPROG commands. */ -static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) +static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info, + struct mtd_info *mtd) { int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; - info->data_size = info->fifo_size; + info->data_size = mtd->writesize; if (!oob_enable) return; @@ -426,26 +429,39 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) static void handle_data_pio(struct pxa3xx_nand_info *info) { + unsigned int do_bytes = min(info->data_size, info->fifo_size); + switch (info->state) { case STATE_PIO_WRITING: - __raw_writesl(info->mmio_base + NDDB, info->data_buff, - DIV_ROUND_UP(info->data_size, 4)); + __raw_writesl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(do_bytes, 4)); + if (info->oob_size > 0) - __raw_writesl(info->mmio_base + NDDB, info->oob_buff, - DIV_ROUND_UP(info->oob_size, 4)); + __raw_writesl(info->mmio_base + NDDB, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->oob_size, 4)); break; case STATE_PIO_READING: - __raw_readsl(info->mmio_base + NDDB, info->data_buff, - DIV_ROUND_UP(info->data_size, 4)); + __raw_readsl(info->mmio_base + NDDB, + info->data_buff + info->data_buff_pos, + DIV_ROUND_UP(do_bytes, 4)); + if (info->oob_size > 0) - __raw_readsl(info->mmio_base + NDDB, info->oob_buff, - DIV_ROUND_UP(info->oob_size, 4)); + __raw_readsl(info->mmio_base + NDDB, + info->oob_buff + info->oob_buff_pos, + DIV_ROUND_UP(info->oob_size, 4)); break; default: dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } + + /* Update buffer pointers for multi-page read/write */ + info->data_buff_pos += do_bytes; + info->oob_buff_pos += info->oob_size; + info->data_size -= do_bytes; } #ifdef ARCH_HAS_DMA @@ -612,6 +628,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) info->buf_start = 0; info->buf_count = 0; info->oob_size = 0; + info->data_buff_pos = 0; + info->oob_buff_pos = 0; info->use_ecc = 0; info->use_spare = 1; info->retcode = ERR_NONE; @@ -622,7 +640,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) case NAND_CMD_PAGEPROG: info->use_ecc = 1; case NAND_CMD_READOOB: - pxa3xx_set_datasize(info); + pxa3xx_set_datasize(info, mtd); break; case NAND_CMD_PARAM: info->use_spare = 0; -- cgit v1.2.3 From 70ed85232a93af5253bff4802ef4ead1e83faa5f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:37 -0300 Subject: mtd: nand: pxa3xx: Introduce multiple page I/O support As preparation work to fully support large pages, this commit adds the initial infrastructure to support splitted (aka chunked) I/O operation. This commit adds support for read, and follow-up patches will add write support. When a read (aka READ0) command is issued, the driver loops issuing the same command until all the requested data is transfered, changing the 'extended' command field as needed. For instance, if the driver is required to read a 4 KiB page, using a chunk size of 2 KiB, the transaction is splitted in: 1. Monolithic read, first 2 KiB page chunk is read 2. Last naked read, second and last 2KiB page chunk is read If ECC is enabled it is calculated on each chunk transfered and added at a controller-fixed location after the data chunk that must be spare area. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 182 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 172 insertions(+), 10 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index c17c28594a29..72dce4546451 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -103,6 +103,8 @@ #define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) +#define NDCB0_EXT_CMD_TYPE_MASK (0x7 << 29) +#define NDCB0_EXT_CMD_TYPE(x) (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK) #define NDCB0_CMD_TYPE_MASK (0x7 << 21) #define NDCB0_CMD_TYPE(x) (((x) << 21) & NDCB0_CMD_TYPE_MASK) #define NDCB0_NC (0x1 << 20) @@ -113,6 +115,14 @@ #define NDCB0_CMD1_MASK (0xff) #define NDCB0_ADDR_CYC_SHIFT (16) +#define EXT_CMD_TYPE_DISPATCH 6 /* Command dispatch */ +#define EXT_CMD_TYPE_NAKED_RW 5 /* Naked read or Naked write */ +#define EXT_CMD_TYPE_READ 4 /* Read */ +#define EXT_CMD_TYPE_DISP_WR 4 /* Command dispatch with write */ +#define EXT_CMD_TYPE_FINAL 3 /* Final command */ +#define EXT_CMD_TYPE_LAST_RW 1 /* Last naked read/write */ +#define EXT_CMD_TYPE_MONO 0 /* Monolithic read/write */ + /* macros for registers read/write */ #define nand_writel(info, off, val) \ __raw_writel((val), (info)->mmio_base + (off)) @@ -206,8 +216,8 @@ struct pxa3xx_nand_info { int use_spare; /* use spare ? */ int need_wait; - unsigned int fifo_size; /* max. data size in the FIFO */ unsigned int data_size; /* data to be read from FIFO */ + unsigned int chunk_size; /* split commands chunk size */ unsigned int oob_size; unsigned int spare_size; unsigned int ecc_size; @@ -271,6 +281,31 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = bbt_mirror_pattern }; +static struct nand_ecclayout ecc_layout_4KB_bch4bit = { + .eccbytes = 64, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127}, + /* Bootrom looks in bytes 0 & 5 for bad blocks */ + .oobfree = { {6, 26}, { 64, 32} } +}; + +static struct nand_ecclayout ecc_layout_4KB_bch8bit = { + .eccbytes = 128, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { } +}; + /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) @@ -429,7 +464,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) static void handle_data_pio(struct pxa3xx_nand_info *info) { - unsigned int do_bytes = min(info->data_size, info->fifo_size); + unsigned int do_bytes = min(info->data_size, info->chunk_size); switch (info->state) { case STATE_PIO_WRITING: @@ -666,7 +701,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) } static int prepare_set_command(struct pxa3xx_nand_info *info, int command, - uint16_t column, int page_addr) + int ext_cmd_type, uint16_t column, int page_addr) { int addr_cycle, exec_cmd; struct pxa3xx_nand_host *host; @@ -699,9 +734,20 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, if (command == NAND_CMD_READOOB) info->buf_start += mtd->writesize; - /* Second command setting for large pages */ - if (mtd->writesize >= PAGE_CHUNK_SIZE) + /* + * Multiple page read needs an 'extended command type' field, + * which is either naked-read or last-read according to the + * state. + */ + if (mtd->writesize == PAGE_CHUNK_SIZE) { info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8); + } else if (mtd->writesize > PAGE_CHUNK_SIZE) { + info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->chunk_size + + info->oob_size; + } set_command_address(info, mtd->writesize, column, page_addr); break; @@ -817,7 +863,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, prepare_start_command(info, command); info->state = STATE_PREPARED; - exec_cmd = prepare_set_command(info, command, column, page_addr); + exec_cmd = prepare_set_command(info, command, 0, column, page_addr); + if (exec_cmd) { init_completion(&info->cmd_complete); init_completion(&info->dev_ready); @@ -835,6 +882,93 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->state = STATE_IDLE; } +static void armada370_nand_cmdfunc(struct mtd_info *mtd, + const unsigned command, + int column, int page_addr) +{ + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; + int ret, exec_cmd, ext_cmd_type; + + /* + * if this is a x16 device then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, info->ndtr0cs0); + nand_writel(info, NDTR1CS0, info->ndtr1cs0); + } + + /* Select the extended command for the first command */ + switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + ext_cmd_type = EXT_CMD_TYPE_MONO; + break; + default: + ext_cmd_type = 0; + } + + prepare_start_command(info, command); + + /* + * Prepare the "is ready" completion before starting a command + * transaction sequence. If the command is not executed the + * completion will be completed, see below. + * + * We can do that inside the loop because the command variable + * is invariant and thus so is the exec_cmd. + */ + info->need_wait = 1; + init_completion(&info->dev_ready); + do { + info->state = STATE_PREPARED; + exec_cmd = prepare_set_command(info, command, ext_cmd_type, + column, page_addr); + if (!exec_cmd) { + info->need_wait = 0; + complete(&info->dev_ready); + break; + } + + init_completion(&info->cmd_complete); + pxa3xx_nand_start(info); + + ret = wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT); + if (!ret) { + dev_err(&info->pdev->dev, "Wait time out!!!\n"); + /* Stop State Machine for next command cycle */ + pxa3xx_nand_stop(info); + break; + } + + /* Check if the sequence is complete */ + if (info->data_size == 0) + break; + + if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { + /* Last read: issue a 'last naked read' */ + if (info->data_size == info->chunk_size) + ext_cmd_type = EXT_CMD_TYPE_LAST_RW; + else + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + } + } while (1); + + info->state = STATE_IDLE; +} + static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int oob_required) { @@ -1015,13 +1149,14 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) if (ndcr & NDCR_PAGE_SZ) { /* Controller's FIFO size */ - info->fifo_size = 2048; + info->chunk_size = 2048; host->read_id_bytes = 4; } else { - info->fifo_size = 512; + info->chunk_size = 512; host->read_id_bytes = 2; } + /* Set an initial chunk size */ info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); @@ -1125,6 +1260,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, * is used with non-ONFI compliant devices. */ if (page_size == 2048) { + info->chunk_size = 2048; info->spare_size = 40; info->ecc_size = 24; ecc->mode = NAND_ECC_HW; @@ -1133,6 +1269,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, return 1; } else if (page_size == 512) { + info->chunk_size = 512; info->spare_size = 8; info->ecc_size = 8; ecc->mode = NAND_ECC_HW; @@ -1147,7 +1284,28 @@ static int armada370_ecc_init(struct pxa3xx_nand_info *info, struct nand_ecc_ctrl *ecc, int strength, int page_size) { - /* Unimplemented yet */ + if (strength == 4 && page_size == 4096) { + info->ecc_bch = 1; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch4bit; + ecc->strength = 16; + return 1; + + } else if (strength == 8 && page_size == 4096) { + info->ecc_bch = 1; + info->chunk_size = 1024; + info->spare_size = 0; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_4KB_bch8bit; + ecc->strength = 16; + return 1; + } return 0; } @@ -1315,12 +1473,16 @@ static int alloc_nand_resource(struct platform_device *pdev) chip->controller = &info->controller; chip->waitfunc = pxa3xx_nand_waitfunc; chip->select_chip = pxa3xx_nand_select_chip; - chip->cmdfunc = pxa3xx_nand_cmdfunc; chip->read_word = pxa3xx_nand_read_word; chip->read_byte = pxa3xx_nand_read_byte; chip->read_buf = pxa3xx_nand_read_buf; chip->write_buf = pxa3xx_nand_write_buf; chip->options |= NAND_NO_SUBPAGE_WRITE; + + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) + chip->cmdfunc = armada370_nand_cmdfunc; + else + chip->cmdfunc = pxa3xx_nand_cmdfunc; } spin_lock_init(&chip->controller->lock); -- cgit v1.2.3 From 535cb57a4da0378b8a28d415249d501a4fa99ddf Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:38 -0300 Subject: mtd: nand: pxa3xx: Add multiple chunk write support This commit adds write support for large pages (4 KiB, 8 KiB). Such support is implemented by issuing a multiple command sequence, transfering a set of 2 KiB chunks per transaction. The splitted command sequence requires to send the SEQIN command independently of the PAGEPROG command and therefore it's set as an execution command. Since PAGEPROG enables ECC, each 2 KiB chunk of data is written together with ECC code at a controller-fixed location within the flash page. Currently, only devices with a 4 KiB page size has been tested. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 81 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 72dce4546451..ce3449c50e12 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -756,6 +756,20 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, info->buf_start = column; set_command_address(info, mtd->writesize, 0, page_addr); + + /* + * Multiple page programming needs to execute the initial + * SEQIN command that sets the page address. + */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | addr_cycle + | command; + /* No data transfer in this case */ + info->data_size = 0; + exec_cmd = 1; + } break; case NAND_CMD_PAGEPROG: @@ -765,13 +779,40 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 |= NDCB0_CMD_TYPE(0x1) - | NDCB0_AUTO_RS - | NDCB0_ST_ROW_EN - | NDCB0_DBC - | (NAND_CMD_PAGEPROG << 8) - | NAND_CMD_SEQIN - | addr_cycle; + /* Second command setting for large pages */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + /* + * Multiple page write uses the 'extended command' + * field. This can be used to issue a command dispatch + * or a naked-write depending on the current stage. + */ + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_LEN_OVRD + | NDCB0_EXT_CMD_TYPE(ext_cmd_type); + info->ndcb3 = info->chunk_size + + info->oob_size; + + /* + * This is the command dispatch that completes a chunked + * page program operation. + */ + if (info->data_size == 0) { + info->ndcb0 = NDCB0_CMD_TYPE(0x1) + | NDCB0_EXT_CMD_TYPE(ext_cmd_type) + | command; + info->ndcb1 = 0; + info->ndcb2 = 0; + info->ndcb3 = 0; + } + } else { + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | (NAND_CMD_PAGEPROG << 8) + | NAND_CMD_SEQIN + | addr_cycle; + } break; case NAND_CMD_PARAM: @@ -915,8 +956,15 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, case NAND_CMD_READOOB: ext_cmd_type = EXT_CMD_TYPE_MONO; break; + case NAND_CMD_SEQIN: + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; + break; + case NAND_CMD_PAGEPROG: + ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + break; default: ext_cmd_type = 0; + break; } prepare_start_command(info, command); @@ -954,7 +1002,16 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, } /* Check if the sequence is complete */ - if (info->data_size == 0) + if (info->data_size == 0 && command != NAND_CMD_PAGEPROG) + break; + + /* + * After a splitted program command sequence has issued + * the command dispatch, the command sequence is complete. + */ + if (info->data_size == 0 && + command == NAND_CMD_PAGEPROG && + ext_cmd_type == EXT_CMD_TYPE_DISPATCH) break; if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) { @@ -963,6 +1020,14 @@ static void armada370_nand_cmdfunc(struct mtd_info *mtd, ext_cmd_type = EXT_CMD_TYPE_LAST_RW; else ext_cmd_type = EXT_CMD_TYPE_NAKED_RW; + + /* + * If a splitted program command has no more data to transfer, + * the command dispatch must be issued to complete. + */ + } else if (command == NAND_CMD_PAGEPROG && + info->data_size == 0) { + ext_cmd_type = EXT_CMD_TYPE_DISPATCH; } } while (1); -- cgit v1.2.3 From 87f5336eef63f0a1d1755cfe9392e2c414605780 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 14 Nov 2013 18:25:39 -0300 Subject: mtd: nand: pxa3xx: Add ECC BCH correctable errors detection This commit extends the ECC correctable error detection to include ECC BCH errors. The number of BCH correctable errors can be any up to 16, and the actual value is exposed in the NDSR register. Therefore, we change some symbol names to refer to correctable or uncorrectable (instead of single-bit or double-bit as it was in the Hamming case) and while at it, cleanup the detection code slightly. Signed-off-by: Ezequiel Garcia Tested-by: Daniel Mack Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 57 ++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ce3449c50e12..f00ce27f61d0 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -85,6 +85,9 @@ #define NDCR_INT_MASK (0xFFF) #define NDSR_MASK (0xfff) +#define NDSR_ERR_CNT_OFF (16) +#define NDSR_ERR_CNT_MASK (0x1f) +#define NDSR_ERR_CNT(sr) ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK) #define NDSR_RDY (0x1 << 12) #define NDSR_FLASH_RDY (0x1 << 11) #define NDSR_CS0_PAGED (0x1 << 10) @@ -93,8 +96,8 @@ #define NDSR_CS1_CMDD (0x1 << 7) #define NDSR_CS0_BBD (0x1 << 6) #define NDSR_CS1_BBD (0x1 << 5) -#define NDSR_DBERR (0x1 << 4) -#define NDSR_SBERR (0x1 << 3) +#define NDSR_UNCORERR (0x1 << 4) +#define NDSR_CORERR (0x1 << 3) #define NDSR_WRDREQ (0x1 << 2) #define NDSR_RDDREQ (0x1 << 1) #define NDSR_WRCMDREQ (0x1) @@ -135,9 +138,9 @@ enum { ERR_NONE = 0, ERR_DMABUSERR = -1, ERR_SENDCMD = -2, - ERR_DBERR = -3, + ERR_UNCORERR = -3, ERR_BBERR = -4, - ERR_SBERR = -5, + ERR_CORERR = -5, }; enum { @@ -221,6 +224,8 @@ struct pxa3xx_nand_info { unsigned int oob_size; unsigned int spare_size; unsigned int ecc_size; + unsigned int ecc_err_cnt; + unsigned int max_bitflips; int retcode; /* cached register value */ @@ -567,10 +572,25 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) status = nand_readl(info, NDSR); - if (status & NDSR_DBERR) - info->retcode = ERR_DBERR; - if (status & NDSR_SBERR) - info->retcode = ERR_SBERR; + if (status & NDSR_UNCORERR) + info->retcode = ERR_UNCORERR; + if (status & NDSR_CORERR) { + info->retcode = ERR_CORERR; + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 && + info->ecc_bch) + info->ecc_err_cnt = NDSR_ERR_CNT(status); + else + info->ecc_err_cnt = 1; + + /* + * Each chunk composing a page is corrected independently, + * and we need to store maximum number of corrected bitflips + * to return it to the MTD layer in ecc.read_page(). + */ + info->max_bitflips = max_t(unsigned int, + info->max_bitflips, + info->ecc_err_cnt); + } if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { /* whether use dma to transfer data */ if (info->use_dma) { @@ -668,6 +688,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) info->use_ecc = 0; info->use_spare = 1; info->retcode = ERR_NONE; + info->ecc_err_cnt = 0; info->ndcb3 = 0; switch (command) { @@ -1049,26 +1070,18 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int max_bitflips = 0; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - if (info->retcode == ERR_SBERR) { - switch (info->use_ecc) { - case 1: - max_bitflips = 1; - mtd->ecc_stats.corrected++; - break; - case 0: - default: - break; - } - } else if (info->retcode == ERR_DBERR) { + if (info->retcode == ERR_CORERR && info->use_ecc) { + mtd->ecc_stats.corrected += info->ecc_err_cnt; + + } else if (info->retcode == ERR_UNCORERR) { /* * for blank page (all 0xff), HW will calculate its ECC as * 0, which is different from the ECC information within - * OOB, ignore such double bit errors + * OOB, ignore such uncorrectable errors */ if (is_buf_blank(buf, mtd->writesize)) info->retcode = ERR_NONE; @@ -1076,7 +1089,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, mtd->ecc_stats.failed++; } - return max_bitflips; + return info->max_bitflips; } static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) -- cgit v1.2.3 From 6033a949b2c466a13e84daebd99fdca5960b4db5 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Thu, 14 Nov 2013 14:41:32 -0800 Subject: mtd: nand: pxa3xx: make ECC configuration checks more explicit The Armada BCH configuration in this driver uses one of the two following ECC schemes: 16-bit correction per 2048 bytes 16-bit correction per 1024 bytes These are sufficient for mapping to the 4-bit per 512-bytes and 8-bit per 512-bytes (respectively) minimum correctability requirements of many common NAND. The current code only checks for the required strength (4-bit or 8-bit) without checking the ECC step size that is associated with that strength (and simply assumes it is 512). While that is often a safe assumption to make, let's make it explicit, since we have that information. Signed-off-by: Brian Norris Acked-by: Ezequiel Garcia Tested-by: Daniel Mack --- drivers/mtd/nand/pxa3xx_nand.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f00ce27f61d0..8f38abdb3310 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1360,9 +1360,13 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, static int armada370_ecc_init(struct pxa3xx_nand_info *info, struct nand_ecc_ctrl *ecc, - int strength, int page_size) + int strength, int ecc_stepsize, int page_size) { - if (strength == 4 && page_size == 4096) { + /* + * Required ECC: 4-bit correction per 512 bytes + * Select: 16-bit correction per 2048 bytes + */ + if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->chunk_size = 2048; info->spare_size = 32; @@ -1373,7 +1377,11 @@ static int armada370_ecc_init(struct pxa3xx_nand_info *info, ecc->strength = 16; return 1; - } else if (strength == 8 && page_size == 4096) { + /* + * Required ECC: 8-bit correction per 512 bytes + * Select: 16-bit correction per 1024 bytes + */ + } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->chunk_size = 1024; info->spare_size = 0; @@ -1481,6 +1489,7 @@ KEEP_CONFIG: if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) ret = armada370_ecc_init(info, &chip->ecc, chip->ecc_strength_ds, + chip->ecc_step_ds, mtd->writesize); else ret = pxa_ecc_init(info, &chip->ecc, -- cgit v1.2.3 From df877fb3f51980e60f785bb85ab841a5df01dc26 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:44 +0800 Subject: mtd: gpmi: do not use the local array to do the DMA transfer The local array feature[] is in the stack. We can see the warning when we enable the CONFIG_DMA_API_DEBUG: ---------------------------------------------------------- WARNING: at lib/dma-debug.c:950 check_for_stack+0xac/0xf8() gpmi-nand 112000.gpmi-nand: DMA-API: device driver maps memory fromstack [addr=dc05be34] Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.17-16851-g2414a73 #1324 [<80014cbc>] (unwind_backtrace+0x0/0x138) from [<8001251c>] (show_stack+0x10/0x14) [<8001251c>] (show_stack+0x10/0x14) from [<8002699c>] (warn_slowpath_common+0x4c/0x68) [<8002699c>] (warn_slowpath_common+0x4c/0x68) from [<80026a4c>] (warn_slowpath_fmt+0x30/0x40) [<80026a4c>] (warn_slowpath_fmt+0x30/0x40) from [<8028e2f8>] (check_for_stack+0xac/0xf8) [<8028e2f8>] (check_for_stack+0xac/0xf8) from [<8028e438>] (debug_dma_map_sg+0xf4/0x188) [<8028e438>] (debug_dma_map_sg+0xf4/0x188) from [<803968d0>] (prepare_data_dma+0xb8/0x1a8) [<803968d0>] (prepare_data_dma+0xb8/0x1a8) from [<80397b20>] (gpmi_send_data+0x84/0xfc) [<80397b20>] (gpmi_send_data+0x84/0xfc) from [<8038c2b4>] (nand_onfi_set_features+0x50/0x74) [<8038c2b4>] (nand_onfi_set_features+0x50/0x74) from [<80397198>] (gpmi_extra_init+0x90/0x170) [<80397198>] (gpmi_extra_init+0x90/0x170) from [<8039520c>] (gpmi_nand_probe+0x2f8/0xb3c) [<8039520c>] (gpmi_nand_probe+0x2f8/0xb3c) from [<8031b974>] (platform_drv_probe+0x18/0x1c) ---------------------------------------------------------- The patch uses the kzalloc to allocate the buffer, and free it when we do not use it anymore. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index c7a578c954fb..10a6f07eec7f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -20,6 +20,7 @@ */ #include #include +#include #include "gpmi-nand.h" #include "gpmi-regs.h" @@ -911,10 +912,14 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) struct resources *r = &this->resources; struct nand_chip *nand = &this->nand; struct mtd_info *mtd = &this->mtd; - uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {}; + uint8_t *feature; unsigned long rate; int ret; + feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL); + if (!feature) + return -ENOMEM; + nand->select_chip(mtd, 0); /* [1] send SET FEATURE commond to NAND */ @@ -942,11 +947,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode) this->flags |= GPMI_ASYNC_EDO_ENABLED; this->timing_mode = mode; + kfree(feature); dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode); return 0; err_out: nand->select_chip(mtd, -1); + kfree(feature); dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode); return -EINVAL; } -- cgit v1.2.3 From d7364a2710c4b159c189522a504b91d6cddf4208 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:45 +0800 Subject: mtd: gpmi: delete the gpmi_pre_bbt_scan We do not scan the BBT after we call the gpmi_pre_bbt_scan, so it has lost the meaning of existence. This patch merges this function into gpmi_init_last, and delete it. This patch does not change any logic. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 739f131e572c..9bce04bd3cac 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1562,19 +1562,6 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) return gpmi_alloc_dma_buffer(this); } -static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) -{ - /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ - if (GPMI_IS_MX23(this)) - this->swap_block_mark = false; - else - this->swap_block_mark = true; - - /* Set up the medium geometry */ - return gpmi_set_geometry(this); - -} - static void gpmi_nfc_exit(struct gpmi_nand_data *this) { nand_release(&this->mtd); @@ -1589,8 +1576,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this) struct bch_geometry *bch_geo = &this->bch_geometry; int ret; - /* Prepare for the BBT scan. */ - ret = gpmi_pre_bbt_scan(this); + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + this->swap_block_mark = !GPMI_IS_MX23(this); + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); if (ret) return ret; -- cgit v1.2.3 From bd92029cdb07bd82293d4ff3cd1123d5b012ad8a Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:46 +0800 Subject: mtd: gpmi: remove the unused line We do not use the chip->oob_poi in the mx23_write_transcription_stamp. So remove the unused line. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 9bce04bd3cac..1faf198a1085 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1439,7 +1439,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Write the NCB fingerprint into the page buffer. */ memset(buffer, ~0, mtd->writesize); - memset(chip->oob_poi, ~0, mtd->oobsize); memcpy(buffer + 12, fingerprint, strlen(fingerprint)); /* Loop through the first search area, writing NCB fingerprints. */ -- cgit v1.2.3 From ccce417734dd4eb1703483d419f7739133ca9f91 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:47 +0800 Subject: mtd: gpmi: rename the functions from gpmi_nfc_* to gpmi_nand_* The gpmi_nfc_* is the legacy name. In order to avoid the confusion, The patch renames the gpmi_nfc_* functions to gpmi_nand_*. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 1faf198a1085..36ef60aed216 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1561,7 +1561,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) return gpmi_alloc_dma_buffer(this); } -static void gpmi_nfc_exit(struct gpmi_nand_data *this) +static void gpmi_nand_exit(struct gpmi_nand_data *this) { nand_release(&this->mtd); gpmi_free_dma_buffer(this); @@ -1604,7 +1604,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this) return 0; } -static int gpmi_nfc_init(struct gpmi_nand_data *this) +static int gpmi_nand_init(struct gpmi_nand_data *this) { struct mtd_info *mtd = &this->mtd; struct nand_chip *chip = &this->nand; @@ -1668,7 +1668,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this) return 0; err_out: - gpmi_nfc_exit(this); + gpmi_nand_exit(this); return ret; } @@ -1725,7 +1725,7 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (ret) goto exit_nfc_init; - ret = gpmi_nfc_init(this); + ret = gpmi_nand_init(this); if (ret) goto exit_nfc_init; @@ -1745,7 +1745,7 @@ static int gpmi_nand_remove(struct platform_device *pdev) { struct gpmi_nand_data *this = platform_get_drvdata(pdev); - gpmi_nfc_exit(this); + gpmi_nand_exit(this); release_resources(this); return 0; } -- cgit v1.2.3 From 87a9d69892836fc9cf738fa8960a0c29cf8e3f16 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:48 +0800 Subject: mtd: gpmi: use devm_ioremap_resource Use the devm_ioremap_resource to simplify the code. [Note: as a side effect, this adds a missing call to request_memory().] Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 36ef60aed216..1f99038caf5f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -486,16 +486,9 @@ static int acquire_register_block(struct gpmi_nand_data *this, void __iomem *p; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); - if (!r) { - pr_err("Can't get resource for %s\n", res_name); - return -ENODEV; - } - - p = ioremap(r->start, resource_size(r)); - if (!p) { - pr_err("Can't remap %s\n", res_name); - return -ENOMEM; - } + p = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(p)) + return PTR_ERR(p); if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) res->gpmi_regs = p; @@ -507,17 +500,6 @@ static int acquire_register_block(struct gpmi_nand_data *this, return 0; } -static void release_register_block(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - if (res->gpmi_regs) - iounmap(res->gpmi_regs); - if (res->bch_regs) - iounmap(res->bch_regs); - res->gpmi_regs = NULL; - res->bch_regs = NULL; -} - static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) { struct platform_device *pdev = this->pdev; @@ -665,13 +647,11 @@ exit_clock: exit_dma_channels: release_bch_irq(this); exit_regs: - release_register_block(this); return ret; } static void release_resources(struct gpmi_nand_data *this) { - release_register_block(this); release_bch_irq(this); release_dma_channels(this); } -- cgit v1.2.3 From 3cb2c1ed4abe19d2881f74aa60c1a5b44524b2d0 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 14 Nov 2013 14:25:49 +0800 Subject: mtd: gpmi: use devm_request_irq Use devm_request_irq to simplify the code. Also remove the unused fields of structure resources{}. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 27 +++++---------------------- drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 -- 2 files changed, 5 insertions(+), 24 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 1f99038caf5f..5617876728ad 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -503,7 +503,6 @@ static int acquire_register_block(struct gpmi_nand_data *this, static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) { struct platform_device *pdev = this->pdev; - struct resources *res = &this->resources; const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; struct resource *r; int err; @@ -514,24 +513,11 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) return -ENODEV; } - err = request_irq(r->start, irq_h, 0, res_name, this); - if (err) { - pr_err("Can't own %s\n", res_name); - return err; - } - - res->bch_low_interrupt = r->start; - res->bch_high_interrupt = r->end; - return 0; -} - -static void release_bch_irq(struct gpmi_nand_data *this) -{ - struct resources *res = &this->resources; - int i = res->bch_low_interrupt; + err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this); + if (err) + dev_err(this->dev, "error requesting BCH IRQ\n"); - for (; i <= res->bch_high_interrupt; i++) - free_irq(i, this); + return err; } static void release_dma_channels(struct gpmi_nand_data *this) @@ -635,7 +621,7 @@ static int acquire_resources(struct gpmi_nand_data *this) ret = acquire_dma_channels(this); if (ret) - goto exit_dma_channels; + goto exit_regs; ret = gpmi_get_clks(this); if (ret) @@ -644,15 +630,12 @@ static int acquire_resources(struct gpmi_nand_data *this) exit_clock: release_dma_channels(this); -exit_dma_channels: - release_bch_irq(this); exit_regs: return ret; } static void release_resources(struct gpmi_nand_data *this) { - release_bch_irq(this); release_dma_channels(this); } diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index a7685e3a8748..4c801fa18725 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -26,8 +26,6 @@ struct resources { void __iomem *gpmi_regs; void __iomem *bch_regs; - unsigned int bch_low_interrupt; - unsigned int bch_high_interrupt; unsigned int dma_low_channel; unsigned int dma_high_channel; struct clk *clock[GPMI_CLK_MAX]; -- cgit v1.2.3 From 4f0614a020524547d46e85ae5327f531e33cdf47 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 13 Nov 2013 15:59:25 +0400 Subject: mtd: nand: diskonchip: Request memory region prior ioremap() This patch adds request_mem_region() prior ioremap() for diskonchip driver. This will allow to check if memory region is occupied by any other device, for example in case if we have memory region for several optional devices and only one device can be used at once. Signed-off-by: Alexander Shiyan Signed-off-by: Brian Norris --- drivers/mtd/nand/diskonchip.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b68a4959f700..0afafa049ea1 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1440,10 +1440,13 @@ static int __init doc_probe(unsigned long physadr) int reg, len, numchips; int ret = 0; + if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL)) + return -EBUSY; virtadr = ioremap(physadr, DOC_IOREMAP_LEN); if (!virtadr) { printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); - return -EIO; + ret = -EIO; + goto error_ioremap; } /* It's not possible to cleanly detect the DiskOnChip - the @@ -1629,6 +1632,10 @@ static int __init doc_probe(unsigned long physadr) WriteDOC(save_control, virtadr, DOCControl); fail: iounmap(virtadr); + +error_ioremap: + release_mem_region(physadr, DOC_IOREMAP_LEN); + return ret; } @@ -1645,6 +1652,7 @@ static void release_nanddoc(void) nextmtd = doc->nextdoc; nand_release(mtd); iounmap(doc->virtadr); + release_mem_region(doc->physadr, DOC_IOREMAP_LEN); kfree(mtd); } } -- cgit v1.2.3 From 43a34b8b730b6e12a8824c5bf2145022ed01f74f Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Tue, 19 Nov 2013 10:57:50 +0800 Subject: mtd: gpmi: remove the unnecessary pr_err() The error messages for the failure of dmaengine_prep_slave_sg are not necessary, this patch removes all these pr_err, and returns with the proper error code -EINVAL, not -1. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 63 ++++++++++++----------------------- 1 file changed, 22 insertions(+), 41 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 10a6f07eec7f..45b9a3db3606 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -1128,10 +1128,8 @@ int gpmi_send_command(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ sgl = &this->cmd_sgl; @@ -1141,11 +1139,8 @@ int gpmi_send_command(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, sgl, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] submit the DMA */ set_dma_type(this, DMA_FOR_COMMAND); @@ -1174,20 +1169,17 @@ int gpmi_send_data(struct gpmi_nand_data *this) pio[1] = 0; desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] send DMA request */ prepare_data_dma(this, DMA_TO_DEVICE); desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; + /* [3] submit the DMA */ set_dma_type(this, DMA_FOR_WRITE_DATA); return start_dma_without_bch_irq(this, desc); @@ -1211,20 +1203,16 @@ int gpmi_read_data(struct gpmi_nand_data *this) desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] : send DMA request */ prepare_data_dma(this, DMA_FROM_DEVICE); desc = dmaengine_prep_slave_sg(channel, &this->data_sgl, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] : submit the DMA */ set_dma_type(this, DMA_FOR_READ_DATA); @@ -1269,10 +1257,9 @@ int gpmi_send_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; + set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); return start_dma_with_bch_irq(this, desc); } @@ -1304,10 +1291,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio, 2, DMA_TRANS_NONE, 0); - if (!desc) { - pr_err("step 1 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [2] Enable the BCH block and read. */ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; @@ -1334,10 +1319,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, ARRAY_SIZE(pio), DMA_TRANS_NONE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 2 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [3] Disable the BCH block */ command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; @@ -1355,10 +1338,8 @@ int gpmi_read_page(struct gpmi_nand_data *this, (struct scatterlist *)pio, 3, DMA_TRANS_NONE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - pr_err("step 3 error\n"); - return -1; - } + if (!desc) + return -EINVAL; /* [4] submit the DMA */ set_dma_type(this, DMA_FOR_READ_ECC_PAGE); -- cgit v1.2.3 From da40c16a72f70329b599bb90a03bc23c8e0e7929 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 20 Nov 2013 10:09:43 +0800 Subject: mtd: gpmi: change pr_err to dev_err There are pr_err and dev_err in the gpmi driver now. It makes people confused. This patch changes all the pr_err to dev_err except the one in the gpmi_reset_block(). We also remove the unnecessary print for OOM message. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 47 +++++++++++++++++++++------------- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 44 +++++++++++++++---------------- 2 files changed, 50 insertions(+), 41 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 45b9a3db3606..dd1df605a1d6 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -208,30 +208,41 @@ void gpmi_dump_info(struct gpmi_nand_data *this) u32 reg; int i; - pr_err("Show GPMI registers :\n"); + dev_err(this->dev, "Show GPMI registers :\n"); for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { reg = readl(r->gpmi_regs + i * 0x10); - pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); } /* start to print out the BCH info */ - pr_err("Show BCH registers :\n"); + dev_err(this->dev, "Show BCH registers :\n"); for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) { reg = readl(r->bch_regs + i * 0x10); - pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); } - pr_err("BCH Geometry :\n"); - pr_err("GF length : %u\n", geo->gf_len); - pr_err("ECC Strength : %u\n", geo->ecc_strength); - pr_err("Page Size in Bytes : %u\n", geo->page_size); - pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); - pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); - pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); - pr_err("Payload Size in Bytes : %u\n", geo->payload_size); - pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); - pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); - pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); - pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); + dev_err(this->dev, "BCH Geometry :\n" + "GF length : %u\n" + "ECC Strength : %u\n" + "Page Size in Bytes : %u\n" + "Metadata Size in Bytes : %u\n" + "ECC Chunk Size in Bytes: %u\n" + "ECC Chunk Count : %u\n" + "Payload Size in Bytes : %u\n" + "Auxiliary Size in Bytes: %u\n" + "Auxiliary Status Offset: %u\n" + "Block Mark Byte Offset : %u\n" + "Block Mark Bit Offset : %u\n", + geo->gf_len, + geo->ecc_strength, + geo->page_size, + geo->metadata_size, + geo->ecc_chunk_size, + geo->ecc_chunk_count, + geo->payload_size, + geo->auxiliary_size, + geo->auxiliary_status_offset, + geo->block_mark_byte_offset, + geo->block_mark_bit_offset); } /* Configures the geometry for BCH. */ @@ -993,7 +1004,7 @@ void gpmi_begin(struct gpmi_nand_data *this) /* Enable the clock. */ ret = gpmi_enable_clk(this); if (ret) { - pr_err("We failed in enable the clk\n"); + dev_err(this->dev, "We failed in enable the clk\n"); goto err_out; } @@ -1097,7 +1108,7 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); reg = readl(r->gpmi_regs + HW_GPMI_STAT); } else - pr_err("unknow arch.\n"); + dev_err(this->dev, "unknow arch.\n"); return reg & mask; } diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 5617876728ad..46544edb1b2f 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -385,7 +385,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) - pr_err("DMA mapping failed.\n"); + dev_err(this->dev, "DMA mapping failed.\n"); this->direct_dma_map_ok = false; } @@ -419,7 +419,7 @@ static void dma_irq_callback(void *param) break; default: - pr_err("in wrong DMA operation.\n"); + dev_err(this->dev, "in wrong DMA operation.\n"); } complete(dma_c); @@ -441,7 +441,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the DMA block. */ err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "DMA timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -470,7 +471,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, /* Wait for the interrupt from the BCH block. */ err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); if (!err) { - pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + dev_err(this->dev, "BCH timeout, last DMA :%d\n", + this->last_dma_type); gpmi_dump_info(this); return -ETIMEDOUT; } @@ -495,7 +497,7 @@ static int acquire_register_block(struct gpmi_nand_data *this, else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) res->bch_regs = p; else - pr_err("unknown resource name : %s\n", res_name); + dev_err(this->dev, "unknown resource name : %s\n", res_name); return 0; } @@ -509,7 +511,7 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); if (!r) { - pr_err("Can't get resource for %s\n", res_name); + dev_err(this->dev, "Can't get resource for %s\n", res_name); return -ENODEV; } @@ -538,7 +540,7 @@ static int acquire_dma_channels(struct gpmi_nand_data *this) /* request dma channel */ dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx"); if (!dma_chan) { - pr_err("Failed to request DMA channel.\n"); + dev_err(this->dev, "Failed to request DMA channel.\n"); goto acquire_err; } @@ -681,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this, length, DMA_FROM_DEVICE); if (dma_mapping_error(dev, dest_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -732,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this, DMA_TO_DEVICE); if (dma_mapping_error(dev, source_phys)) { if (alt_size < length) { - pr_err("%s, Alternate buffer is too small\n", - __func__); + dev_err(dev, "Alternate buffer is too small\n"); return -ENOMEM; } goto map_failed; @@ -821,7 +821,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) error_alloc: gpmi_free_dma_buffer(this); - pr_err("Error allocating DMA buffers!\n"); return -ENOMEM; } @@ -853,7 +852,8 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) ret = gpmi_send_command(this); if (ret) - pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + dev_err(this->dev, "Chip: %u, Error %d\n", + this->current_chip, ret); this->command_length = 0; } @@ -981,7 +981,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate DMA buffer\n"); + dev_err(this->dev, "Inadequate DMA buffer\n"); ret = -ENOMEM; return ret; } @@ -995,7 +995,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, payload_virt, payload_phys); if (ret) { - pr_err("Error in ECC-based read: %d\n", ret); + dev_err(this->dev, "Error in ECC-based read: %d\n", ret); return ret; } @@ -1081,7 +1081,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->payload_size, &payload_virt, &payload_phys); if (ret) { - pr_err("Inadequate payload DMA buffer\n"); + dev_err(this->dev, "Inadequate payload DMA buffer\n"); return 0; } @@ -1091,7 +1091,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, nfc_geo->auxiliary_size, &auxiliary_virt, &auxiliary_phys); if (ret) { - pr_err("Inadequate auxiliary DMA buffer\n"); + dev_err(this->dev, "Inadequate auxiliary DMA buffer\n"); goto exit_auxiliary; } } @@ -1099,7 +1099,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, /* Ask the NFC. */ ret = gpmi_send_page(this, payload_phys, auxiliary_phys); if (ret) - pr_err("Error in ECC-based write: %d\n", ret); + dev_err(this->dev, "Error in ECC-based write: %d\n", ret); if (!this->swap_block_mark) { send_page_end(this, chip->oob_poi, mtd->oobsize, @@ -1516,7 +1516,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this) /* Set up the NFC geometry which is used by BCH. */ ret = bch_set_geometry(this); if (ret) { - pr_err("Error setting BCH geometry : %d\n", ret); + dev_err(this->dev, "Error setting BCH geometry : %d\n", ret); return ret; } @@ -1666,15 +1666,13 @@ static int gpmi_nand_probe(struct platform_device *pdev) if (of_id) { pdev->id_entry = of_id->data; } else { - pr_err("Failed to find the right device id.\n"); + dev_err(&pdev->dev, "Failed to find the right device id.\n"); return -ENODEV; } this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL); - if (!this) { - pr_err("Failed to allocate per-device memory\n"); + if (!this) return -ENOMEM; - } platform_set_drvdata(pdev, this); this->pdev = pdev; -- cgit v1.2.3 From c23259627c7f60646ac772d159baaf71796eefac Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 20 Nov 2013 10:09:44 +0800 Subject: mtd: gpmi: change pr_debug to dev_dbg change all the pr_debug to dev_dbg. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 46544edb1b2f..e2f58207c779 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -18,9 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -884,7 +881,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = buf; this->upper_len = len; @@ -896,7 +893,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) struct nand_chip *chip = mtd->priv; struct gpmi_nand_data *this = chip->priv; - pr_debug("len is %d\n", len); + dev_dbg(this->dev, "len is %d\n", len); this->upper_buf = (uint8_t *)buf; this->upper_len = len; @@ -975,7 +972,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, unsigned int max_bitflips = 0; int ret; - pr_debug("page number is : %d\n", page); + dev_dbg(this->dev, "page number is : %d\n", page); ret = read_page_prepare(this, buf, mtd->writesize, this->payload_virt, this->payload_phys, nfc_geo->payload_size, @@ -1051,7 +1048,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip, dma_addr_t auxiliary_phys; int ret; - pr_debug("ecc write page.\n"); + dev_dbg(this->dev, "ecc write page.\n"); if (this->swap_block_mark) { /* * If control arrives here, we're doing block mark swapping. @@ -1189,7 +1186,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, { struct gpmi_nand_data *this = chip->priv; - pr_debug("page number is %d\n", page); + dev_dbg(this->dev, "page number is %d\n", page); /* clear the OOB buffer */ memset(chip->oob_poi, ~0, mtd->oobsize); -- cgit v1.2.3 From afc62baf107355715beaf982513db3355867b29b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 25 Sep 2013 15:40:38 +0800 Subject: mtd: mpc5121_nfc: drop devm_free_irq of devm_ allocated irq The devm_request_irq function allocates irq that is released when a driver detaches. Thus, there is no reason to explicitly call devm_free_irq in probe or remove functions. Signed-off-by: Wei Yongjun Signed-off-by: Brian Norris --- drivers/mtd/nand/mpc5121_nfc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 439bc3896418..d744cf798978 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -786,7 +786,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) /* Detect NAND chips */ if (nand_scan(mtd, be32_to_cpup(chips_no))) { dev_err(dev, "NAND Flash not found !\n"); - devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; goto error; } @@ -811,7 +810,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) default: dev_err(dev, "Unsupported NAND flash!\n"); - devm_free_irq(dev, prv->irq, mtd); retval = -ENXIO; goto error; } @@ -822,7 +820,6 @@ static int mpc5121_nfc_probe(struct platform_device *op) retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (retval) { dev_err(dev, "Error adding MTD device!\n"); - devm_free_irq(dev, prv->irq, mtd); goto error; } @@ -836,11 +833,8 @@ static int mpc5121_nfc_remove(struct platform_device *op) { struct device *dev = &op->dev; struct mtd_info *mtd = dev_get_drvdata(dev); - struct nand_chip *chip = mtd->priv; - struct mpc5121_nfc_prv *prv = chip->priv; nand_release(mtd); - devm_free_irq(dev, prv->irq, mtd); mpc5121_nfc_free(dev, mtd); return 0; -- cgit v1.2.3 From 1ba80c9e08a6d17ac495d8e6a1acd3d0f6a7971b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Mon, 25 Nov 2013 12:24:22 +0900 Subject: mtd: dataflash: remove unnecessary spi_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/devices/mtd_dataflash.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 4a47b0266d4e..624069de4f28 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, if (!err) return 0; - spi_set_drvdata(spi, NULL); kfree(priv); return err; } @@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi) pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); - if (status == 0) { - spi_set_drvdata(spi, NULL); + if (status == 0) kfree(flash); - } return status; } -- cgit v1.2.3 From 0566477762f9e174e97af347ee9c865f908a5647 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 29 Nov 2013 14:14:29 +0100 Subject: mtd: mxc_nand: remove duplicated ecc_stats counting The ecc_stats.corrected count variable will already be incremented in the above framework-layer just after this callback. Cc: stable@vger.kernel.org # 2.6.36+ Signed-off-by: Michael Grzeschik Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 9dfdb06c508b..a4bad1165c2a 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -677,7 +677,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, ecc_stat >>= 4; } while (--no_subpages); - mtd->ecc_stats.corrected += ret; pr_debug("%d Symbol Correctable RS-ECC Error\n", ret); return ret; -- cgit v1.2.3 From dcedf628f55ccdb34c8783a03bed9382bb5e1a82 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 2 Dec 2013 00:50:02 -0200 Subject: mtd: nand: mxc_nand: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so let's check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a4bad1165c2a..7a4e032f6c7c 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1511,7 +1511,9 @@ static int mxcnd_probe(struct platform_device *pdev) if (err) return err; - clk_prepare_enable(host->clk); + err = clk_prepare_enable(host->clk); + if (err) + return err; host->clk_act = 1; /* -- cgit v1.2.3 From 574926c5bc3d787bb0b935b99d8825b3199ba76b Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Mon, 11 Nov 2013 22:55:29 +0200 Subject: mtd: m25p80: add support for m25px16 Add support for Micron m25px16 spi flash chip. Signed-off-by: Igor Grinberg Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7dc2c147720a..7b976e869636 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -998,6 +998,7 @@ static const struct spi_device_id m25p_ids[] = { { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, -- cgit v1.2.3 From 54c738f694ab67a007a43482d1dd7cf956fbb6c3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 2 Dec 2013 10:12:25 +0800 Subject: mtd: convert to use ATTRIBUTE_GROUPS Use new ATTRIBUTE_GROUPS macro to declare attribute groups. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/mtdcore.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 92311a56939f..34c0b16aed5c 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -313,15 +313,7 @@ static struct attribute *mtd_attrs[] = { &dev_attr_bitflip_threshold.attr, NULL, }; - -static struct attribute_group mtd_group = { - .attrs = mtd_attrs, -}; - -static const struct attribute_group *mtd_groups[] = { - &mtd_group, - NULL, -}; +ATTRIBUTE_GROUPS(mtd); static struct device_type mtd_devtype = { .name = "mtd", -- cgit v1.2.3 From 7e8eb8ae6618a82e598fe11ac01839d0bc4a5520 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 2 Dec 2013 00:30:27 -0200 Subject: mtd: tests: mtd_nandecctest: Use IS_ENABLED() macro Using the IS_ENABLED() macro can make the code shorter and simpler. Signed-off-by: Fabio Estevam Signed-off-by: Brian Norris --- drivers/mtd/tests/mtd_nandecctest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index 70106607c247..e579f9027c47 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -19,7 +19,7 @@ * or detected. */ -#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE) +#if IS_ENABLED(CONFIG_MTD_NAND) struct nand_ecc_test { const char *name; -- cgit v1.2.3 From 20171642ed064815fd4372e9e8b1fedff79148f1 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 25 Nov 2013 08:30:31 -0300 Subject: mtd: nand: refactor print messages Add a nice "nand:" prefix to all pr_xxx() messages. This allows to get rid of the "NAND" words in messages, given the context is already given by the prefix. Remove the __func__ report from messages where it's not needed and refactor the device detection messages to show itself in several lines. Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bd39f7b67906..9b3bb3c519e9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -29,6 +29,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -2979,7 +2981,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 10; if (!chip->onfi_version) { - pr_info("%s: unsupported ONFI version: %d\n", __func__, val); + pr_info("unsupported ONFI version: %d\n", val); return 0; } @@ -3372,8 +3374,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - pr_info("%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, + pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -3440,10 +3441,10 @@ ident_done: * Check, if buswidth is correct. Hardware drivers should set * chip correct! */ - pr_info("NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - pr_warn("NAND bus width %d instead %d bit\n", + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); return ERR_PTR(-EINVAL); @@ -3472,14 +3473,13 @@ ident_done: if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n", - *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, + pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", + *maf_id, *dev_id); + pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name); - - pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n", + pr_info("%dMiB, %s, page size: %d, OOB size: %d\n", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->writesize, mtd->oobsize); - return type; } @@ -3535,7 +3535,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->select_chip(mtd, -1); } if (i > 1) - pr_info("%d NAND chips detected\n", i); + pr_info("%d chips detected\n", i); /* Store the number of chips and calc total size for mtd */ chip->numchips = i; -- cgit v1.2.3 From cf3b2b1e24998ba67ca6defa71899bee2432046f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Dec 2013 18:59:15 +0800 Subject: mtd: make deregister_mtd_parser return void deregister_mtd_parser never fails; hence make it return void. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/mtdpart.c | 3 +-- include/linux/mtd/partitions.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 67a89bb45943..29ee91e6a70f 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -682,12 +682,11 @@ int register_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(register_mtd_parser); -int deregister_mtd_parser(struct mtd_part_parser *p) +void deregister_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_del(&p->list); spin_unlock(&part_parser_lock); - return 0; } EXPORT_SYMBOL_GPL(deregister_mtd_parser); diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 335ffca10c10..d513ffbd8043 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -77,7 +77,7 @@ struct mtd_part_parser { }; extern int register_mtd_parser(struct mtd_part_parser *parser); -extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern void deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, const char *name, -- cgit v1.2.3 From 6e14a61d412eb87ef7bdcec8b08a95bead771a78 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 Dec 2013 19:01:06 +0800 Subject: mtd: make register_mtd_parser return void register_mtd_parser never fails; hence make it return void. Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/afs.c | 3 ++- drivers/mtd/ar7part.c | 3 ++- drivers/mtd/bcm47xxpart.c | 3 ++- drivers/mtd/bcm63xxpart.c | 3 ++- drivers/mtd/cmdlinepart.c | 3 ++- drivers/mtd/mtdpart.c | 4 +--- drivers/mtd/ofpart.c | 15 +++------------ drivers/mtd/redboot.c | 3 ++- include/linux/mtd/partitions.h | 2 +- 9 files changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 5a3942bf109c..96a33e3f7b00 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = { static int __init afs_parser_init(void) { - return register_mtd_parser(&afs_parser); + register_mtd_parser(&afs_parser); + return 0; } static void __exit afs_parser_exit(void) diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index ddc0a4287a4b..7c9172ad2621 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = { static int __init ar7_parser_init(void) { - return register_mtd_parser(&ar7_parser); + register_mtd_parser(&ar7_parser); + return 0; } static void __exit ar7_parser_exit(void) diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 7a6384b0962a..931746ded989 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -243,7 +243,8 @@ static struct mtd_part_parser bcm47xxpart_mtd_parser = { static int __init bcm47xxpart_init(void) { - return register_mtd_parser(&bcm47xxpart_mtd_parser); + register_mtd_parser(&bcm47xxpart_mtd_parser); + return 0; } static void __exit bcm47xxpart_exit(void) diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index 5c813907661c..b2443f7031c9 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = { static int __init bcm63xx_cfe_parser_init(void) { - return register_mtd_parser(&bcm63xx_cfe_parser); + register_mtd_parser(&bcm63xx_cfe_parser); + return 0; } static void __exit bcm63xx_cfe_parser_exit(void) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 721caebbc5cc..3e829b37af8d 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void) { if (mtdparts) mtdpart_setup(mtdparts); - return register_mtd_parser(&cmdline_parser); + register_mtd_parser(&cmdline_parser); + return 0; } static void __exit cmdline_parser_exit(void) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 29ee91e6a70f..3c7d6d7623c1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -672,13 +672,11 @@ static struct mtd_part_parser *get_partition_parser(const char *name) #define put_partition_parser(p) do { module_put((p)->owner); } while (0) -int register_mtd_parser(struct mtd_part_parser *p) +void register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); - - return 0; } EXPORT_SYMBOL_GPL(register_mtd_parser); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index f0a708bf9b0e..aa26c32e1bc2 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = { static int __init ofpart_parser_init(void) { - int rc; - rc = register_mtd_parser(&ofpart_parser); - if (rc) - goto out; - - rc = register_mtd_parser(&ofoldpart_parser); - if (!rc) - return 0; - - deregister_mtd_parser(&ofoldpart_parser); -out: - return rc; + register_mtd_parser(&ofpart_parser); + register_mtd_parser(&ofoldpart_parser); + return 0; } static void __exit ofpart_parser_exit(void) diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 580035c803d6..5da911ebdf49 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot"); static int __init redboot_parser_init(void) { - return register_mtd_parser(&redboot_parser); + register_mtd_parser(&redboot_parser); + return 0; } static void __exit redboot_parser_exit(void) diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index d513ffbd8043..6a35e6de5da1 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -76,7 +76,7 @@ struct mtd_part_parser { struct mtd_part_parser_data *); }; -extern int register_mtd_parser(struct mtd_part_parser *parser); +extern void register_mtd_parser(struct mtd_part_parser *parser); extern void deregister_mtd_parser(struct mtd_part_parser *parser); int mtd_is_partition(const struct mtd_info *mtd); -- cgit v1.2.3 From 6bcda8a71080b8fa35e07a3339b2d79ebcfa4c33 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 27 Nov 2013 02:18:31 +0100 Subject: mtd: sh_flctl: enable driver compilation with COMPILE_TEST This helps increasing build testing coverage. Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Laurent Pinchart Acked-by: Simon Horman Signed-off-by: Brian Norris --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 691f5a05ecf3..a7808e6d4c71 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -458,7 +458,7 @@ config MTD_NAND_MXC config MTD_NAND_SH_FLCTL tristate "Support for NAND on Renesas SuperH FLCTL" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help Several Renesas SuperH CPU has FLCTL. This option enables support for NAND Flash using FLCTL. -- cgit v1.2.3 From 82ae816e160c6d349784daa03800006090d38fd0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 27 Nov 2013 11:17:28 +0100 Subject: mtd: sh_flctl: fix warnings due to improper casts Cast pointers to uintptr_t instead of unsigned int. This fixes warnings on platforms where pointers have a different size than int. Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Laurent Pinchart Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index a3c84ebbe392..0f135cbaed89 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -151,7 +151,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) dma_cap_set(DMA_SLAVE, mask); flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_fifo0_tx); + (void *)(uintptr_t)pdata->slave_id_fifo0_tx); dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__, flctl->chan_fifo0_tx); @@ -168,7 +168,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) goto err; flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_fifo0_rx); + (void *)(uintptr_t)pdata->slave_id_fifo0_rx); dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__, flctl->chan_fifo0_rx); -- cgit v1.2.3 From f7b5e849d516e3955715689678602ac55b952e2a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 27 Nov 2013 11:27:44 +0100 Subject: mtd: sh_flctl: use devm_* managed allocators This simplifies error and cleanup code paths. Cc: David Woodhouse Cc: linux-mtd@lists.infradead.org Signed-off-by: Laurent Pinchart Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 0f135cbaed89..50f1cb93324f 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1094,38 +1094,32 @@ static int flctl_probe(struct platform_device *pdev) struct mtd_info *flctl_mtd; struct nand_chip *nand; struct sh_flctl_platform_data *pdata; - int ret = -ENXIO; + int ret; int irq; struct mtd_part_parser_data ppdata = {}; - flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL); + flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL); if (!flctl) { dev_err(&pdev->dev, "failed to allocate driver data\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - goto err_iomap; - } - - flctl->reg = ioremap(res->start, resource_size(res)); - if (flctl->reg == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - goto err_iomap; - } + flctl->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(flctl->reg)) + return PTR_ERR(flctl->reg); irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "failed to get flste irq data\n"); - goto err_flste; + return -ENXIO; } - ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl); + ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED, + "flste", flctl); if (ret) { dev_err(&pdev->dev, "request interrupt failed.\n"); - goto err_flste; + return ret; } if (pdev->dev.of_node) @@ -1135,8 +1129,7 @@ static int flctl_probe(struct platform_device *pdev) if (!pdata) { dev_err(&pdev->dev, "no setup data defined\n"); - ret = -EINVAL; - goto err_pdata; + return -EINVAL; } platform_set_drvdata(pdev, flctl); @@ -1190,12 +1183,6 @@ static int flctl_probe(struct platform_device *pdev) err_chip: flctl_release_dma(flctl); pm_runtime_disable(&pdev->dev); -err_pdata: - free_irq(irq, flctl); -err_flste: - iounmap(flctl->reg); -err_iomap: - kfree(flctl); return ret; } @@ -1206,9 +1193,6 @@ static int flctl_remove(struct platform_device *pdev) flctl_release_dma(flctl); nand_release(&flctl->mtd); pm_runtime_disable(&pdev->dev); - free_irq(platform_get_irq(pdev, 0), flctl); - iounmap(flctl->reg); - kfree(flctl); return 0; } -- cgit v1.2.3 From 94f7039a360be982b97c06a78d9666ac1b5aaaf6 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 3 Dec 2013 08:18:28 +0900 Subject: mtd: denali: remove DEFINE_PCI_DEVICE_TABLE macro Don't use DEFINE_PCI_DEVICE_TABLE macro, because this macro is not preferred. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/denali_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 033f177a6369..622dfb7eba66 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -21,7 +21,7 @@ #define DENALI_NAND_NAME "denali-nand-pci" /* List of platforms this NAND controller has be integrated into */ -static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = { +static const struct pci_device_id denali_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 }, { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST }, { /* end: all zeroes */ } -- cgit v1.2.3 From 0d681560176ef94b6b2aaa39e3e935662cffc6e6 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Sat, 7 Dec 2013 11:31:01 -0300 Subject: mtd: nand: sh_flctl: Remove unneeded CONFIG_OF Since the of_mtd header provides dummy stubs for !CONFIG_OF, it's safe to remove the #ifdef CONFIG_OF. Build tested only. Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 50f1cb93324f..1940bd127d2d 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1021,7 +1021,6 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_OF struct flctl_soc_config { unsigned long flcmncr_val; unsigned has_hwecc:1; @@ -1080,12 +1079,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) return pdata; } -#else /* CONFIG_OF */ -static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) -{ - return NULL; -} -#endif /* CONFIG_OF */ static int flctl_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 8bfd4f7f18050535892b74e6ec3aa2ca598c6a64 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 17 Dec 2013 11:35:35 +0800 Subject: mtd: mxc_nand: add missing clk_disable_unprepare() in mxcnd_remove() clock source is prepared and enabled by clk_prepare_enable() in mxcnd_probe() function, but no disable/unprepare in mxcnd_remove(). Signed-off-by: Wei Yongjun Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 7a4e032f6c7c..567a5e56660c 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1577,6 +1577,8 @@ static int mxcnd_remove(struct platform_device *pdev) struct mxc_nand_host *host = platform_get_drvdata(pdev); nand_release(&host->mtd); + if (host->clk_act) + clk_disable_unprepare(host->clk); return 0; } -- cgit v1.2.3 From a1d7994e639c33926405448c50831d0b3e28dddc Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 11 Nov 2013 14:18:29 +0800 Subject: mtd: au1550nd: add missing platform_set_drvdata() Add missing platform_set_drvdata() in au1550nd_probe(), otherwise calling platform_get_drvdata() in remove returns NULL. Signed-off-by: Wei Yongjun Signed-off-by: Brian Norris --- drivers/mtd/nand/au1550nd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index ae8dd7c41039..909b6738ece2 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -480,6 +480,8 @@ static int au1550nd_probe(struct platform_device *pdev) mtd_device_register(&ctx->info, pd->parts, pd->num_parts); + platform_set_drvdata(pdev, ctx); + return 0; out3: -- cgit v1.2.3 From eaaa4a9af3f553dd07e1a21bbf857933ec9032f0 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:33:50 +0200 Subject: mtd: nand: davinci: fix driver registration When kernel is booted using DT, there is no guarantee that Davinci NAND device has been created already at the time when driver init function is executed. Therefore, platform_driver_probe() can't be used because this may result the Davinci NAND driver will never be probed. The driver probing has to be made with core mechanism. Acked-by: Santosh Shilimkar Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index b77a01efb483..584c1f4b6fce 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -487,7 +487,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd) * ten ECC bytes plus the manufacturer's bad block marker byte, and * and not overlapping the default BBT markers. */ -static struct nand_ecclayout hwecc4_small __initconst = { +static struct nand_ecclayout hwecc4_small = { .eccbytes = 10, .eccpos = { 0, 1, 2, 3, 4, /* offset 5 holds the badblock marker */ @@ -503,7 +503,7 @@ static struct nand_ecclayout hwecc4_small __initconst = { * storing ten ECC bytes plus the manufacturer's bad block marker byte, * and not overlapping the default BBT markers. */ -static struct nand_ecclayout hwecc4_2048 __initconst = { +static struct nand_ecclayout hwecc4_2048 = { .eccbytes = 40, .eccpos = { /* at the end of spare sector */ @@ -585,7 +585,7 @@ static struct davinci_nand_pdata } #endif -static int __init nand_davinci_probe(struct platform_device *pdev) +static int nand_davinci_probe(struct platform_device *pdev) { struct davinci_nand_pdata *pdata; struct davinci_nand_info *info; @@ -860,7 +860,7 @@ err_nomem: return ret; } -static int __exit nand_davinci_remove(struct platform_device *pdev) +static int nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); @@ -877,7 +877,8 @@ static int __exit nand_davinci_remove(struct platform_device *pdev) } static struct platform_driver nand_davinci_driver = { - .remove = __exit_p(nand_davinci_remove), + .probe = nand_davinci_probe, + .remove = nand_davinci_remove, .driver = { .name = "davinci_nand", .owner = THIS_MODULE, @@ -886,7 +887,7 @@ static struct platform_driver nand_davinci_driver = { }; MODULE_ALIAS("platform:davinci_nand"); -module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe); +module_platform_driver(nand_davinci_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Texas Instruments"); -- cgit v1.2.3 From f735a4d0d5b76c6035f30749c4e0aa64b3a9a74e Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:36:05 +0200 Subject: mtd: nand: davinci: return ENOMEM if memory allocation is failed In case when memory allocation is failed the driver should return ENOMEM instead of ENODEV. Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 584c1f4b6fce..4577fb41c0c7 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -541,7 +541,7 @@ static struct davinci_nand_pdata GFP_KERNEL); pdev->dev.platform_data = pdata; if (!pdata) - return NULL; + return ERR_PTR(-ENOMEM); if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-chipselect", &prop)) pdev->id = prop; @@ -598,6 +598,9 @@ static int nand_davinci_probe(struct platform_device *pdev) nand_ecc_modes_t ecc_mode; pdata = nand_davinci_get_pdata(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + /* insist on board-specific configuration */ if (!pdata) return -ENODEV; -- cgit v1.2.3 From 05103825fc1ef9a60a45ecf95db2b60c6e09be9a Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:36:44 +0200 Subject: mtd: nand: davinci: check required ti,davinci-chipselect property The property "ti,davinci-chipselect" is required. So we have to check if it is set. Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 4577fb41c0c7..9eea26953871 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -545,6 +545,9 @@ static struct davinci_nand_pdata if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-chipselect", &prop)) pdev->id = prop; + else + return ERR_PTR(-EINVAL); + if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-mask-ale", &prop)) pdata->mask_ale = prop; -- cgit v1.2.3 From 30a3970cde5be1e2950946f2e943fb84d07938fc Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:37:00 +0200 Subject: mtd: nand: davinci: simplify error handling There is not needed to use a lot of names for err handling. It complicates code support and reading. Acked-by: Santosh Shilimkar Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 46 +++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 9eea26953871..e6757b3a33b1 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -615,8 +615,7 @@ static int nand_davinci_probe(struct platform_device *pdev) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) { dev_err(&pdev->dev, "unable to allocate memory\n"); - ret = -ENOMEM; - goto err_nomem; + return -ENOMEM; } platform_set_drvdata(pdev, info); @@ -625,20 +624,16 @@ static int nand_davinci_probe(struct platform_device *pdev) res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res1 || !res2) { dev_err(&pdev->dev, "resource missing\n"); - ret = -EINVAL; - goto err_nomem; + return -EINVAL; } vaddr = devm_ioremap_resource(&pdev->dev, res1); - if (IS_ERR(vaddr)) { - ret = PTR_ERR(vaddr); - goto err_ioremap; - } + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + base = devm_ioremap_resource(&pdev->dev, res2); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto err_ioremap; - } + if (IS_ERR(base)) + return PTR_ERR(base); info->dev = &pdev->dev; info->base = base; @@ -705,7 +700,7 @@ static int nand_davinci_probe(struct platform_device *pdev) spin_unlock_irq(&davinci_nand_lock); if (ret == -EBUSY) - goto err_ecc; + return ret; info->chip.ecc.calculate = nand_davinci_calculate_4bit; info->chip.ecc.correct = nand_davinci_correct_4bit; @@ -721,8 +716,7 @@ static int nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.strength = pdata->ecc_bits; break; default: - ret = -EINVAL; - goto err_ecc; + return -EINVAL; } info->chip.ecc.mode = ecc_mode; @@ -730,7 +724,7 @@ static int nand_davinci_probe(struct platform_device *pdev) if (IS_ERR(info->clk)) { ret = PTR_ERR(info->clk); dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret); - goto err_clk; + return ret; } ret = clk_prepare_enable(info->clk); @@ -759,7 +753,7 @@ static int nand_davinci_probe(struct platform_device *pdev) info->core_chipsel); if (ret < 0) { dev_dbg(&pdev->dev, "NAND timing values setup fail\n"); - goto err_timing; + goto err; } spin_lock_irq(&davinci_nand_lock); @@ -775,7 +769,7 @@ static int nand_davinci_probe(struct platform_device *pdev) ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL); if (ret < 0) { dev_dbg(&pdev->dev, "no NAND chip(s) found\n"); - goto err_scan; + goto err; } /* Update ECC layout if needed ... for 1-bit HW ECC, the default @@ -789,7 +783,7 @@ static int nand_davinci_probe(struct platform_device *pdev) if (!chunks || info->mtd.oobsize < 16) { dev_dbg(&pdev->dev, "too small\n"); ret = -EINVAL; - goto err_scan; + goto err; } /* For small page chips, preserve the manufacturer's @@ -820,7 +814,7 @@ static int nand_davinci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "no 4-bit ECC support yet " "for 4KiB-page NAND\n"); ret = -EIO; - goto err_scan; + goto err; syndrome_done: info->chip.ecc.layout = &info->ecclayout; @@ -828,7 +822,7 @@ syndrome_done: ret = nand_scan_tail(&info->mtd); if (ret < 0) - goto err_scan; + goto err; if (pdata->parts) ret = mtd_device_parse_register(&info->mtd, NULL, NULL, @@ -841,7 +835,7 @@ syndrome_done: NULL, 0); } if (ret < 0) - goto err_scan; + goto err; val = davinci_nand_readl(info, NRCSR_OFFSET); dev_info(&pdev->dev, "controller rev. %d.%d\n", @@ -849,8 +843,7 @@ syndrome_done: return 0; -err_scan: -err_timing: +err: clk_disable_unprepare(info->clk); err_clk_enable: @@ -858,11 +851,6 @@ err_clk_enable: if (ecc_mode == NAND_ECC_HW_SYNDROME) ecc4_busy = false; spin_unlock_irq(&davinci_nand_lock); - -err_ecc: -err_clk: -err_ioremap: -err_nomem: return ret; } -- cgit v1.2.3 From 75be1ea26b7153a8e09b02e26655a4d7daf3627e Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:37:56 +0200 Subject: mtd: nand: davinci: adjust DT properties to MTD generic The properties davinci-ecc-mode, davinci-nand-use-bbt, davinci-nand-buswidth are MTD generic. Correct names for them are: nand-ecc-mode, nand-on-flash-bbt, nand-bus-width accordingly. So rename them in dts and documentation. Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- .../devicetree/bindings/mtd/davinci-nand.txt | 25 +++++++++++++++++----- drivers/mtd/nand/davinci_nand.c | 14 ++++++++---- 2 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers/mtd') diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt index d2a3fc020023..befaa5bb84e5 100644 --- a/Documentation/devicetree/bindings/mtd/davinci-nand.txt +++ b/Documentation/devicetree/bindings/mtd/davinci-nand.txt @@ -37,7 +37,7 @@ Recommended properties : - ti,davinci-mask-chipsel: mask for chipselect address. Needed to mask addresses for given chipselect. -- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode +- nand-ecc-mode: operation mode of the NAND ecc mode. ECC mode valid values for davinci driver: - "none" - "soft" @@ -45,10 +45,25 @@ Recommended properties : - ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. -- ti,davinci-nand-buswidth: buswidth 8 or 16. +- nand-bus-width: buswidth 8 or 16. If not present 8. + +- nand-on-flash-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Deprecated properties: + +- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-nand-buswidth: buswidth 8 or 16. If not present 8. - ti,davinci-nand-use-bbt: use flash based bad block table support. OOB - identifier is saved in OOB area. + identifier is saved in OOB area. If not present + false. Nand device bindings may contain additional sub-nodes describing partitions of the address space. See partition.txt for more detail. The NAND Flash timing @@ -66,9 +81,9 @@ nand_cs3@62000000 { ti,davinci-mask-ale = <0>; ti,davinci-mask-cle = <0>; ti,davinci-mask-chipsel = <0>; - ti,davinci-ecc-mode = "hw"; + nand-ecc-mode = "hw"; ti,davinci-ecc-bits = <4>; - ti,davinci-nand-use-bbt; + nand-on-flash-bbt; partition@180000 { label = "ubifs"; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index e6757b3a33b1..8a61a40f2ca9 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -534,7 +535,6 @@ static struct davinci_nand_pdata struct davinci_nand_pdata *pdata; const char *mode; u32 prop; - int len; pdata = devm_kzalloc(&pdev->dev, sizeof(struct davinci_nand_pdata), @@ -558,6 +558,8 @@ static struct davinci_nand_pdata "ti,davinci-mask-chipsel", &prop)) pdata->mask_chipsel = prop; if (!of_property_read_string(pdev->dev.of_node, + "nand-ecc-mode", &mode) || + !of_property_read_string(pdev->dev.of_node, "ti,davinci-ecc-mode", &mode)) { if (!strncmp("none", mode, 4)) pdata->ecc_mode = NAND_ECC_NONE; @@ -569,12 +571,16 @@ static struct davinci_nand_pdata if (!of_property_read_u32(pdev->dev.of_node, "ti,davinci-ecc-bits", &prop)) pdata->ecc_bits = prop; - if (!of_property_read_u32(pdev->dev.of_node, + + prop = of_get_nand_bus_width(pdev->dev.of_node); + if (0 < prop || !of_property_read_u32(pdev->dev.of_node, "ti,davinci-nand-buswidth", &prop)) if (prop == 16) pdata->options |= NAND_BUSWIDTH_16; - if (of_find_property(pdev->dev.of_node, - "ti,davinci-nand-use-bbt", &len)) + if (of_property_read_bool(pdev->dev.of_node, + "nand-on-flash-bbt") || + of_property_read_bool(pdev->dev.of_node, + "ti,davinci-nand-use-bbt")) pdata->bbt_options = NAND_BBT_USE_FLASH; } -- cgit v1.2.3 From 458f3933bb8a72c2c4a2751009152d83ac71c23b Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:38:12 +0200 Subject: mtd: nand: davinci: reuse driver for Keystone arch The Keystone arch has compatible nand device, so reuse it. In case with Keystone it depends on TI_AEMIF because AEMIF driver is responsible to set timings. See http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- Documentation/devicetree/bindings/mtd/davinci-nand.txt | 8 +++++--- drivers/mtd/nand/Kconfig | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/mtd') diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt index befaa5bb84e5..cfb18abe6001 100644 --- a/Documentation/devicetree/bindings/mtd/davinci-nand.txt +++ b/Documentation/devicetree/bindings/mtd/davinci-nand.txt @@ -1,14 +1,16 @@ -Device tree bindings for Texas instruments Davinci NAND controller +Device tree bindings for Texas instruments Davinci/Keystone NAND controller -This file provides information, what the device node for the davinci NAND -interface contains. +This file provides information, what the device node for the davinci/keystone +NAND interface contains. Documentation: Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf Required properties: - compatible: "ti,davinci-nand" + "ti,keystone-nand" - reg: Contains 2 offset/length values: - offset and length for the access window. diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a7808e6d4c71..90ff447bf043 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -464,11 +464,11 @@ config MTD_NAND_SH_FLCTL for NAND Flash using FLCTL. config MTD_NAND_DAVINCI - tristate "Support NAND on DaVinci SoC" - depends on ARCH_DAVINCI + tristate "Support NAND on DaVinci/Keystone SoC" + depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) help Enable the driver for NAND flash chips on Texas Instruments - DaVinci processors. + DaVinci/Keystone processors. config MTD_NAND_TXX9NDFMC tristate "NAND Flash support for TXx9 SoC" -- cgit v1.2.3 From 0966a416d22bb5d4a5444e5a8eb0e0ae671826e6 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Tue, 17 Dec 2013 15:38:31 +0200 Subject: mtd: nand: davinci: don't request AEMIF address range The TI AEMIF driver registers are used to setup timings for each chip select. The same registers range is used to setup NAND settings. The AEMIF and NAND drivers not use the same registers in this range. In case with TI AEMIF driver, the memory address range is requested already by AEMIF, so we cannot request it twice, just ioremap. Acked-by: Santosh Shilimkar Reviewed-by: Grygorii Strashko Reviewed-by: Taras Kondratiuk Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8a61a40f2ca9..0104d262dc89 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -637,9 +637,17 @@ static int nand_davinci_probe(struct platform_device *pdev) if (IS_ERR(vaddr)) return PTR_ERR(vaddr); - base = devm_ioremap_resource(&pdev->dev, res2); - if (IS_ERR(base)) - return PTR_ERR(base); + /* + * This registers range is used to setup NAND settings. In case with + * TI AEMIF driver, the same memory address range is requested already + * by AEMIF, so we cannot request it twice, just ioremap. + * The AEMIF and NAND drivers not use the same registers in this range. + */ + base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2)); + if (!base) { + dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2); + return -EADDRNOTAVAIL; + } info->dev = &pdev->dev; info->base = base; -- cgit v1.2.3 From 5e41d0a7102cfd43a3f0e178d37f2e9654f2fd50 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 16 Dec 2013 20:50:32 -0800 Subject: mtd: nand: lpc32xx_mlc: drop custom write_page callback This driver doesn't need its own custom chip->write_page callback; the only "custom" requirement is that this driver does not support subpage writes, which we can avoid using the NAND_NO_SUBPAGE_WRITE flag. With NAND_NO_SUBPAGE_WRITE, the default routine (nand_write_page()) should perform the equivalent operations. Signed-off-by: Brian Norris Acked-by: Roland Stigge Tested-by: Roland Stigge --- drivers/mtd/nand/lpc32xx_mlc.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 327d96c03505..48be85039a89 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -539,20 +539,6 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd, return 0; } -static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int cached, int raw) -{ - int res; - - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); - res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required); - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); - lpc32xx_waitfunc(mtd, chip); - - return res; -} - static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { @@ -732,9 +718,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) nand_chip->ecc.write_oob = lpc32xx_write_oob; nand_chip->ecc.read_oob = lpc32xx_read_oob; nand_chip->ecc.strength = 4; - nand_chip->write_page = lpc32xx_write_page; nand_chip->waitfunc = lpc32xx_waitfunc; + nand_chip->options = NAND_NO_SUBPAGE_WRITE; nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB; nand_chip->bbt_td = &lpc32xx_nand_bbt; nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror; -- cgit v1.2.3 From 176e4a233f50da75306df8ae1360d0ecbbeb8a37 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Fri, 13 Dec 2013 12:44:07 +0530 Subject: mtd: lpddr: Mark functions as static and remove unused function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch marks the functions do_write_buffer() and do_erase_oneblock() as static because because they are not used outside this file. It also removes the unused function word_program() in lpddr/lpddr_cmds.c. Thus, it also removes the following warnings in lpddr/lpddr_cmds.c: drivers/mtd/lpddr/lpddr_cmds.c:391:5: warning: no previous prototype for ‘do_write_buffer’ [-Wmissing-prototypes] drivers/mtd/lpddr/lpddr_cmds.c:472:5: warning: no previous prototype for ‘do_erase_oneblock’ [-Wmissing-prototypes] drivers/mtd/lpddr/lpddr_cmds.c:751:5: warning: no previous prototype for ‘word_program’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Brian Norris --- drivers/mtd/lpddr/lpddr_cmds.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 2ef19aa0086b..d38b6460d505 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -388,7 +388,7 @@ static void put_chip(struct map_info *map, struct flchip *chip) wake_up(&chip->wq); } -int do_write_buffer(struct map_info *map, struct flchip *chip, +static int do_write_buffer(struct map_info *map, struct flchip *chip, unsigned long adr, const struct kvec **pvec, unsigned long *pvec_seek, int len) { @@ -469,7 +469,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip, return ret; } -int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) +static int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) { struct map_info *map = mtd->priv; struct lpddr_private *lpddr = map->fldrv_priv; @@ -748,34 +748,6 @@ static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK); } -int word_program(struct map_info *map, loff_t adr, uint32_t curval) -{ - int ret; - struct lpddr_private *lpddr = map->fldrv_priv; - int chipnum = adr >> lpddr->chipshift; - struct flchip *chip = &lpddr->chips[chipnum]; - - mutex_lock(&chip->mutex); - ret = get_chip(map, chip, FL_WRITING); - if (ret) { - mutex_unlock(&chip->mutex); - return ret; - } - - send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval); - - ret = wait_for_ready(map, chip, (1<qinfo->SingleWordProgTime)); - if (ret) { - printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n", - map->name, adr, curval); - goto out; - } - -out: put_chip(map, chip); - mutex_unlock(&chip->mutex); - return ret; -} - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexey Korolev "); MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); -- cgit v1.2.3 From 919193cee04f49628ae9efdc45bf4af1e506205f Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Fri, 13 Dec 2013 12:46:04 +0530 Subject: mtd: denali: Mark function is_erased() as static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch marks the function is_erased() as static in denali.c because it is not used outside this file. This patch elimiates the following warning in nand/denali.c: drivers/mtd/nand/denali.c:900:6: warning: no previous prototype for ‘is_erased’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Brian Norris --- drivers/mtd/nand/denali.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 370b9dd7a278..3a3a47f60d28 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -897,7 +897,7 @@ 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 * indicate that the buffer is part of an erased region of flash. */ -bool is_erased(uint8_t *buf, int len) +static bool is_erased(uint8_t *buf, int len) { int i = 0; for (i = 0; i < len; i++) -- cgit v1.2.3 From d20d0a6cf75ba60cac5d00f9a4c2caabf611c51e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 18 Dec 2013 18:44:08 -0300 Subject: mtd: nand: pxa3xx: Clear need_wait flag when starting a command Currently the driver assumes all commands will eventually trigger a RnB transition, and thus a "device is ready" IRQ. This assumption means that on every issued command, the dev_ready completion handler is init'ed and the need_wait flag is set. However this is incorrect: some commands (such as NAND_CMD_STATUS) don't make the device 'busy' and thus a RnB transition never occurs. Given, the NAND core never calls waitfunc() after such commands, this is not a problem. Therefore, it's possible to only clear the need_wait flag on every command that is started. This fixes a current bug that can be reproduced on PXA boards by writing blank (all 0xff'ed) to a page: 1. The kernel issues NAND_CMD_STATUS and sets need_wait=1. The flag won't be cleared for this command since no RnB transition is involved. 2. NAND_CMD_PAGEPROG is issued but since the data is blank, the driver decides not to execute the command (and no IRQ activity is involved). 3. The NAND core calls waitfunc() and waits for the dev_ready completion, which will never end since the device _is_ already ready. Tested-by: Arnaud Ebalard Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 8f38abdb3310..982803372185 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -690,6 +690,7 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command) info->retcode = ERR_NONE; info->ecc_err_cnt = 0; info->ndcb3 = 0; + info->need_wait = 0; switch (command) { case NAND_CMD_READ0: -- cgit v1.2.3 From 5cbbdc6a9f8830737e099aca12794eb907f96882 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 18 Dec 2013 18:44:09 -0300 Subject: mtd: nand: pxa3xx: Use extended cmdfunc() only if needed Currently, we have two different cmdfunc's implementations: one for PXA3xx SoC variant and one for Armada 370/XP SoC variant. The former is the legacy one, typically constrained to devices with page sizes smaller or equal to the controller's FIFO buffer. On the other side, the latter _only_ supports the so-called extended command semantics, which allow to handle devices with larger page sizes (4 KiB, 8 KiB, ...). This means we currently don't support devices with smaller pages on the A370/XP SoC. Fix it by first renaming the cmdfuncs variants, and then make the choice based on device page size (and SoC variant), rather than SoC variant alone. While at it, add a check for page size, to make sure we don't allow larger pages sizes on the PXA3xx variant. Tested-by: Arnaud Ebalard Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 982803372185..f722ba70aaac 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -897,8 +897,8 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command, return exec_cmd; } -static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; @@ -945,9 +945,9 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->state = STATE_IDLE; } -static void armada370_nand_cmdfunc(struct mtd_info *mtd, - const unsigned command, - int column, int page_addr) +static void nand_cmdfunc_extended(struct mtd_info *mtd, + const unsigned command, + int column, int page_addr) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; @@ -1487,6 +1487,21 @@ KEEP_CONFIG: chip->bbt_md = &bbt_mirror_descr; } + /* + * If the page size is bigger than the FIFO size, let's check + * we are given the right variant and then switch to the extended + * (aka splitted) command handling, + */ + if (mtd->writesize > PAGE_CHUNK_SIZE) { + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) { + chip->cmdfunc = nand_cmdfunc_extended; + } else { + dev_err(&info->pdev->dev, + "unsupported page size on this variant\n"); + return -ENODEV; + } + } + if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) ret = armada370_ecc_init(info, &chip->ecc, chip->ecc_strength_ds, @@ -1566,11 +1581,7 @@ static int alloc_nand_resource(struct platform_device *pdev) chip->read_buf = pxa3xx_nand_read_buf; chip->write_buf = pxa3xx_nand_write_buf; chip->options |= NAND_NO_SUBPAGE_WRITE; - - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) - chip->cmdfunc = armada370_nand_cmdfunc; - else - chip->cmdfunc = pxa3xx_nand_cmdfunc; + chip->cmdfunc = nand_cmdfunc; } spin_lock_init(&chip->controller->lock); -- cgit v1.2.3 From 30b2afc8471ea06a6d18b9f6bc183dafb99de1f9 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Wed, 18 Dec 2013 18:44:10 -0300 Subject: mtd: nand: pxa3xx: Consolidate ECC initialization In order to avoid code duplication, let's consolidate the ECC setting for all SoC variants. Such decision is based on page size and ECC strength requirements. Also, provide a default value for the case where such ECC information is not provided (non-ONFI devices). Tested-by: Arnaud Ebalard Signed-off-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f722ba70aaac..0599a880e347 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1332,13 +1332,9 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) static int pxa_ecc_init(struct pxa3xx_nand_info *info, struct nand_ecc_ctrl *ecc, - int strength, int page_size) + int strength, int ecc_stepsize, int page_size) { - /* - * We don't use strength here as the PXA variant - * is used with non-ONFI compliant devices. - */ - if (page_size == 2048) { + if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) { info->chunk_size = 2048; info->spare_size = 40; info->ecc_size = 24; @@ -1347,7 +1343,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->strength = 1; return 1; - } else if (page_size == 512) { + } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) { info->chunk_size = 512; info->spare_size = 8; info->ecc_size = 8; @@ -1355,19 +1351,12 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = 512; ecc->strength = 1; return 1; - } - return 0; -} -static int armada370_ecc_init(struct pxa3xx_nand_info *info, - struct nand_ecc_ctrl *ecc, - int strength, int ecc_stepsize, int page_size) -{ /* * Required ECC: 4-bit correction per 512 bytes * Select: 16-bit correction per 2048 bytes */ - if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->chunk_size = 2048; info->spare_size = 32; @@ -1408,6 +1397,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) uint32_t id = -1; uint64_t chipsize; int i, ret, num; + uint16_t ecc_strength, ecc_step; if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) goto KEEP_CONFIG; @@ -1502,15 +1492,17 @@ KEEP_CONFIG: } } - if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) - ret = armada370_ecc_init(info, &chip->ecc, - chip->ecc_strength_ds, - chip->ecc_step_ds, - mtd->writesize); - else - ret = pxa_ecc_init(info, &chip->ecc, - chip->ecc_strength_ds, - mtd->writesize); + ecc_strength = chip->ecc_strength_ds; + ecc_step = chip->ecc_step_ds; + + /* Set default ECC strength requirements on non-ONFI devices */ + if (ecc_strength < 1 && ecc_step < 1) { + ecc_strength = 1; + ecc_step = 512; + } + + ret = pxa_ecc_init(info, &chip->ecc, ecc_strength, + ecc_step, mtd->writesize); if (!ret) { dev_err(&info->pdev->dev, "ECC strength %d at page size %d is not supported\n", -- cgit v1.2.3 From 82402aeb8c81edab9249b9e330b21e88723f539e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:40:52 +0900 Subject: mtd: docg3: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/devices/docg3.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 4f091c1a9981..dd5e1018d37b 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev) ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ress) { dev_err(dev, "No I/O memory resource defined\n"); - goto noress; + return ret; } - base = ioremap(ress->start, DOC_IOSPACE_SIZE); + base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, - GFP_KERNEL); + cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, + GFP_KERNEL); if (!cascade) - goto nomem1; + return ret; cascade->base = base; mutex_init(&cascade->lock); cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, DOC_ECC_BCH_PRIMPOLY); if (!cascade->bch) - goto nomem2; + return ret; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { mtd = doc_probe_device(cascade, floor, dev); @@ -2101,11 +2101,6 @@ err_probe: for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); -nomem2: - kfree(cascade); -nomem1: - iounmap(base); -noress: return ret; } @@ -2119,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev) { struct docg3_cascade *cascade = platform_get_drvdata(pdev); struct docg3 *docg3 = cascade->floors[0]->priv; - void __iomem *base = cascade->base; int floor; doc_unregister_sysfs(pdev, cascade); @@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev) doc_release_device(cascade->floors[floor]); free_bch(docg3->cascade->bch); - kfree(cascade); - iounmap(base); return 0; } -- cgit v1.2.3 From 436bf63ba5792f2f7bb5e1a4e8d38df8f1a44edc Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:42:34 +0900 Subject: mtd: lantiq-flash: Use devm_kzalloc() Use devm_kzalloc() to make cleanup paths simpler. Also, checking return value of devm_kzalloc() is added in order to check if the allocation succeded. Signed-off-by: Jingoo Han Acked-by: John Crispin Signed-off-by: Brian Norris --- drivers/mtd/maps/lantiq-flash.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index d7ac65d1d569..93c507a6f862 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -123,24 +123,28 @@ ltq_mtd_probe(struct platform_device *pdev) return -ENODEV; } - ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); + ltq_mtd = devm_kzalloc(&pdev->dev, sizeof(struct ltq_mtd), GFP_KERNEL); + if (!ltq_mtd) + return -ENOMEM; + platform_set_drvdata(pdev, ltq_mtd); ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ltq_mtd->res) { dev_err(&pdev->dev, "failed to get memory resource\n"); - err = -ENOENT; - goto err_out; + return -ENOENT; } - ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); + ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info), + GFP_KERNEL); + if (!ltq_mtd->map) + return -ENOMEM; + ltq_mtd->map->phys = ltq_mtd->res->start; ltq_mtd->map->size = resource_size(ltq_mtd->res); ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res); - if (IS_ERR(ltq_mtd->map->virt)) { - err = PTR_ERR(ltq_mtd->map->virt); - goto err_out; - } + if (IS_ERR(ltq_mtd->map->virt)) + return PTR_ERR(ltq_mtd->map->virt); ltq_mtd->map->name = ltq_map_name; ltq_mtd->map->bankwidth = 2; @@ -155,8 +159,7 @@ ltq_mtd_probe(struct platform_device *pdev) if (!ltq_mtd->mtd) { dev_err(&pdev->dev, "probing failed\n"); - err = -ENXIO; - goto err_free; + return -ENXIO; } ltq_mtd->mtd->owner = THIS_MODULE; @@ -177,10 +180,6 @@ ltq_mtd_probe(struct platform_device *pdev) err_destroy: map_destroy(ltq_mtd->mtd); -err_free: - kfree(ltq_mtd->map); -err_out: - kfree(ltq_mtd); return err; } @@ -189,13 +188,9 @@ ltq_mtd_remove(struct platform_device *pdev) { struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); - if (ltq_mtd) { - if (ltq_mtd->mtd) { - mtd_device_unregister(ltq_mtd->mtd); - map_destroy(ltq_mtd->mtd); - } - kfree(ltq_mtd->map); - kfree(ltq_mtd); + if (ltq_mtd && ltq_mtd->mtd) { + mtd_device_unregister(ltq_mtd->mtd); + map_destroy(ltq_mtd->mtd); } return 0; } -- cgit v1.2.3 From 2281f7b63ed0a7e230a34303c0e9e8f0264fda6c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:43:11 +0900 Subject: mtd: denali_dt: Use devm_clk_get() Use devm_clk_get() to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/denali_dt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 92530244e2cb..babb02c4b220 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -108,7 +108,7 @@ static int denali_dt_probe(struct platform_device *ofdev) denali->dev->dma_mask = NULL; } - dt->clk = clk_get(&ofdev->dev, NULL); + dt->clk = devm_clk_get(&ofdev->dev, NULL); if (IS_ERR(dt->clk)) { dev_err(&ofdev->dev, "no clk available\n"); return PTR_ERR(dt->clk); @@ -124,7 +124,6 @@ static int denali_dt_probe(struct platform_device *ofdev) out_disable_clk: clk_disable_unprepare(dt->clk); - clk_put(dt->clk); return ret; } @@ -135,7 +134,6 @@ static int denali_dt_remove(struct platform_device *ofdev) denali_remove(&dt->denali); clk_disable(dt->clk); - clk_put(dt->clk); return 0; } -- cgit v1.2.3 From 133432a7e2b848ada53910df16c420d297e5c65a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:44:30 +0900 Subject: mtd: lpc32xx_slc: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Acked-by: Roland Stigge Signed-off-by: Brian Norris --- drivers/mtd/nand/lpc32xx_slc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 23e6974ccd20..5f2039446bf0 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -791,8 +791,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) } if (host->ncfg->wp_gpio == -EPROBE_DEFER) return -EPROBE_DEFER; - if (gpio_is_valid(host->ncfg->wp_gpio) && - gpio_request(host->ncfg->wp_gpio, "NAND WP")) { + if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev, + host->ncfg->wp_gpio, "NAND WP")) { dev_err(&pdev->dev, "GPIO not available\n"); return -EBUSY; } @@ -808,7 +808,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) mtd->dev.parent = &pdev->dev; /* Get NAND clock */ - host->clk = clk_get(&pdev->dev, NULL); + host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { dev_err(&pdev->dev, "Clock failure\n"); res = -ENOENT; @@ -927,10 +927,8 @@ err_exit3: dma_release_channel(host->dma_chan); err_exit2: clk_disable(host->clk); - clk_put(host->clk); err_exit1: lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); return res; } @@ -953,9 +951,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) writel(tmp, SLC_CTRL(host->io_base)); clk_disable(host->clk); - clk_put(host->clk); lpc32xx_wp_enable(host); - gpio_free(host->ncfg->wp_gpio); return 0; } -- cgit v1.2.3 From e8009ca0360954f5bd3db5b2128a11ce0e994ab9 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:44:59 +0900 Subject: mtd: nuc900_nand: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/nuc900_nand.c | 55 ++++++++++-------------------------------- 1 file changed, 13 insertions(+), 42 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 52115151e4a7..661fd1417000 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -241,12 +241,10 @@ static int nuc900_nand_probe(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand; struct nand_chip *chip; - int retval; struct resource *res; - retval = 0; - - nuc900_nand = kzalloc(sizeof(struct nuc900_nand), GFP_KERNEL); + nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand), + GFP_KERNEL); if (!nuc900_nand) return -ENOMEM; chip = &(nuc900_nand->chip); @@ -255,11 +253,9 @@ static int nuc900_nand_probe(struct platform_device *pdev) nuc900_nand->mtd.owner = THIS_MODULE; spin_lock_init(&nuc900_nand->lock); - nuc900_nand->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(nuc900_nand->clk)) { - retval = -ENOENT; - goto fail1; - } + nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(nuc900_nand->clk)) + return -ENOENT; clk_enable(nuc900_nand->clk); chip->cmdfunc = nuc900_nand_command_lp; @@ -272,57 +268,32 @@ static int nuc900_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_SOFT; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENXIO; - goto fail1; - } + if (!res) + return -ENXIO; - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - retval = -EBUSY; - goto fail1; - } - - nuc900_nand->reg = ioremap(res->start, resource_size(res)); - if (!nuc900_nand->reg) { - retval = -ENOMEM; - goto fail2; - } + nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nuc900_nand->reg)) + return PTR_ERR(nuc900_nand->reg); nuc900_nand_enable(nuc900_nand); - if (nand_scan(&(nuc900_nand->mtd), 1)) { - retval = -ENXIO; - goto fail3; - } + if (nand_scan(&(nuc900_nand->mtd), 1)) + return -ENXIO; mtd_device_register(&(nuc900_nand->mtd), partitions, ARRAY_SIZE(partitions)); platform_set_drvdata(pdev, nuc900_nand); - return retval; - -fail3: iounmap(nuc900_nand->reg); -fail2: release_mem_region(res->start, resource_size(res)); -fail1: kfree(nuc900_nand); - return retval; + return 0; } static int nuc900_nand_remove(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); - struct resource *res; nand_release(&nuc900_nand->mtd); - iounmap(nuc900_nand->reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - clk_disable(nuc900_nand->clk); - clk_put(nuc900_nand->clk); - - kfree(nuc900_nand); return 0; } -- cgit v1.2.3 From 8f91fb681ec177fc2c2329c222a2ff4970381a23 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 10:45:55 +0900 Subject: mtd: tmio_nand: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/tmio_nand.c | 46 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 33 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index a3747c914d57..fb8fd35fa668 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -371,11 +371,9 @@ static int tmio_probe(struct platform_device *dev) if (data == NULL) dev_warn(&dev->dev, "NULL platform data!\n"); - tmio = kzalloc(sizeof *tmio, GFP_KERNEL); - if (!tmio) { - retval = -ENOMEM; - goto err_kzalloc; - } + tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL); + if (!tmio) + return -ENOMEM; tmio->dev = dev; @@ -385,22 +383,18 @@ static int tmio_probe(struct platform_device *dev) mtd->priv = nand_chip; mtd->name = "tmio-nand"; - tmio->ccr = ioremap(ccr->start, resource_size(ccr)); - if (!tmio->ccr) { - retval = -EIO; - goto err_iomap_ccr; - } + tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr)); + if (!tmio->ccr) + return -EIO; tmio->fcr_base = fcr->start & 0xfffff; - tmio->fcr = ioremap(fcr->start, resource_size(fcr)); - if (!tmio->fcr) { - retval = -EIO; - goto err_iomap_fcr; - } + tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr)); + if (!tmio->fcr) + return -EIO; retval = tmio_hw_init(dev, tmio); if (retval) - goto err_hwinit; + return retval; /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = tmio->fcr; @@ -428,7 +422,8 @@ static int tmio_probe(struct platform_device *dev) /* 15 us command delay time */ nand_chip->chip_delay = 15; - retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio); + retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0, + dev_name(&dev->dev), tmio); if (retval) { dev_err(&dev->dev, "request_irq error %d\n", retval); goto err_irq; @@ -440,7 +435,7 @@ static int tmio_probe(struct platform_device *dev) /* Scan to find existence of the device */ if (nand_scan(mtd, 1)) { retval = -ENODEV; - goto err_scan; + goto err_irq; } /* Register the partitions */ retval = mtd_device_parse_register(mtd, NULL, NULL, @@ -451,18 +446,8 @@ static int tmio_probe(struct platform_device *dev) nand_release(mtd); -err_scan: - if (tmio->irq) - free_irq(tmio->irq, tmio); err_irq: tmio_hw_stop(dev, tmio); -err_hwinit: - iounmap(tmio->fcr); -err_iomap_fcr: - iounmap(tmio->ccr); -err_iomap_ccr: - kfree(tmio); -err_kzalloc: return retval; } @@ -471,12 +456,7 @@ static int tmio_remove(struct platform_device *dev) struct tmio_nand *tmio = platform_get_drvdata(dev); nand_release(&tmio->mtd); - if (tmio->irq) - free_irq(tmio->irq, tmio); tmio_hw_stop(dev, tmio); - iounmap(tmio->fcr); - iounmap(tmio->ccr); - kfree(tmio); return 0; } -- cgit v1.2.3 From 9e3677a8134cb49fcc3e64974500c22f0ad7bb55 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:00:16 +0900 Subject: mtd: atmel_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 59f08c44abdb..e633c4454bad 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1961,10 +1961,8 @@ static int atmel_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n"); + if (!host) return -ENOMEM; - } res = platform_driver_register(&atmel_nand_nfc_driver); if (res) -- cgit v1.2.3 From 36cbcf85ebe30733fec2a1ccc61ed554fb7e051a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:00:58 +0900 Subject: mtd: orion_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/orion_nand.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index a393a5b6ce1e..a6a4a20f6069 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -87,7 +87,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); if (!nc) { - printk(KERN_ERR "orion_nand: failed to allocate device structure.\n"); ret = -ENOMEM; goto no_res; } @@ -110,7 +109,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data), GFP_KERNEL); if (!board) { - printk(KERN_ERR "orion_nand: failed to allocate board structure.\n"); ret = -ENOMEM; goto no_res; } -- cgit v1.2.3 From fc59a51e48010630507d8a0da6a1cf9ab23528bf Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:01:55 +0900 Subject: mtd: sharpsl: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/sharpsl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 87908d760feb..61a85abfdc41 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -121,10 +121,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Allocate memory for MTD device structure and private data */ sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); - if (!sharpsl) { - printk("Unable to allocate SharpSL NAND MTD device structure.\n"); + if (!sharpsl) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { -- cgit v1.2.3 From ce3737f047526f519985e175f07201d10b15c713 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:02:30 +0900 Subject: mtd: au1550nd: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/au1550nd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 909b6738ece2..2880d888cfc5 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -418,10 +418,8 @@ static int au1550nd_probe(struct platform_device *pdev) } ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - dev_err(&pdev->dev, "no memory for NAND context\n"); + if (!ctx) return -ENOMEM; - } r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { -- cgit v1.2.3 From aad075318333e09640bceec3db4e282ac440c625 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:04:18 +0900 Subject: mtd: bf5xx_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Mike Frysinger Signed-off-by: Brian Norris --- drivers/mtd/nand/bf5xx_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 2c42e125720f..94f55dbde995 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -745,7 +745,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev) info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto out_err_kzalloc; } -- cgit v1.2.3 From 9fd9e4cd1aa8c286e477ad13724a4eed9059fb7a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:04:58 +0900 Subject: mtd: cafe_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/cafe_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index c34985a55101..f2f64addb5e8 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -640,10 +640,8 @@ static int cafe_nand_probe(struct pci_dev *pdev, pci_set_master(pdev); mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL); - if (!mtd) { - dev_warn(&pdev->dev, "failed to alloc mtd_info\n"); + if (!mtd) return -ENOMEM; - } cafe = (void *)(&mtd[1]); mtd->dev.parent = &pdev->dev; -- cgit v1.2.3 From 4caab3ba593a6999070ecd5ba96ea7791444db29 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:06:00 +0900 Subject: mtd: cmx270_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/cmx270_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 39b2ef848811..66ec95e6ca6c 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -164,7 +164,6 @@ static int __init cmx270_init(void) sizeof(struct nand_chip), GFP_KERNEL); if (!cmx270_nand_mtd) { - pr_debug("Unable to allocate CM-X270 NAND MTD device structure.\n"); ret = -ENOMEM; goto err_kzalloc; } -- cgit v1.2.3 From 1f4bd45a7e4238b154791c24c32d5619b2046531 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:06:46 +0900 Subject: mtd: cs553x_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/cs553x_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index d469a9a1dea0..88109d375ae7 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -199,7 +199,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Allocate memory for MTD device structure and private data */ new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); if (!new_mtd) { - printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n"); err = -ENOMEM; goto out; } -- cgit v1.2.3 From bf521a3b80060a666d41d70d06a1e150009a7805 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:07:20 +0900 Subject: mtd: diskonchip: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/diskonchip.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0afafa049ea1..fec31d71b84e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1058,7 +1058,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1))) @@ -1166,7 +1165,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti buf = kmalloc(mtd->writesize, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); return 0; } @@ -1564,7 +1562,6 @@ static int __init doc_probe(unsigned long physadr) sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr)); mtd = kzalloc(len, GFP_KERNEL); if (!mtd) { - printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); ret = -ENOMEM; goto fail; } -- cgit v1.2.3 From 3fc697cadf7d46258454a242d59926c94aa95e2d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:08:24 +0900 Subject: mtd: fsl_elbc_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/fsl_elbc_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index c966fc7474ce..d32f1d3b52f7 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -847,7 +847,6 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) if (!fsl_lbc_ctrl_dev->nand) { elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL); if (!elbc_fcm_ctrl) { - dev_err(dev, "failed to allocate memory\n"); mutex_unlock(&fsl_elbc_nand_mutex); ret = -ENOMEM; goto err; -- cgit v1.2.3 From 95cdd5a48abb6edb4611a4bbcc4b7657d505456f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:09:19 +0900 Subject: mtd: fsl_ifc_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/fsl_ifc_nand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 43355779cff5..33440803cf62 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -1060,7 +1060,6 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) if (!fsl_ifc_ctrl_dev->nand) { ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); if (!ifc_nand_ctrl) { - dev_err(&dev->dev, "failed to allocate memory\n"); mutex_unlock(&fsl_ifc_nand_mutex); return -ENOMEM; } -- cgit v1.2.3 From 51b37b8a72eff5982948eb4d840a40d9b9f55bed Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:09:47 +0900 Subject: mtd: jz4740_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/jz4740_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index a264b888c66c..a2c804de156b 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -416,10 +416,8 @@ static int jz_nand_probe(struct platform_device *pdev) uint8_t nand_maf_id = 0, nand_dev_id = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); - if (!nand) { - dev_err(&pdev->dev, "Failed to allocate device structure.\n"); + if (!nand) return -ENOMEM; - } ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); if (ret) -- cgit v1.2.3 From 844a72c5af0dc1e8f45f0beb8306b9b1887fe7c1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:12:03 +0900 Subject: mtd: txx9ndfmc: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/txx9ndfmc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 235714a421dd..c1622a5ba814 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -319,11 +319,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) continue; txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv), GFP_KERNEL); - if (!txx9_priv) { - dev_err(&dev->dev, "Unable to allocate " - "TXx9 NDFMC MTD device structure.\n"); + if (!txx9_priv) continue; - } chip = &txx9_priv->chip; mtd = &txx9_priv->mtd; mtd->owner = THIS_MODULE; -- cgit v1.2.3 From 006692319bf0362f053a9e8a56a1416611aaa116 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:13:59 +0900 Subject: mtd: davinci_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 0104d262dc89..a4989ec6292e 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -619,10 +619,8 @@ static int nand_davinci_probe(struct platform_device *pdev) return -ENODEV; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); - if (!info) { - dev_err(&pdev->dev, "unable to allocate memory\n"); + if (!info) return -ENOMEM; - } platform_set_drvdata(pdev, info); -- cgit v1.2.3 From d9a21ae8e5f3fe2d940f54e45386b35b98cbcc35 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:16:38 +0900 Subject: mtd: fsmc_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Linus Walleij Signed-off-by: Brian Norris --- drivers/mtd/nand/fsmc_nand.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 8b2752263db9..a5915f1172e6 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -889,10 +889,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, pdata->nand_timings = devm_kzalloc(&pdev->dev, sizeof(*pdata->nand_timings), GFP_KERNEL); - if (!pdata->nand_timings) { - dev_err(&pdev->dev, "no memory for nand_timing\n"); + if (!pdata->nand_timings) return -ENOMEM; - } of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, sizeof(*pdata->nand_timings)); @@ -950,10 +948,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure\n"); + if (!host) return -ENOMEM; - } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data"); host->data_va = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.2.3 From 24e9971d3d938f49ea03e0c76649a62894175b3f Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:17:42 +0900 Subject: mtd: nand-gpio: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/gpio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index e826f898241f..8dfdbb63e096 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -211,10 +211,8 @@ static int gpio_nand_probe(struct platform_device *pdev) return -EINVAL; gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL); - if (!gpiomtd) { - dev_err(&pdev->dev, "failed to create NAND MTD\n"); + if (!gpiomtd) return -ENOMEM; - } chip = &gpiomtd->nand_chip; -- cgit v1.2.3 From 3479c9dcefad0c88aa5e8b20c9462b6c170223bd Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:18:24 +0900 Subject: mtd: lpc32xx_mlc: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Roland Stigge Signed-off-by: Brian Norris --- drivers/mtd/nand/lpc32xx_mlc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 48be85039a89..687478c9f09c 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -613,10 +613,8 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev) struct device_node *np = dev->of_node; ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); - if (!ncfg) { - dev_err(dev, "could not allocate memory for platform data\n"); + if (!ncfg) return NULL; - } of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay); of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay); @@ -652,10 +650,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure.\n"); + if (!host) return -ENOMEM; - } rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->io_base = devm_ioremap_resource(&pdev->dev, rc); @@ -750,14 +746,12 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); if (!host->dma_buf) { - dev_err(&pdev->dev, "Error allocating dma_buf memory\n"); res = -ENOMEM; goto err_exit3; } host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); if (!host->dummy_buf) { - dev_err(&pdev->dev, "Error allocating dummy_buf memory\n"); res = -ENOMEM; goto err_exit3; } -- cgit v1.2.3 From 8ecb66ba39546f17d0338c3ba5ae56e9ffb3639c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:18:56 +0900 Subject: mtd: lpc32xx_slc: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Acked-by: Roland Stigge Signed-off-by: Brian Norris --- drivers/mtd/nand/lpc32xx_slc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 5f2039446bf0..53a6742e3da3 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -725,10 +725,8 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev) struct device_node *np = dev->of_node; ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL); - if (!ncfg) { - dev_err(dev, "could not allocate memory for NAND config\n"); + if (!ncfg) return NULL; - } of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks); of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth); @@ -772,10 +770,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(&pdev->dev, "failed to allocate device structure\n"); + if (!host) return -ENOMEM; - } host->io_base_dma = rc->start; host->io_base = devm_ioremap_resource(&pdev->dev, rc); @@ -858,7 +854,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len, GFP_KERNEL); if (host->data_buf == NULL) { - dev_err(&pdev->dev, "Error allocating memory\n"); res = -ENOMEM; goto err_exit2; } -- cgit v1.2.3 From 61a623fe0d451c3977bc9f5a56bbef76cee8818e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:19:55 +0900 Subject: mtd: mpc5121_nfc: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/mpc5121_nfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index d744cf798978..61e2abc216ad 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -653,10 +653,8 @@ static int mpc5121_nfc_probe(struct platform_device *op) } prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL); - if (!prv) { - dev_err(dev, "Memory exhausted!\n"); + if (!prv) return -ENOMEM; - } mtd = &prv->mtd; chip = &prv->chip; -- cgit v1.2.3 From ad745810070e013f8f66744dc31ab7c202881dec Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:21:39 +0900 Subject: mtd: s3c2410: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/s3c2410.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d65cbe903d40..47fbd9a2cacf 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -919,7 +919,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { - dev_err(&pdev->dev, "no memory for flash info\n"); err = -ENOMEM; goto exit_error; } @@ -974,7 +973,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) size = nr_sets * sizeof(*info->mtds); info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (info->mtds == NULL) { - dev_err(&pdev->dev, "failed to allocate mtd storage\n"); err = -ENOMEM; goto exit_error; } -- cgit v1.2.3 From b5d306c0349020a89322514ec010a9bf70d00b9b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:22:37 +0900 Subject: mtd: sh_flctl: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 1940bd127d2d..d72783dd7b96 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1058,10 +1058,8 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev) pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "%s: failed to allocate config data\n", __func__); + if (!pdata) return NULL; - } /* set SoC specific options */ pdata->flcmncr_val = config->flcmncr_val; @@ -1092,10 +1090,8 @@ static int flctl_probe(struct platform_device *pdev) struct mtd_part_parser_data ppdata = {}; flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL); - if (!flctl) { - dev_err(&pdev->dev, "failed to allocate driver data\n"); + if (!flctl) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); flctl->reg = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.2.3 From 1295f97002bd8c4fd7d927607dcd4657d4727d08 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:30:58 +0900 Subject: mtd: atmel_nand: use dev_err() instead of printk() Use dev_err() instead of printk() to provide a better message to userspace. Signed-off-by: Jingoo Han Acked-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e633c4454bad..c36e9b84487c 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -2060,14 +2060,14 @@ static int atmel_nand_probe(struct platform_device *pdev) } if (gpio_get_value(host->board.det_pin)) { - printk(KERN_INFO "No SmartMedia card inserted.\n"); + dev_info(&pdev->dev, "No SmartMedia card inserted.\n"); res = -ENXIO; goto err_no_card; } } if (host->board.on_flash_bbt || on_flash_bbt) { - printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); + dev_info(&pdev->dev, "Use On Flash BBT\n"); nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } -- cgit v1.2.3 From 67b19a631eb0a21584ff179f93c0dd93f94f8ce0 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:31:25 +0900 Subject: mtd: fsmc_nand: use dev_warn() instead of printk() Use dev_warn() instead of printk() to provide a better message to userspace. Signed-off-by: Jingoo Han Acked-by: Linus Walleij Signed-off-by: Brian Norris --- drivers/mtd/nand/fsmc_nand.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index a5915f1172e6..1550692973dc 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -1104,8 +1104,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) host->ecc_place = &fsmc_ecc4_lp_place; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } else { @@ -1120,8 +1120,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand->ecc.layout = &fsmc_ecc1_128_layout; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } -- cgit v1.2.3 From 4867d582d56a0cb7041779d781b98e548fb018e3 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:31:52 +0900 Subject: mtd: orion_nand: use dev_err() instead of printk() Use dev_err() instead of printk() to provide a better message to userspace. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/orion_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index a6a4a20f6069..dd7fe817eafb 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -100,7 +100,7 @@ static int __init orion_nand_probe(struct platform_device *pdev) io_base = ioremap(res->start, resource_size(res)); if (!io_base) { - printk(KERN_ERR "orion_nand: ioremap failed\n"); + dev_err(&pdev->dev, "ioremap failed\n"); ret = -EIO; goto no_res; } -- cgit v1.2.3 From bb13bec74efd279942f8cf53fc86fb671acc5d9d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 26 Dec 2013 12:32:29 +0900 Subject: mtd: sharpsl: use dev_err() instead of printk() Use dev_err() instead of printk() to provide a better message to userspace. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/sharpsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 61a85abfdc41..e81059b58382 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -134,7 +134,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* map physical address */ sharpsl->io = ioremap(r->start, resource_size(r)); if (!sharpsl->io) { - printk("ioremap to access Sharp SL NAND chip failed\n"); + dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n"); err = -EIO; goto err_ioremap; } -- cgit v1.2.3 From ed0b272ed25fb947af1cc71973b986be6dd19d04 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 3 Jan 2014 11:15:04 +0900 Subject: mtd: ixp4xx: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/maps/ixp4xx.c | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 10debfea81e7..d6b2451eab1d 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -13,6 +13,7 @@ * */ +#include #include #include #include @@ -162,13 +163,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev) mtd_device_unregister(info->mtd); map_destroy(info->mtd); } - if (info->map.virt) - iounmap(info->map.virt); - - if (info->res) { - release_resource(info->res); - kfree(info->res); - } if (plat->exit) plat->exit(); @@ -194,7 +188,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev) return err; } - info = kzalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL); + info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info), + GFP_KERNEL); if(!info) { err = -ENOMEM; goto Error; @@ -220,20 +215,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev) info->map.write = ixp4xx_probe_write16; info->map.copy_from = ixp4xx_copy_from; - info->res = request_mem_region(dev->resource->start, - resource_size(dev->resource), - "IXP4XXFlash"); - if (!info->res) { - printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n"); - err = -ENOMEM; - goto Error; - } - - info->map.virt = ioremap(dev->resource->start, - resource_size(dev->resource)); - if (!info->map.virt) { - printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n"); - err = -EIO; + info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource); + if (IS_ERR(info->map.virt)) { + err = PTR_ERR(info->map.virt); goto Error; } -- cgit v1.2.3 From ffdac7cd31d04f81a09f517f37c371c5f978efec Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 3 Jan 2014 11:16:28 +0900 Subject: mtd: plat_nand: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/plat_nand.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index cad4cdc9df39..d00e3a7c6bd8 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -9,6 +9,7 @@ * */ +#include #include #include #include @@ -52,25 +53,16 @@ static int plat_nand_probe(struct platform_device *pdev) return -ENXIO; /* Allocate memory for the device structure (and zero it) */ - data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data), + GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "failed to allocate device structure.\n"); return -ENOMEM; } - if (!request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto out_free; - } - - data->io_base = ioremap(res->start, resource_size(res)); - if (data->io_base == NULL) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -EIO; - goto out_release_io; - } + data->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->io_base)) + return PTR_ERR(data->io_base); data->chip.priv = &data; data->mtd.priv = &data->chip; @@ -122,11 +114,6 @@ static int plat_nand_probe(struct platform_device *pdev) out: if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); - iounmap(data->io_base); -out_release_io: - release_mem_region(res->start, resource_size(res)); -out_free: - kfree(data); return err; } @@ -137,16 +124,10 @@ static int plat_nand_remove(struct platform_device *pdev) { struct plat_nand_data *data = platform_get_drvdata(pdev); struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_release(&data->mtd); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); - iounmap(data->io_base); - release_mem_region(res->start, resource_size(res)); - kfree(data); return 0; } -- cgit v1.2.3 From a01eb2043b84bd6d595df58b7eba4f8841050b5e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 3 Jan 2014 11:17:29 +0900 Subject: mtd: plat_nand: Remove unnecessary OOM messages The site-specific OOM messages are unnecessary, because they duplicate the MM subsystem generic OOM message. Signed-off-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/plat_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index d00e3a7c6bd8..4ebed7273bc0 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -55,10 +55,8 @@ static int plat_nand_probe(struct platform_device *pdev) /* Allocate memory for the device structure (and zero it) */ data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data), GFP_KERNEL); - if (!data) { - dev_err(&pdev->dev, "failed to allocate device structure.\n"); + if (!data) return -ENOMEM; - } data->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(data->io_base)) -- cgit v1.2.3 From 103cdd8520b5ec85ab4345f54db5cc32a517f468 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 13 Dec 2013 21:19:58 -0800 Subject: mtd: nand-gpio: don't waste memory for OF failure We shouldn't try to allocate a resource until we're sure the of_property_read_u64() call didn't fail. This is especially important if we use this code for both CONFIG_OF and !CONFIG_OF builds, since of_property_read_u64() will always return -ENOSYS for !CONFIG_OF. Signed-off-by: Brian Norris --- drivers/mtd/nand/gpio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 8dfdbb63e096..8e6148aa4539 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -132,13 +132,17 @@ static int gpio_nand_get_config_of(const struct device *dev, static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) { - struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); + struct resource *r; u64 addr; - if (!r || of_property_read_u64(pdev->dev.of_node, + if (of_property_read_u64(pdev->dev.of_node, "gpio-control-nand,io-sync-reg", &addr)) return NULL; + r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); + if (!r) + return NULL; + r->start = addr; r->end = r->start + 0x3; r->flags = IORESOURCE_MEM; -- cgit v1.2.3 From cf0e4d2b3faf9494bb6bd32141c0dcfceced1746 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 30 Oct 2013 19:39:51 -0400 Subject: mtd: omap2: use nand_base defaults for polled I/O The omap_{read,write}_buf{8,16}() functions are identical to the default nand_base versions. Just let nand_base assign them in the NAND_OMAP_POLLED case. Signed-off-by: Brian Norris Tested-by: Pekon Gupta --- drivers/mtd/nand/omap2.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f77725009907..ef4190a02b7b 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1730,13 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev) break; case NAND_OMAP_POLLED: - if (nand_chip->options & NAND_BUSWIDTH_16) { - nand_chip->read_buf = omap_read_buf16; - nand_chip->write_buf = omap_write_buf16; - } else { - nand_chip->read_buf = omap_read_buf8; - nand_chip->write_buf = omap_write_buf8; - } + /* Use nand_base defaults for {read,write}_buf */ break; case NAND_OMAP_PREFETCH_DMA: -- cgit v1.2.3 From 8b3ae733534a153756f142a3e8573a1ae967cf8b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 20 Sep 2013 12:44:26 -0700 Subject: mtd: onenand: fix warning (integer used as pointer) Fixes this sparse warning: CHECK drivers/mtd/onenand/generic.c drivers/mtd/onenand/generic.c:61:62: warning: Using plain integer as NULL pointer Signed-off-by: Brian Norris --- drivers/mtd/onenand/generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 63699fffc96d..8e1919b6f074 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -58,7 +58,7 @@ static int generic_onenand_probe(struct platform_device *pdev) goto out_release_mem_region; } - info->onenand.mmcontrol = pdata ? pdata->mmcontrol : 0; + info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL; info->onenand.irq = platform_get_irq(pdev, 0); info->mtd.name = dev_name(&pdev->dev); -- cgit v1.2.3 From 7f11b4d411d0e1ac9217d8a0546f60e057540772 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 13 Dec 2013 10:58:44 -0300 Subject: mtd: Hide CONFIG_MTD_BLKDEVS from the menu Make this option a hidden one and get a cleaner configuration. This option just selects a common infrastructure for MTD-based devices to expose a block interface. There is no point in allowing a separate enable/disable. Signed-off-by: Ezequiel Garcia [Brian: keep symbol as tristate] Signed-off-by: Brian Norris --- drivers/mtd/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5fab4e6e8301..5ebcda39f554 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -157,10 +157,11 @@ config MTD_BCM47XX_PARTS comment "User Modules And Translation Layers" +# +# MTD block device support is select'ed if needed +# config MTD_BLKDEVS - tristate "Common interface to block layer for MTD 'translation layers'" - depends on BLOCK - default n + tristate config MTD_BLOCK tristate "Caching block device access to MTD devices" -- cgit v1.2.3 From 4f8aaf72287578c846ed7ac8c6114aacbf416e45 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sat, 21 Dec 2013 19:39:11 +0100 Subject: mtd: bcm47xxpart: find boot partition by CFE magic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices have even nicer-to-recognize CFE thanks to the magic. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/bcm47xxpart.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 931746ded989..877c17c7f5d3 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -23,10 +23,11 @@ * Amount of bytes we read when analyzing each block of flash memory. * Set it big enough to allow detecting partition and reading important data. */ -#define BCM47XXPART_BYTES_TO_READ 0x404 +#define BCM47XXPART_BYTES_TO_READ 0x4e8 /* Magics */ #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ +#define CFE_MAGIC 0x43464531 /* 1EFC */ #define FACTORY_MAGIC 0x59544346 /* FCTY */ #define POT_MAGIC1 0x54544f50 /* POTT */ #define POT_MAGIC2 0x504f /* OP */ @@ -102,8 +103,9 @@ static int bcm47xxpart_parse(struct mtd_info *master, continue; } - /* CFE has small NVRAM at 0x400 */ - if (buf[0x400 / 4] == NVRAM_HEADER) { + /* Magic or small NVRAM at 0x400 */ + if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) || + (buf[0x400 / 4] == NVRAM_HEADER)) { bcm47xxpart_add_part(&parts[curr_part++], "boot", offset, MTD_WRITEABLE); continue; -- cgit v1.2.3 From f0501e81fbaa51cfc8c28c60bc3fc7965fde94f4 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sat, 21 Dec 2013 19:39:12 +0100 Subject: mtd: bcm47xxpart: alternative MAGIC for board_data partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices (like WNDR3700v3) have board_data without MPFR magic, some extra header or extra NVRAM around 0x100. In such case we have to look for another magic which is BD 0B 0D BD (BD probably stands for Board Data). It's located "far far away", so instead of extending buffer add another mtd_read. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/bcm47xxpart.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 877c17c7f5d3..de1eb92e42f5 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -27,6 +27,7 @@ /* Magics */ #define BOARD_DATA_MAGIC 0x5246504D /* MPFR */ +#define BOARD_DATA_MAGIC2 0xBD0D0BBD #define CFE_MAGIC 0x43464531 /* 1EFC */ #define FACTORY_MAGIC 0x59544346 /* FCTY */ #define POT_MAGIC1 0x54544f50 /* POTT */ @@ -192,6 +193,21 @@ static int bcm47xxpart_parse(struct mtd_info *master, offset, 0); continue; } + + /* Read middle of the block */ + if (mtd_read(master, offset + 0x8000, 0x4, + &bytes_read, (uint8_t *)buf) < 0) { + pr_err("mtd_read error while parsing (offset: 0x%X)!\n", + offset); + continue; + } + + /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */ + if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) { + bcm47xxpart_add_part(&parts[curr_part++], "board_data", + offset, MTD_WRITEABLE); + continue; + } } /* Look for NVRAM at the end of the last block. */ -- cgit v1.2.3 From 88c305912db5d50e2b2568e22119b9ee3b56ad88 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 23 Dec 2013 13:54:56 -0800 Subject: mtd: denali: Drop print of build date/time The kernel already has this information, and individual drivers shouldn't duplicate that. This also eliminates the use of __DATE__ and __TIME__, which make the build non-deterministic. Signed-off-by: Josh Triplett Reviewed-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/denali_pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 622dfb7eba66..6e2f387b823f 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -131,7 +131,6 @@ static struct pci_driver denali_pci_driver = { static int denali_init_pci(void) { - pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__); return pci_register_driver(&denali_pci_driver); } module_init(denali_init_pci); -- cgit v1.2.3 From 3e77216c2acf063d4233c73fb3edc189142ae439 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 26 Dec 2013 11:48:34 +0530 Subject: mtd: onenand: Trivial cleanup in samsung.h commit 93115b7fa8f4 ("mtd: onenand/samsung: make regs-onenand.h file local") moved the file to the current location but forgot to remove the pointer to its previous location. Clean it up. Signed-off-by: Sachin Kamat Signed-off-by: Brian Norris --- drivers/mtd/onenand/samsung.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/onenand/samsung.h b/drivers/mtd/onenand/samsung.h index c4a80e67e438..9016dc0136a8 100644 --- a/drivers/mtd/onenand/samsung.h +++ b/drivers/mtd/onenand/samsung.h @@ -1,6 +1,4 @@ /* - * linux/arch/arm/plat-s3c/include/plat/regs-onenand.h - * * Copyright (C) 2008-2010 Samsung Electronics * Kyungmin Park * -- cgit v1.2.3 From 092b6a1dd0c82013f59c717b8f2ca057863183e3 Mon Sep 17 00:00:00 2001 From: Cai Zhiyong Date: Wed, 25 Dec 2013 21:19:21 +0800 Subject: mtd: nand: assign mtd->name in find_full_id_nand This patch assigned the type->name to mtd->name when mtd->name is NULL in function "find_full_id_nand". mtd->name is NULL may cause some problem. Signed-off-by: Cai Zhiyong Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9b3bb3c519e9..404e83d7e3da 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3327,6 +3327,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, *busw = type->options & NAND_BUSWIDTH_16; + if (!mtd->name) + mtd->name = type->name; + return true; } return false; -- cgit v1.2.3 From 2fec386a94bbe8a02d0669d9fcb32e6a69918d9f Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Sat, 28 Dec 2013 12:17:35 +0530 Subject: mtd: nand: Update mtd.name assignment type to u64 for IFC, eLBC mtd.name is assigned to IFC NAND physical address. Assignment type is u32. It is not providing correct physical address of IFC NAND. Update assignment type to u64. Signed-off-by: Prabhakar Kushwaha Signed-off-by: Brian Norris --- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/fsl_ifc_nand.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index d32f1d3b52f7..bcf60800c3ce 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -874,7 +874,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev) goto err; } - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 33440803cf62..90ca7e75d6f0 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -1100,7 +1100,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) IFC_NAND_EVTER_INTR_FTOERIR_EN | IFC_NAND_EVTER_INTR_WPERIR_EN, &ifc->ifc_nand.nand_evter_intr_en); - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); + priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!priv->mtd.name) { ret = -ENOMEM; goto err; -- cgit v1.2.3 From a5900554a8b5fbc4fb731c6f9896ed265683f94e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sat, 21 Dec 2013 00:02:27 +0800 Subject: mtd: mxc-nand: kill the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE We kill the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE by the following way: 1.) Before we call the nand_scan_ident, we allocate a temporary buffer whose size is PAGE_SIZE. 2.) After we finish the nand_scan_ident, we have already getten the page size and oob size. We will allocate the right buffer size again. Signed-off-by: Huang Shijie Reviewed-by: Josh Triplett Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 567a5e56660c..e9a4835c4dd9 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1399,12 +1399,15 @@ static int mxcnd_probe(struct platform_device *pdev) int err = 0; /* Allocate memory for MTD device structure and private data */ - host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) + - NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL); + host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host), + GFP_KERNEL); if (!host) return -ENOMEM; - host->data_buf = (uint8_t *)(host + 1); + /* allocate a temporary buffer for the nand_scan_ident() */ + host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!host->data_buf) + return -ENOMEM; host->dev = &pdev->dev; /* structures must be linked */ @@ -1532,6 +1535,15 @@ static int mxcnd_probe(struct platform_device *pdev) goto escan; } + /* allocate the right size buffer now */ + devm_kfree(&pdev->dev, (void *)host->data_buf); + host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize, + GFP_KERNEL); + if (!host->data_buf) { + err = -ENOMEM; + goto escan; + } + /* Call preset again, with correct writesize this time */ host->devtype_data->preset(mtd); -- cgit v1.2.3 From e07caa3687317e1c5a9efa0d315a2d7ca57f3df5 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Sat, 21 Dec 2013 00:02:28 +0800 Subject: mtd: denali: kill the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE This patch kills the NAND_MAX_PAGESIZE/NAND_MAX_OOBSIZE by the following way: 1.) change the @buf field of nand_buf{} from an array to a pointer. also remove the DENALI_BUF_SIZE macro. 2.) Before we call the nand_scan_ident, we allocate a temporary buffer whose size is PAGE_SIZE. 3.) After we finish the nand_scan_ident, we have already getten the page size and oob size. We will allocate the right buffer size again. Signed-off-by: Huang Shijie Reviewed-by: Josh Triplett Signed-off-by: Brian Norris --- drivers/mtd/nand/denali.c | 51 ++++++++++++++++++++++++++++------------------- drivers/mtd/nand/denali.h | 4 +--- 2 files changed, 31 insertions(+), 24 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3a3a47f60d28..c07cd573ad3a 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -125,7 +125,6 @@ static void reset_buf(struct denali_nand_info *denali) static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte) { - BUG_ON(denali->buf.tail >= sizeof(denali->buf.buf)); denali->buf.buf[denali->buf.tail++] = byte; } @@ -1429,20 +1428,12 @@ int denali_init(struct denali_nand_info *denali) } } - /* Is 32-bit DMA supported? */ - ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); - if (ret) { - pr_err("Spectra: no usable DMA configuration\n"); - return ret; - } - denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, - DENALI_BUF_SIZE, - DMA_BIDIRECTIONAL); + /* allocate a temporary buffer for nand_scan_ident() */ + denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE, + GFP_DMA | GFP_KERNEL); + if (!denali->buf.buf) + return -ENOMEM; - if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { - dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); - return -EIO; - } denali->mtd.dev.parent = denali->dev; denali_hw_init(denali); denali_drv_init(denali); @@ -1475,12 +1466,29 @@ int denali_init(struct denali_nand_info *denali) goto failed_req_irq; } - /* MTD supported page sizes vary by kernel. We validate our - * kernel supports the device here. - */ - if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) { - ret = -ENODEV; - pr_err("Spectra: device size not supported by this version of MTD."); + /* allocate the right size buffer now */ + devm_kfree(denali->dev, denali->buf.buf); + denali->buf.buf = devm_kzalloc(denali->dev, + denali->mtd.writesize + denali->mtd.oobsize, + GFP_KERNEL); + if (!denali->buf.buf) { + ret = -ENOMEM; + goto failed_req_irq; + } + + /* Is 32-bit DMA supported? */ + ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); + if (ret) { + pr_err("Spectra: no usable DMA configuration\n"); + goto failed_req_irq; + } + + denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf, + denali->mtd.writesize + denali->mtd.oobsize, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { + dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); + ret = -EIO; goto failed_req_irq; } @@ -1602,7 +1610,8 @@ EXPORT_SYMBOL(denali_init); void denali_remove(struct denali_nand_info *denali) { denali_irq_cleanup(denali->irq, denali); - dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE, + dma_unmap_single(denali->dev, denali->buf.dma_buf, + denali->mtd.writesize + denali->mtd.oobsize, DMA_BIDIRECTIONAL); } EXPORT_SYMBOL(denali_remove); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index cec5712862c9..966817462421 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -455,12 +455,10 @@ #define ECC_SECTOR_SIZE 512 -#define DENALI_BUF_SIZE (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) - struct nand_buf { int head; int tail; - uint8_t buf[DENALI_BUF_SIZE]; + uint8_t *buf; dma_addr_t dma_buf; }; -- cgit v1.2.3 From 1963ff97ca461fed4d9212e7e7b9c29715251342 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 24 Dec 2013 12:40:07 -0300 Subject: mtd: nand: pxa3xx: Add "armada370-nand" compatible Now that the driver can support the Armada 370/XP SoC NAND controller, add the devicetree compatible string, enabling its use. Signed-off-by: Ezequiel Garcia Acked-by: Jason Cooper Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 0599a880e347..31aae535a02a 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -333,6 +333,10 @@ static struct of_device_id pxa3xx_nand_dt_ids[] = { .compatible = "marvell,pxa3xx-nand", .data = (void *)PXA3XX_NAND_VARIANT_PXA, }, + { + .compatible = "marvell,armada370-nand", + .data = (void *)PXA3XX_NAND_VARIANT_ARMADA370, + }, {} }; MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids); -- cgit v1.2.3 From b72f3dfb8ccf7e39b9434f548c1c98aa45c11426 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 3 Dec 2013 11:04:14 -0800 Subject: mtd: nand: localize ECC failures per page ECC failures can be tracked at the page level, not the do_read_ops level (i.e., a potentially multi-page transaction). This helps prepare for READ RETRY support. Signed-off-by: Brian Norris Acked-by: Huang Shijie --- drivers/mtd/nand/nand_base.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 404e83d7e3da..b5c3768b32ae 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1422,7 +1422,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, { int chipnr, page, realpage, col, bytes, aligned, oob_required; struct nand_chip *chip = mtd->priv; - struct mtd_ecc_stats stats; int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; @@ -1431,8 +1430,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint8_t *bufpoi, *oob, *buf; unsigned int max_bitflips = 0; - - stats = mtd->ecc_stats; + bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); chip->select_chip(mtd, chipnr); @@ -1447,6 +1445,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, oob_required = oob ? 1 : 0; while (1) { + unsigned int ecc_failures = mtd->ecc_stats.failed; + bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); @@ -1483,7 +1483,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Transfer not aligned data */ if (!aligned) { if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed) && + !(mtd->ecc_stats.failed - ecc_failures) && (ops->mode != MTD_OPS_RAW)) { chip->pagebuf = realpage; chip->pagebuf_bitflips = ret; @@ -1513,6 +1513,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else nand_wait_ready(mtd); } + + if (mtd->ecc_stats.failed - ecc_failures) + ecc_fail = true; } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1547,7 +1550,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (ret < 0) return ret; - if (mtd->ecc_stats.failed - stats.failed) + if (ecc_fail) return -EBADMSG; return max_bitflips; -- cgit v1.2.3 From ba84fb5952af114e28ac82adcdef75297701ccc1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 3 Jan 2014 15:13:33 -0800 Subject: mtd: nand: add generic READ RETRY support Modern MLC (and even SLC?) NAND can experience a large number of bitflips (beyond the recommended correctability capacity) due to drifts in the voltage threshold (Vt). These bitflips can cause ECC errors to occur well within the expected lifetime of the flash. To account for this, some manufacturers provide a mechanism for shifting the Vt threshold after a corrupted read. The generic pattern seems to be that a particular flash has N read retry modes (where N = 0, traditionally), and after an ECC failure, the host should reconfigure the flash to use the next available mode, then retry the read operation. This process repeats until all bitfips can be corrected or until the host has tried all available retry modes. This patch adds the infrastructure support for a vendor-specific/flash-specific callback, used for setting the read-retry mode (i.e., voltage threshold). For now, this patch always returns the flash to mode 0 (the default mode) after a successful read-retry, according to the flowchart found in Micron's datasheets. This may need to change in the future if it is determined that eventually, mode 0 is insufficient for the majority of the flash cells (and so for performance reasons, we should leave the flash in mode 1, 2, etc.). Signed-off-by: Brian Norris Acked-by: Huang Shijie --- drivers/mtd/nand/nand_base.c | 56 ++++++++++++++++++++++++++++++++++++++++---- include/linux/mtd/nand.h | 6 +++++ 2 files changed, 58 insertions(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b5c3768b32ae..4c2f39f351da 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1409,6 +1409,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, return NULL; } +/** + * nand_setup_read_retry - [INTERN] Set the READ RETRY mode + * @mtd: MTD device structure + * @retry_mode: the retry mode to use + * + * Some vendors supply a special command to shift the Vt threshold, to be used + * when there are too many bitflips in a page (i.e., ECC error). After setting + * a new threshold, the host should retry reading the page. + */ +static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + + pr_debug("setting READ RETRY mode %d\n", retry_mode); + + if (retry_mode >= chip->read_retries) + return -EINVAL; + + if (!chip->setup_read_retry) + return -EOPNOTSUPP; + + return chip->setup_read_retry(mtd, retry_mode); +} + /** * nand_do_read_ops - [INTERN] Read data with ECC * @mtd: MTD device structure @@ -1430,6 +1454,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint8_t *bufpoi, *oob, *buf; unsigned int max_bitflips = 0; + int retry_mode = 0; bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); @@ -1454,6 +1479,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; +read_retry: chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* @@ -1494,8 +1520,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, memcpy(buf, chip->buffers->databuf + col, bytes); } - buf += bytes; - if (unlikely(oob)) { int toread = min(oobreadlen, max_oobsize); @@ -1514,8 +1538,24 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, nand_wait_ready(mtd); } - if (mtd->ecc_stats.failed - ecc_failures) - ecc_fail = true; + if (mtd->ecc_stats.failed - ecc_failures) { + if (retry_mode + 1 <= chip->read_retries) { + retry_mode++; + ret = nand_setup_read_retry(mtd, + retry_mode); + if (ret < 0) + break; + + /* Reset failures; retry */ + mtd->ecc_stats.failed = ecc_failures; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_fail = true; + } + } + + buf += bytes; } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1525,6 +1565,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, readlen -= bytes; + /* Reset to retry mode 0 */ + if (retry_mode) { + ret = nand_setup_read_retry(mtd, 0); + if (ret < 0) + break; + retry_mode = 0; + } + if (!readlen) break; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 029fe5948dc4..267d61dd89dd 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -472,6 +472,8 @@ struct nand_buffers { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. + * @setup_read_retry: [FLASHSPECIFIC] flash (vendor) specific function for + * setting the read-retry mode. Mostly needed for MLC NAND. * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure @@ -518,6 +520,7 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. + * @read_retries: [INTERN] the number of read retry modes supported * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand * @bbt: [INTERN] bad block table pointer @@ -565,6 +568,7 @@ struct nand_chip { int feature_addr, uint8_t *subfeature_para); int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, int feature_addr, uint8_t *subfeature_para); + int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode); int chip_delay; unsigned int options; @@ -589,6 +593,8 @@ struct nand_chip { int onfi_version; struct nand_onfi_params onfi_params; + int read_retries; + flstate_t state; uint8_t *oob_poi; -- cgit v1.2.3 From 8429bb3975ef81c114cde4da111e64d224d19f83 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 3 Dec 2013 15:51:09 -0800 Subject: mtd: nand: support Micron READ RETRY Micron provides READ RETRY support via the ONFI vendor-specific parameter block (to indicate how many read-retry modes are available) and the ONFI {GET,SET}_FEATURES commands with a vendor-specific feature address (to support reading/switching the current read-retry mode). The recommended sequence is as follows: 1. Perform PAGE_READ operation 2. If no ECC error, we are done 3. Run SET_FEATURES with feature address 89h, mode 1 4. Retry PAGE_READ operation 5. If ECC error and there are remaining supported modes, increment the mode and return to step 3. Otherwise, this is a true ECC error. 6. Run SET_FEATURES with feature address 89h, mode 0, to return to the default state. This patch implements the chip->setup_read_retry() callback for Micron and fills in the chip->read_retries. Tested on Micron MT29F32G08CBADA, which supports 8 read-retry modes. The Micron vendor-specific table was checked against the datasheets for the following Micron NAND: Needs retry Cell-type Part number Vendor revision Byte 180 ----------- --------- ---------------- --------------- ------------ No SLC MT29F16G08ABABA 1 Reserved (0) No MLC MT29F32G08CBABA 1 Reserved (0) No SLC MT29F1G08AACWP 1 0 Yes MLC MT29F32G08CBADA 1 08h Yes MLC MT29F64G08CBABA 2 08h Signed-off-by: Brian Norris Acked-by: Huang Shijie --- drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++++++++++ include/linux/mtd/nand.h | 3 +++ 2 files changed, 30 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 4c2f39f351da..b8c74cda7625 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2979,6 +2979,30 @@ ext_out: return ret; } +static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode) +{ + struct nand_chip *chip = mtd->priv; + uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode}; + + return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY, + feature); +} + +/* + * Configure chip properties from Micron vendor-specific ONFI table + */ +static void nand_onfi_detect_micron(struct nand_chip *chip, + struct nand_onfi_params *p) +{ + struct nand_onfi_vendor_micron *micron = (void *)p->vendor; + + if (le16_to_cpu(p->vendor_revision) < 1) + return; + + chip->read_retries = micron->read_retry_options; + chip->setup_read_retry = nand_setup_read_retry_micron; +} + /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -3085,6 +3109,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, pr_warn("Could not retrieve ONFI ECC requirements\n"); } + if (p->jedec_id == NAND_MFR_MICRON) + nand_onfi_detect_micron(chip, p); + return 1; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 267d61dd89dd..3080a8c8b62e 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -219,6 +219,9 @@ struct nand_chip; /* ONFI feature address */ #define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 +/* Vendor-specific feature address (Micron) */ +#define ONFI_FEATURE_ADDR_READ_RETRY 0x89 + /* ONFI subfeature parameters length */ #define ONFI_SUBFEATURE_PARAM_LEN 4 -- cgit v1.2.3 From 05f7835975dad6b3b517f9e23415985e648fb875 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 5 Dec 2013 22:22:04 +0100 Subject: mtd: nand: don't use {read,write}_buf for 8-bit transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the Open NAND Flash Interface Specification (ONFI) Revision 3.1 "Parameters are always transferred on the lower 8-bits of the data bus." for the Get Features and Set Features commands. So using read_buf and write_buf is wrong for 16-bit wide nand chips as they use I/O[15:0]. The Get Features command is easily fixed using 4 times the read_byte callback. For Set Features implement a new overwritable callback "write_byte". Still I expect the default to work just fine for all controllers and making it overwriteable was just done for symmetry. Signed-off-by: Uwe Kleine-König [Brian: fixed warning] Tested-by: Brian Norris Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 57 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/mtd/nand.h | 3 +++ 2 files changed, 58 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index b8c74cda7625..d388c7f6fec9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -203,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) } } +/** + * nand_write_byte - [DEFAULT] write single byte to chip + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] + */ +static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + + chip->write_buf(mtd, &byte, 1); +} + +/** + * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16 + * @mtd: MTD device structure + * @byte: value to write + * + * Default function to write a byte to I/O[7:0] on a 16-bit wide chip. + */ +static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) +{ + struct nand_chip *chip = mtd->priv; + uint16_t word = byte; + + /* + * It's not entirely clear what should happen to I/O[15:8] when writing + * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads: + * + * When the host supports a 16-bit bus width, only data is + * transferred at the 16-bit width. All address and command line + * transfers shall use only the lower 8-bits of the data bus. During + * command transfers, the host may place any value on the upper + * 8-bits of the data bus. During address transfers, the host shall + * set the upper 8-bits of the data bus to 00h. + * + * One user of the write_byte callback is nand_onfi_set_features. The + * four parameters are specified to be written to I/O[7:0], but this is + * neither an address nor a command transfer. Let's assume a 0 on the + * upper I/O lines is OK. + */ + chip->write_buf(mtd, (uint8_t *)&word, 2); +} + /** * nand_write_buf - [DEFAULT] write buffer to chip * @mtd: MTD device structure @@ -2769,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { int status; + int i; if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) @@ -2776,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, return -EINVAL; chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); - chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + chip->write_byte(mtd, subfeature_param[i]); + status = chip->waitfunc(mtd, chip); if (status & NAND_STATUS_FAIL) return -EIO; @@ -2793,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, int addr, uint8_t *subfeature_param) { + int i; + if (!chip->onfi_version || !(le16_to_cpu(chip->onfi_params.opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES)) @@ -2802,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); - chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i) + *subfeature_param++ = chip->read_byte(mtd); return 0; } @@ -2865,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf || chip->write_buf == nand_write_buf) chip->write_buf = busw ? nand_write_buf16 : nand_write_buf; + if (!chip->write_byte || chip->write_byte == nand_write_byte) + chip->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!chip->read_buf || chip->read_buf == nand_read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; if (!chip->scan_bbt) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 05fcdfea640b..352e23891f58 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -456,6 +456,8 @@ struct nand_buffers { * flash device. * @read_byte: [REPLACEABLE] read one byte from the chip * @read_word: [REPLACEABLE] read one word from the chip + * @write_byte: [REPLACEABLE] write a single byte to the chip on the + * low 8 I/O lines * @write_buf: [REPLACEABLE] write data from the buffer to the chip * @read_buf: [REPLACEABLE] read data from the chip into the buffer * @select_chip: [REPLACEABLE] select chip nr @@ -548,6 +550,7 @@ struct nand_chip { uint8_t (*read_byte)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd); + void (*write_byte)(struct mtd_info *mtd, uint8_t byte); void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip); -- cgit v1.2.3 From 7587f64d546d6a05dab0a7d1ac964e7ac12072f0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 15 Jan 2014 16:48:55 +0100 Subject: mtd: m25p80: Use OPCODE_QUAD_READ_4B for 4-byte addressing commit 3487a63955c34ea508bcf4ca5131ddd953876e2d ("drivers: mtd: m25p80: add quad read support") in -next added both the 3-byte OPCODE_QUAD_READ and the 4-byte OPCODE_QUAD_READ_4B, but incorrectly uses OPCODE_QUAD_READ for both 3-byte and 4-byte addressing. Use OPCODE_QUAD_READ_4B in the 4-byte case to fix this. Signed-off-by: Geert Uytterhoeven Acked-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7b976e869636..19632e330d36 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -1250,7 +1250,7 @@ static int m25p_probe(struct spi_device *spi) /* Dedicated 4-byte command set */ switch (flash->flash_read) { case M25P80_QUAD: - flash->read_opcode = OPCODE_QUAD_READ; + flash->read_opcode = OPCODE_QUAD_READ_4B; break; case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ_4B; -- cgit v1.2.3 From 3db227b64841383b0e3c00d02e7c84d363494281 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Mon, 13 Jan 2014 15:35:38 +0100 Subject: mtd: nand: pxa3xx: Add support for 2048 bytes page size devices This commit adds support for devices with 2048B page sizes and 4-bit ECC strength requirements. This is achieved by enabling the BCH ECC engine, which provides a higher strength: 16-bit over 2048 bytes. Additionally, add a proper ECC layout to model the controller's view of the device (where 'U' means unused and 'B' is the bad block marker): ---------------------------------------------------- | 2048B data | B | B | 30B spare | 30B ECC | U | U | ---------------------------------------------------- Signed-off-by: Rodolfo Giometti [Brian: updated with Ezequiel's patch description] Acked-by: Ezequiel Garcia Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 31aae535a02a..2a7a0b27ac38 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -286,6 +286,16 @@ static struct nand_bbt_descr bbt_mirror_descr = { .pattern = bbt_mirror_pattern }; +static struct nand_ecclayout ecc_layout_2KB_bch4bit = { + .eccbytes = 32, + .eccpos = { + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { {2, 30} } +}; + static struct nand_ecclayout ecc_layout_4KB_bch4bit = { .eccbytes = 64, .eccpos = { @@ -1360,6 +1370,17 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, * Required ECC: 4-bit correction per 512 bytes * Select: 16-bit correction per 2048 bytes */ + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) { + info->ecc_bch = 1; + info->chunk_size = 2048; + info->spare_size = 32; + info->ecc_size = 32; + ecc->mode = NAND_ECC_HW; + ecc->size = info->chunk_size; + ecc->layout = &ecc_layout_2KB_bch4bit; + ecc->strength = 16; + return 1; + } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) { info->ecc_bch = 1; info->chunk_size = 2048; -- cgit v1.2.3 From 94d04e824fc879f66d1a8f7c9689b85159e3f24e Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 25 Dec 2013 17:18:55 +0800 Subject: mtd: nand: add support for Samsung K9LCG08U0B Assume that: tmp = ((extid >> 2) & 0x04) | (extid & 0x03)); From the K9LCG08U0B's datasheet, we know that: the oob size is 640 when tmp is 6; the oob size is 1024 when tmp is 7; Signed-off-by: Huang Shijie [Brian: fixed compile issue] Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d388c7f6fec9..59eba5d2c685 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3285,9 +3285,12 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, mtd->oobsize = 512; break; case 6: - default: /* Other cases are "reserved" (unknown) */ mtd->oobsize = 640; break; + case 7: + default: /* Other cases are "reserved" (unknown) */ + mtd->oobsize = 1024; + break; } extid >>= 2; /* Calc blocksize */ -- cgit v1.2.3 From 3f97c6ff6de8a657e4d4d826e502698004cfc2ae Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Thu, 26 Dec 2013 15:37:45 +0800 Subject: mtd: nand: add SanDisk manufacturer ID Add the manufactor ID for SanDisk. Make preparation for SanDisk SDTNRGAMA-008G. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index a87b0a3afa35..136a46321c6f 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -169,6 +169,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_AMD, "AMD/Spansion"}, {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, + {NAND_MFR_SANDISK, "SanDisk"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 352e23891f58..e03a78c70de1 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -633,6 +633,7 @@ struct nand_chip { #define NAND_MFR_AMD 0x01 #define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_EON 0x92 +#define NAND_MFR_SANDISK 0x45 /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 -- cgit v1.2.3 From 4968a4124cf2df4b3672eed4714c6755f10f400c Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 3 Jan 2014 16:50:39 +0800 Subject: mtd: nand: add Intel manufacturer ID Add the Intel manufacturer Id. Tested with Intel JS29F32G08ACMD1(4096 + 224) which is ONFI 2.0 compliant nand. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 136a46321c6f..daa2faacd7d0 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -170,6 +170,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_MACRONIX, "Macronix"}, {NAND_MFR_EON, "Eon"}, {NAND_MFR_SANDISK, "SanDisk"}, + {NAND_MFR_INTEL, "Intel"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index e03a78c70de1..32f8612469d8 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -634,6 +634,7 @@ struct nand_chip { #define NAND_MFR_MACRONIX 0xc2 #define NAND_MFR_EON 0x92 #define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_INTEL 0x89 /* The maximum expected count of bytes in the NAND ID sequence */ #define NAND_MAX_ID_LEN 8 -- cgit v1.2.3 From 840f53c31224d687a7c4a24ea118fa3c737407b0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Jan 2014 21:38:12 +0800 Subject: mtd: plat_nand: remove redundant return value check of platform_get_resource() Remove unneeded error handling on the result of a call to platform_get_resource() when the value is passed to devm_ioremap_resource(). And move those two call together to make the connection between them more clear. Signed-off-by: Wei Yongjun Reviewed-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/plat_nand.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 4ebed7273bc0..0b068a5c0bff 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -48,16 +48,13 @@ static int plat_nand_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - /* Allocate memory for the device structure (and zero it) */ data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data), GFP_KERNEL); if (!data) return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->io_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(data->io_base)) return PTR_ERR(data->io_base); -- cgit v1.2.3 From 973b88fbfa265788f01e65c8667604bf582d5961 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 7 Jan 2014 21:38:32 +0800 Subject: mtd: nuc900_nand: remove redundant return value check of platform_get_resource() Remove unneeded error handling on the result of a call to platform_get_resource() when the value is passed to devm_ioremap_resource(). Signed-off-by: Wei Yongjun Reviewed-by: Jingoo Han Signed-off-by: Brian Norris --- drivers/mtd/nand/nuc900_nand.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 661fd1417000..9ee09a8177c6 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -268,9 +268,6 @@ static int nuc900_nand_probe(struct platform_device *pdev) chip->ecc.mode = NAND_ECC_SOFT; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(nuc900_nand->reg)) return PTR_ERR(nuc900_nand->reg); -- cgit v1.2.3 From 99ed1a167578f85963a0cdf5fd7b2291eaecc400 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 4 Dec 2013 22:59:40 -0800 Subject: mtd: m25p80: assign default read command In the following commit (in -next): commit 8552b439aba7f32063755d23f79ca27b4d0a3115 drivers: mtd: m25p80: convert "bool" read check into an enum We converted the boolean 'fast_read' property to become an enum 'flash_read', but at the same time, we changed the conditional path so that it doesn't choose a default value in some cases (technically, we choose the correct default simply by virtue of devm_kzalloc(), which zeroes this out to be a NORMAL read operation, but still...). Fix this by setting a default for the 'else' clause. Signed-off-by: Brian Norris Cc: Sourav Poddar Acked-by: Marek Vasut --- drivers/mtd/devices/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 19632e330d36..d0f6475504f5 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -1204,6 +1204,8 @@ static int m25p_probe(struct spi_device *spi) /* If we were instantiated by DT, use it */ if (of_property_read_bool(np, "m25p,fast-read")) flash->flash_read = M25P80_FAST; + else + flash->flash_read = M25P80_NORMAL; } else { /* If we weren't instantiated by DT, default to fast-read */ flash->flash_read = M25P80_FAST; -- cgit v1.2.3 From 0a8899b31a7d6c4a3bc7fdbd7c8c1fc79e726363 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 11 Jan 2014 15:51:45 -0800 Subject: mtd: mtdram: add missing 'const' mtdram_init_device() wasn't updated along with mtd_partition.name. Signed-off-by: Brian Norris Cc: Geert Uytterhoeven --- drivers/mtd/devices/mtdram.c | 2 +- include/linux/mtd/mtdram.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index ec59d65897fb..8e285089229c 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void) } int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name) + unsigned long size, const char *name) { memset(mtd, 0, sizeof(*mtd)); diff --git a/include/linux/mtd/mtdram.h b/include/linux/mtd/mtdram.h index 68891313875d..628a6a21ddf0 100644 --- a/include/linux/mtd/mtdram.h +++ b/include/linux/mtd/mtdram.h @@ -3,6 +3,6 @@ #include int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name); + unsigned long size, const char *name); #endif /* __MTD_MTDRAM_H__ */ -- cgit v1.2.3 From 02d018625b7824691cf4f626f139960a5c796805 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 10 Jan 2014 11:24:13 +0530 Subject: mtd: s3c2410: Merge plat/regs-nand.h into s3c2410.c plat/regs-nand.h is used only by S3C2410 nand driver. Since there are no other users, merge this file into the driver code to remove platform dependency. While at it also remove unused macros. Signed-off-by: Sachin Kamat Acked-by: Kukjin Kim Signed-off-by: Brian Norris --- arch/arm/plat-samsung/include/plat/regs-nand.h | 123 ------------------------- drivers/mtd/nand/s3c2410.c | 36 +++++++- 2 files changed, 35 insertions(+), 124 deletions(-) delete mode 100644 arch/arm/plat-samsung/include/plat/regs-nand.h (limited to 'drivers/mtd') diff --git a/arch/arm/plat-samsung/include/plat/regs-nand.h b/arch/arm/plat-samsung/include/plat/regs-nand.h deleted file mode 100644 index 238efea7b9e4..000000000000 --- a/arch/arm/plat-samsung/include/plat/regs-nand.h +++ /dev/null @@ -1,123 +0,0 @@ -/* arch/arm/mach-s3c2410/include/mach/regs-nand.h - * - * Copyright (c) 2004-2005 Simtec Electronics - * http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2410 NAND register definitions -*/ - -#ifndef __ASM_ARM_REGS_NAND -#define __ASM_ARM_REGS_NAND - - -#define S3C2410_NFREG(x) (x) - -#define S3C2410_NFCONF S3C2410_NFREG(0x00) -#define S3C2410_NFCMD S3C2410_NFREG(0x04) -#define S3C2410_NFADDR S3C2410_NFREG(0x08) -#define S3C2410_NFDATA S3C2410_NFREG(0x0C) -#define S3C2410_NFSTAT S3C2410_NFREG(0x10) -#define S3C2410_NFECC S3C2410_NFREG(0x14) - -#define S3C2440_NFCONT S3C2410_NFREG(0x04) -#define S3C2440_NFCMD S3C2410_NFREG(0x08) -#define S3C2440_NFADDR S3C2410_NFREG(0x0C) -#define S3C2440_NFDATA S3C2410_NFREG(0x10) -#define S3C2440_NFECCD0 S3C2410_NFREG(0x14) -#define S3C2440_NFECCD1 S3C2410_NFREG(0x18) -#define S3C2440_NFECCD S3C2410_NFREG(0x1C) -#define S3C2440_NFSTAT S3C2410_NFREG(0x20) -#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) -#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) -#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) -#define S3C2440_NFMECC1 S3C2410_NFREG(0x30) -#define S3C2440_NFSECC S3C2410_NFREG(0x34) -#define S3C2440_NFSBLK S3C2410_NFREG(0x38) -#define S3C2440_NFEBLK S3C2410_NFREG(0x3C) - -#define S3C2412_NFSBLK S3C2410_NFREG(0x20) -#define S3C2412_NFEBLK S3C2410_NFREG(0x24) -#define S3C2412_NFSTAT S3C2410_NFREG(0x28) -#define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) -#define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) -#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) -#define S3C2412_NFMECC1 S3C2410_NFREG(0x38) -#define S3C2412_NFSECC S3C2410_NFREG(0x3C) - -#define S3C2410_NFCONF_EN (1<<15) -#define S3C2410_NFCONF_512BYTE (1<<14) -#define S3C2410_NFCONF_4STEP (1<<13) -#define S3C2410_NFCONF_INITECC (1<<12) -#define S3C2410_NFCONF_nFCE (1<<11) -#define S3C2410_NFCONF_TACLS(x) ((x)<<8) -#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) -#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) - -#define S3C2410_NFSTAT_BUSY (1<<0) - -#define S3C2440_NFCONF_BUSWIDTH_8 (0<<0) -#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0) -#define S3C2440_NFCONF_ADVFLASH (1<<3) -#define S3C2440_NFCONF_TACLS(x) ((x)<<12) -#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) -#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) - -#define S3C2440_NFCONT_LOCKTIGHT (1<<13) -#define S3C2440_NFCONT_SOFTLOCK (1<<12) -#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10) -#define S3C2440_NFCONT_RNBINT_EN (1<<9) -#define S3C2440_NFCONT_RN_FALLING (1<<8) -#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6) -#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5) -#define S3C2440_NFCONT_INITECC (1<<4) -#define S3C2440_NFCONT_nFCE (1<<1) -#define S3C2440_NFCONT_ENABLE (1<<0) - -#define S3C2440_NFSTAT_READY (1<<0) -#define S3C2440_NFSTAT_nCE (1<<1) -#define S3C2440_NFSTAT_RnB_CHANGE (1<<2) -#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3) - -#define S3C2412_NFCONF_NANDBOOT (1<<31) -#define S3C2412_NFCONF_ECCCLKCON (1<<30) -#define S3C2412_NFCONF_ECC_MLC (1<<24) -#define S3C2412_NFCONF_TACLS_MASK (7<<12) /* 1 extra bit of Tacls */ - -#define S3C2412_NFCONT_ECC4_DIRWR (1<<18) -#define S3C2412_NFCONT_LOCKTIGHT (1<<17) -#define S3C2412_NFCONT_SOFTLOCK (1<<16) -#define S3C2412_NFCONT_ECC4_ENCINT (1<<13) -#define S3C2412_NFCONT_ECC4_DECINT (1<<12) -#define S3C2412_NFCONT_MAIN_ECC_LOCK (1<<7) -#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) -#define S3C2412_NFCONT_nFCE1 (1<<2) -#define S3C2412_NFCONT_nFCE0 (1<<1) - -#define S3C2412_NFSTAT_ECC_ENCDONE (1<<7) -#define S3C2412_NFSTAT_ECC_DECDONE (1<<6) -#define S3C2412_NFSTAT_ILLEGAL_ACCESS (1<<5) -#define S3C2412_NFSTAT_RnB_CHANGE (1<<4) -#define S3C2412_NFSTAT_nFCE1 (1<<3) -#define S3C2412_NFSTAT_nFCE0 (1<<2) -#define S3C2412_NFSTAT_Res1 (1<<1) -#define S3C2412_NFSTAT_READY (1<<0) - -#define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) -#define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) -#define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) -#define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) -#define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) -#define S3C2412_NFECCERR_NONE (0) -#define S3C2412_NFECCERR_1BIT (1) -#define S3C2412_NFECCERR_MULTIBIT (2) -#define S3C2412_NFECCERR_ECCAREA (3) - - - -#endif /* __ASM_ARM_REGS_NAND */ - diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 47fbd9a2cacf..f0918e7411d9 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -46,9 +46,43 @@ #include #include -#include #include +#define S3C2410_NFREG(x) (x) + +#define S3C2410_NFCONF S3C2410_NFREG(0x00) +#define S3C2410_NFCMD S3C2410_NFREG(0x04) +#define S3C2410_NFADDR S3C2410_NFREG(0x08) +#define S3C2410_NFDATA S3C2410_NFREG(0x0C) +#define S3C2410_NFSTAT S3C2410_NFREG(0x10) +#define S3C2410_NFECC S3C2410_NFREG(0x14) +#define S3C2440_NFCONT S3C2410_NFREG(0x04) +#define S3C2440_NFCMD S3C2410_NFREG(0x08) +#define S3C2440_NFADDR S3C2410_NFREG(0x0C) +#define S3C2440_NFDATA S3C2410_NFREG(0x10) +#define S3C2440_NFSTAT S3C2410_NFREG(0x20) +#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) +#define S3C2412_NFSTAT S3C2410_NFREG(0x28) +#define S3C2412_NFMECC0 S3C2410_NFREG(0x34) +#define S3C2410_NFCONF_EN (1<<15) +#define S3C2410_NFCONF_INITECC (1<<12) +#define S3C2410_NFCONF_nFCE (1<<11) +#define S3C2410_NFCONF_TACLS(x) ((x)<<8) +#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4) +#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0) +#define S3C2410_NFSTAT_BUSY (1<<0) +#define S3C2440_NFCONF_TACLS(x) ((x)<<12) +#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) +#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) +#define S3C2440_NFCONT_INITECC (1<<4) +#define S3C2440_NFCONT_nFCE (1<<1) +#define S3C2440_NFCONT_ENABLE (1<<0) +#define S3C2440_NFSTAT_READY (1<<0) +#define S3C2412_NFCONF_NANDBOOT (1<<31) +#define S3C2412_NFCONT_INIT_MAIN_ECC (1<<5) +#define S3C2412_NFCONT_nFCE0 (1<<1) +#define S3C2412_NFSTAT_READY (1<<0) + /* new oob placement block for use with hardware ecc generation */ -- cgit v1.2.3 From d8d5d10d0f27d1975e71617efff941321a0dc142 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 21 Jan 2014 13:59:16 +0100 Subject: mtd: m25p80: Enable Quad SPI read transfers for s25fl512s Spansion s25fl512s supports Quad SPI transfers, hence set the M25P80_QUAD_READ flag. Signed-off-by: Geert Uytterhoeven Acked-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d0f6475504f5..320c6a308630 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -943,7 +943,7 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, -- cgit v1.2.3 From 464e906737d6eba2fe63e913e0df4306423b4f61 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 21 Jan 2014 13:59:17 +0100 Subject: mtd: m25p80: Set rx_nbits for Quad SPI transfers When using the Quad Read opcode, SPI masters still use Single SPI transfers, as spi_transfer.rx_nbits defaults to SPI_NBITS_SINGLE. Use SPI_NBITS_QUAD to fix this. While an earlier version of commit 3487a63955c34ea508bcf4ca5131ddd953876e2d ("drivers: mtd: m25p80: add quad read support") did this correctly, it was forgotten in the version that got merged. Signed-off-by: Geert Uytterhoeven Acked-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/mtd') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 320c6a308630..ad1913909702 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -489,6 +489,16 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash) } } +static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_QUAD: + return 4; + default: + return 0; + } +} + /* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. @@ -519,6 +529,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; + t[1].rx_nbits = m25p80_rx_nbits(flash); t[1].len = len; spi_message_add_tail(&t[1], &m); -- cgit v1.2.3 From 06f216c83c25adadc231469d51ab133afdfe110a Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 18 Dec 2013 23:40:59 +0800 Subject: mtd: gpmi: allocate a proper buffer for non ECC read/write The @data_buffer_dma buffer is used for non ECC read/write. Currently, the length of the buffer is PAGE_SIZE, but the NAND chip may has 8K page or 16K page. So we have to extend it for the large page NAND chips. The gpmi_alloc_dma_buffer will be called twice. The first time is to allocate a temporary buffer for scanning the NAND chip; The second time is to allocate a buffer to store the real page content. This patch allocates a buffer of PAGE_SIZE size for scanning the NAND chip when gpmi_alloc_dma_buffer is called the first time, and allocates a buffer of the real NAND page size for the second time gpmi_alloc_dma_buffer is called. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index e2f58207c779..d1d13d86b7e0 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -783,14 +783,23 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) { struct bch_geometry *geo = &this->bch_geometry; struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); if (this->cmd_buffer == NULL) goto error_alloc; - /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ - this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL); + /* + * [2] Allocate a read/write data buffer. + * The gpmi_alloc_dma_buffer can be called twice. + * We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer + * is called before the nand_scan_ident; and we allocate a buffer + * of the real NAND page size when the gpmi_alloc_dma_buffer is + * called after the nand_scan_ident. + */ + this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE, + GFP_DMA | GFP_KERNEL); if (this->data_buffer_dma == NULL) goto error_alloc; -- cgit v1.2.3 From 0ff76a920e3558307567b45aa0a91fb914924bfc Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Wed, 18 Dec 2013 23:41:00 +0800 Subject: mtd: gpmi: add sanity check when mapping DMA for read_buf/write_buf The buffer pointer passed from the upper layer may points to a buffer in the stack or a buffer allocated by vmalloc, and etc.. This patch adds more sanity check to this buffer. After this patch, if we meet a buffer which is allocated by vmalloc or a buffer in the stack, we will use our own DMA buffer @data_buffer_dma to do the DMA operations. If the buffer is not the cases above, we will map it for DMA operations directly. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index d1d13d86b7e0..ca6369fe91ff 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) struct scatterlist *sgl = &this->data_sgl; int ret; - this->direct_dma_map_ok = true; - /* first try to map the upper buffer directly */ - sg_init_one(sgl, this->upper_buf, this->upper_len); - ret = dma_map_sg(this->dev, sgl, 1, dr); - if (ret == 0) { - /* We have to use our own DMA buffer. */ - sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); - - if (dr == DMA_TO_DEVICE) - memcpy(this->data_buffer_dma, this->upper_buf, - this->upper_len); - + if (virt_addr_valid(this->upper_buf) && + !object_is_on_stack(this->upper_buf)) { + sg_init_one(sgl, this->upper_buf, this->upper_len); ret = dma_map_sg(this->dev, sgl, 1, dr); if (ret == 0) - dev_err(this->dev, "DMA mapping failed.\n"); + goto map_fail; - this->direct_dma_map_ok = false; + this->direct_dma_map_ok = true; + return; } + +map_fail: + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, this->upper_len); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len); + + dma_map_sg(this->dev, sgl, 1, dr); + + this->direct_dma_map_ok = false; } /* This will be called after the DMA operation is finished. */ -- cgit v1.2.3