From f384b352cbf0310fd20c379c4710408c70e769b6 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 26 Jun 2017 15:10:00 +0200 Subject: mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables This patch adds support to the JESD216 rev B standard and parses the SFDP tables to dynamically initialize the 'struct spi_nor_flash_parameter'. Signed-off-by: Cyrille Pitchen Reviewed-by: Marek Vasut --- drivers/mtd/spi-nor/spi-nor.c | 775 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 762 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 1413828ff1fb..196b52f083ae 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,7 @@ struct flash_info { * to support memory size above 128Mib. */ #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ +#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ }; #define JEDEC_MFR(info) ((info)->id[0]) @@ -1380,6 +1382,16 @@ write_err: return ret; } +/** + * macronix_quad_enable() - set QE bit in Status Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Status Register. + * + * bit 6 of the Status Register is the QE bit for Macronix like QSPI memories. + * + * Return: 0 on success, -errno otherwise. + */ static int macronix_quad_enable(struct spi_nor *nor) { int ret, val; @@ -1413,22 +1425,13 @@ static int macronix_quad_enable(struct spi_nor *nor) * second byte will be written to the configuration register. * Return negative if error occurred. */ -static int write_sr_cr(struct spi_nor *nor, u16 val) -{ - nor->cmd_buf[0] = val & 0xff; - nor->cmd_buf[1] = (val >> 8); - - return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2); -} - -static int spansion_quad_enable(struct spi_nor *nor) +static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) { int ret; - int quad_en = CR_QUAD_EN_SPAN << 8; write_enable(nor); - ret = write_sr_cr(nor, quad_en); + ret = nor->write_reg(nor, SPINOR_OP_WRSR, sr_cr, 2); if (ret < 0) { dev_err(nor->dev, "error while writing configuration register\n"); @@ -1442,6 +1445,41 @@ static int spansion_quad_enable(struct spi_nor *nor) return ret; } + return 0; +} + +/** + * spansion_quad_enable() - set QE bit in Configuraiton Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function is kept for legacy purpose because it has been used for a + * long time without anybody complaining but it should be considered as + * deprecated and maybe buggy. + * First, this function doesn't care about the previous values of the Status + * and Configuration Registers when it sets the QE bit (bit 1) in the + * Configuration Register: all other bits are cleared, which may have unwanted + * side effects like removing some block protections. + * Secondly, it uses the Read Configuration Register (35h) instruction though + * some very old and few memories don't support this instruction. If a pull-up + * resistor is present on the MISO/IO1 line, we might still be able to pass the + * "read back" test because the QSPI memory doesn't recognize the command, + * so leaves the MISO/IO1 line state unchanged, hence read_cr() returns 0xFF. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable(struct spi_nor *nor) +{ + u8 sr_cr[2] = {0, CR_QUAD_EN_SPAN}; + int ret; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + return ret; + /* read back and check it */ ret = read_cr(nor); if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { @@ -1452,6 +1490,140 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +/** + * spansion_no_read_cr_quad_enable() - set QE bit in Configuration Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function should be used with QSPI memories not supporting the Read + * Configuration Register (35h) instruction. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_no_read_cr_quad_enable(struct spi_nor *nor) +{ + u8 sr_cr[2]; + int ret; + + /* Keep the current value of the Status Register. */ + ret = read_sr(nor); + if (ret < 0) { + dev_err(nor->dev, "error while reading status register\n"); + return -EINVAL; + } + sr_cr[0] = ret; + sr_cr[1] = CR_QUAD_EN_SPAN; + + return write_sr_cr(nor, sr_cr); +} + +/** + * spansion_read_cr_quad_enable() - set QE bit in Configuration Register. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Configuration Register. + * This function should be used with QSPI memories supporting the Read + * Configuration Register (35h) instruction. + * + * bit 1 of the Configuration Register is the QE bit for Spansion like QSPI + * memories. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_read_cr_quad_enable(struct spi_nor *nor) +{ + struct device *dev = nor->dev; + u8 sr_cr[2]; + int ret; + + /* Check current Quad Enable bit value. */ + ret = read_cr(nor); + if (ret < 0) { + dev_err(dev, "error while reading configuration register\n"); + return -EINVAL; + } + + if (ret & CR_QUAD_EN_SPAN) + return 0; + + sr_cr[1] = ret | CR_QUAD_EN_SPAN; + + /* Keep the current value of the Status Register. */ + ret = read_sr(nor); + if (ret < 0) { + dev_err(dev, "error while reading status register\n"); + return -EINVAL; + } + sr_cr[0] = ret; + + ret = write_sr_cr(nor, sr_cr); + if (ret) + return ret; + + /* Read back and check it. */ + ret = read_cr(nor); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +/** + * sr2_bit7_quad_enable() - set QE bit in Status Register 2. + * @nor: pointer to a 'struct spi_nor' + * + * Set the Quad Enable (QE) bit in the Status Register 2. + * + * This is one of the procedures to set the QE bit described in the SFDP + * (JESD216 rev B) specification but no manufacturer using this procedure has + * been identified yet, hence the name of the function. + * + * Return: 0 on success, -errno otherwise. + */ +static int sr2_bit7_quad_enable(struct spi_nor *nor) +{ + u8 sr2; + int ret; + + /* Check current Quad Enable bit value. */ + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + if (ret) + return ret; + if (sr2 & SR2_QUAD_EN_BIT7) + return 0; + + /* Update the Quad Enable bit. */ + sr2 |= SR2_QUAD_EN_BIT7; + + write_enable(nor); + + ret = nor->write_reg(nor, SPINOR_OP_WRSR2, &sr2, 1); + if (ret < 0) { + dev_err(nor->dev, "error while writing status register 2\n"); + return -EINVAL; + } + + ret = spi_nor_wait_till_ready(nor); + if (ret < 0) { + dev_err(nor->dev, "timeout while writing status register 2\n"); + return ret; + } + + /* Read back and check it. */ + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); + if (!(ret > 0 && (sr2 & SR2_QUAD_EN_BIT7))) { + dev_err(nor->dev, "SR2 Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + static int spi_nor_check(struct spi_nor *nor) { if (!nor->dev || !nor->read || !nor->write || @@ -1591,6 +1763,560 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, pp->proto = proto; } +/* + * Serial Flash Discoverable Parameters (SFDP) parsing. + */ + +/** + * spi_nor_read_sfdp() - read Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @addr: offset in the SFDP area to start reading data from + * @len: number of bytes to read + * @buf: buffer where the SFDP data are copied into + * + * Whatever the actual numbers of bytes for address and dummy cycles are + * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always + * followed by a 3-byte address and 8 dummy clock cycles. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, + size_t len, void *buf) +{ + u8 addr_width, read_opcode, read_dummy; + int ret; + + read_opcode = nor->read_opcode; + addr_width = nor->addr_width; + read_dummy = nor->read_dummy; + + nor->read_opcode = SPINOR_OP_RDSFDP; + nor->addr_width = 3; + nor->read_dummy = 8; + + while (len) { + ret = nor->read(nor, addr, len, (u8 *)buf); + if (!ret || ret > len) { + ret = -EIO; + goto read_err; + } + if (ret < 0) + goto read_err; + + buf += ret; + addr += ret; + len -= ret; + } + ret = 0; + +read_err: + nor->read_opcode = read_opcode; + nor->addr_width = addr_width; + nor->read_dummy = read_dummy; + + return ret; +} + +struct sfdp_parameter_header { + u8 id_lsb; + u8 minor; + u8 major; + u8 length; /* in double words */ + u8 parameter_table_pointer[3]; /* byte address */ + u8 id_msb; +}; + +#define SFDP_PARAM_HEADER_ID(p) (((p)->id_msb << 8) | (p)->id_lsb) +#define SFDP_PARAM_HEADER_PTP(p) \ + (((p)->parameter_table_pointer[2] << 16) | \ + ((p)->parameter_table_pointer[1] << 8) | \ + ((p)->parameter_table_pointer[0] << 0)) + +#define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ +#define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ + +#define SFDP_SIGNATURE 0x50444653U +#define SFDP_JESD216_MAJOR 1 +#define SFDP_JESD216_MINOR 0 +#define SFDP_JESD216A_MINOR 5 +#define SFDP_JESD216B_MINOR 6 + +struct sfdp_header { + u32 signature; /* Ox50444653U <=> "SFDP" */ + u8 minor; + u8 major; + u8 nph; /* 0-base number of parameter headers */ + u8 unused; + + /* Basic Flash Parameter Table. */ + struct sfdp_parameter_header bfpt_header; +}; + +/* Basic Flash Parameter Table */ + +/* + * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs. + * They are indexed from 1 but C arrays are indexed from 0. + */ +#define BFPT_DWORD(i) ((i) - 1) +#define BFPT_DWORD_MAX 16 + +/* The first version of JESB216 defined only 9 DWORDs. */ +#define BFPT_DWORD_MAX_JESD216 9 + +/* 1st DWORD. */ +#define BFPT_DWORD1_FAST_READ_1_1_2 BIT(16) +#define BFPT_DWORD1_ADDRESS_BYTES_MASK GENMASK(18, 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY (0x0UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4 (0x1UL << 17) +#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY (0x2UL << 17) +#define BFPT_DWORD1_DTR BIT(19) +#define BFPT_DWORD1_FAST_READ_1_2_2 BIT(20) +#define BFPT_DWORD1_FAST_READ_1_4_4 BIT(21) +#define BFPT_DWORD1_FAST_READ_1_1_4 BIT(22) + +/* 5th DWORD. */ +#define BFPT_DWORD5_FAST_READ_2_2_2 BIT(0) +#define BFPT_DWORD5_FAST_READ_4_4_4 BIT(4) + +/* 11th DWORD. */ +#define BFPT_DWORD11_PAGE_SIZE_SHIFT 4 +#define BFPT_DWORD11_PAGE_SIZE_MASK GENMASK(7, 4) + +/* 15th DWORD. */ + +/* + * (from JESD216 rev B) + * Quad Enable Requirements (QER): + * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4 + * reads based on instruction. DQ3/HOLD# functions are hold during + * instruction phase. + * - 001b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * Writing only one byte to the status register has the side-effect of + * clearing status register 2, including the QE bit. The 100b code is + * used if writing one byte to the status register does not modify + * status register 2. + * - 010b: QE is bit 6 of status register 1. It is set via Write Status with + * one data byte where bit 6 is one. + * [...] + * - 011b: QE is bit 7 of status register 2. It is set via Write status + * register 2 instruction 3Eh with one data byte where bit 7 is one. + * [...] + * The status register 2 is read using instruction 3Fh. + * - 100b: QE is bit 1 of status register 2. It is set via Write Status with + * two data bytes where bit 1 of the second byte is one. + * [...] + * In contrast to the 001b code, writing one byte to the status + * register does not modify status register 2. + * - 101b: QE is bit 1 of status register 2. Status register 1 is read using + * Read Status instruction 05h. Status register2 is read using + * instruction 35h. QE is set via Writ Status instruction 01h with + * two data bytes where bit 1 of the second byte is one. + * [...] + */ +#define BFPT_DWORD15_QER_MASK GENMASK(22, 20) +#define BFPT_DWORD15_QER_NONE (0x0UL << 20) /* Micron */ +#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY (0x1UL << 20) +#define BFPT_DWORD15_QER_SR1_BIT6 (0x2UL << 20) /* Macronix */ +#define BFPT_DWORD15_QER_SR2_BIT7 (0x3UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) +#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ + +struct sfdp_bfpt { + u32 dwords[BFPT_DWORD_MAX]; +}; + +/* Fast Read settings. */ + +static inline void +spi_nor_set_read_settings_from_bfpt(struct spi_nor_read_command *read, + u16 half, + enum spi_nor_protocol proto) +{ + read->num_mode_clocks = (half >> 5) & 0x07; + read->num_wait_states = (half >> 0) & 0x1f; + read->opcode = (half >> 8) & 0xff; + read->proto = proto; +} + +struct sfdp_bfpt_read { + /* The Fast Read x-y-z hardware capability in params->hwcaps.mask. */ + u32 hwcaps; + + /* + * The bit in BFPT DWORD tells us + * whether the Fast Read x-y-z command is supported. + */ + u32 supported_dword; + u32 supported_bit; + + /* + * The half-word at offset in BFPT DWORD + * encodes the op code, the number of mode clocks and the number of wait + * states to be used by Fast Read x-y-z command. + */ + u32 settings_dword; + u32 settings_shift; + + /* The SPI protocol for this Fast Read x-y-z command. */ + enum spi_nor_protocol proto; +}; + +static const struct sfdp_bfpt_read sfdp_bfpt_reads[] = { + /* Fast Read 1-1-2 */ + { + SNOR_HWCAPS_READ_1_1_2, + BFPT_DWORD(1), BIT(16), /* Supported bit */ + BFPT_DWORD(4), 0, /* Settings */ + SNOR_PROTO_1_1_2, + }, + + /* Fast Read 1-2-2 */ + { + SNOR_HWCAPS_READ_1_2_2, + BFPT_DWORD(1), BIT(20), /* Supported bit */ + BFPT_DWORD(4), 16, /* Settings */ + SNOR_PROTO_1_2_2, + }, + + /* Fast Read 2-2-2 */ + { + SNOR_HWCAPS_READ_2_2_2, + BFPT_DWORD(5), BIT(0), /* Supported bit */ + BFPT_DWORD(6), 16, /* Settings */ + SNOR_PROTO_2_2_2, + }, + + /* Fast Read 1-1-4 */ + { + SNOR_HWCAPS_READ_1_1_4, + BFPT_DWORD(1), BIT(22), /* Supported bit */ + BFPT_DWORD(3), 16, /* Settings */ + SNOR_PROTO_1_1_4, + }, + + /* Fast Read 1-4-4 */ + { + SNOR_HWCAPS_READ_1_4_4, + BFPT_DWORD(1), BIT(21), /* Supported bit */ + BFPT_DWORD(3), 0, /* Settings */ + SNOR_PROTO_1_4_4, + }, + + /* Fast Read 4-4-4 */ + { + SNOR_HWCAPS_READ_4_4_4, + BFPT_DWORD(5), BIT(4), /* Supported bit */ + BFPT_DWORD(7), 16, /* Settings */ + SNOR_PROTO_4_4_4, + }, +}; + +struct sfdp_bfpt_erase { + /* + * The half-word at offset in DWORD encodes the + * op code and erase sector size to be used by Sector Erase commands. + */ + u32 dword; + u32 shift; +}; + +static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = { + /* Erase Type 1 in DWORD8 bits[15:0] */ + {BFPT_DWORD(8), 0}, + + /* Erase Type 2 in DWORD8 bits[31:16] */ + {BFPT_DWORD(8), 16}, + + /* Erase Type 3 in DWORD9 bits[15:0] */ + {BFPT_DWORD(9), 0}, + + /* Erase Type 4 in DWORD9 bits[31:16] */ + {BFPT_DWORD(9), 16}, +}; + +static int spi_nor_hwcaps_read2cmd(u32 hwcaps); + +/** + * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table. + * @nor: pointer to a 'struct spi_nor' + * @bfpt_header: pointer to the 'struct sfdp_parameter_header' describing + * the Basic Flash Parameter Table length and version + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Basic Flash Parameter Table is the main and only mandatory table as + * defined by the SFDP (JESD216) specification. + * It provides us with the total size (memory density) of the data array and + * the number of address bytes for Fast Read, Page Program and Sector Erase + * commands. + * For Fast READ commands, it also gives the number of mode clock cycles and + * wait states (regrouped in the number of dummy clock cycles) for each + * supported instruction op code. + * For Page Program, the page size is now available since JESD216 rev A, however + * the supported instruction op codes are still not provided. + * For Sector Erase commands, this table stores the supported instruction op + * codes and the associated sector sizes. + * Finally, the Quad Enable Requirements (QER) are also available since JESD216 + * rev A. The QER bits encode the manufacturer dependent procedure to be + * executed to set the Quad Enable (QE) bit in some internal register of the + * Quad SPI memory. Indeed the QE bit, when it exists, must be set before + * sending any Quad SPI command to the memory. Actually, setting the QE bit + * tells the memory to reassign its WP# and HOLD#/RESET# pins to functions IO2 + * and IO3 hence enabling 4 (Quad) I/O lines. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_bfpt(struct spi_nor *nor, + const struct sfdp_parameter_header *bfpt_header, + struct spi_nor_flash_parameter *params) +{ + struct mtd_info *mtd = &nor->mtd; + struct sfdp_bfpt bfpt; + size_t len; + int i, cmd, err; + u32 addr; + u16 half; + + /* JESD216 Basic Flash Parameter Table length is at least 9 DWORDs. */ + if (bfpt_header->length < BFPT_DWORD_MAX_JESD216) + return -EINVAL; + + /* Read the Basic Flash Parameter Table. */ + len = min_t(size_t, sizeof(bfpt), + bfpt_header->length * sizeof(u32)); + addr = SFDP_PARAM_HEADER_PTP(bfpt_header); + memset(&bfpt, 0, sizeof(bfpt)); + err = spi_nor_read_sfdp(nor, addr, len, &bfpt); + if (err < 0) + return err; + + /* Fix endianness of the BFPT DWORDs. */ + for (i = 0; i < BFPT_DWORD_MAX; i++) + bfpt.dwords[i] = le32_to_cpu(bfpt.dwords[i]); + + /* Number of address bytes. */ + switch (bfpt.dwords[BFPT_DWORD(1)] & BFPT_DWORD1_ADDRESS_BYTES_MASK) { + case BFPT_DWORD1_ADDRESS_BYTES_3_ONLY: + nor->addr_width = 3; + break; + + case BFPT_DWORD1_ADDRESS_BYTES_4_ONLY: + nor->addr_width = 4; + break; + + default: + break; + } + + /* Flash Memory Density (in bits). */ + params->size = bfpt.dwords[BFPT_DWORD(2)]; + if (params->size & BIT(31)) { + params->size &= ~BIT(31); + params->size = 1ULL << params->size; + } else { + params->size++; + } + params->size >>= 3; /* Convert to bytes. */ + + /* Fast Read settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_reads); i++) { + const struct sfdp_bfpt_read *rd = &sfdp_bfpt_reads[i]; + struct spi_nor_read_command *read; + + if (!(bfpt.dwords[rd->supported_dword] & rd->supported_bit)) { + params->hwcaps.mask &= ~rd->hwcaps; + continue; + } + + params->hwcaps.mask |= rd->hwcaps; + cmd = spi_nor_hwcaps_read2cmd(rd->hwcaps); + read = ¶ms->reads[cmd]; + half = bfpt.dwords[rd->settings_dword] >> rd->settings_shift; + spi_nor_set_read_settings_from_bfpt(read, half, rd->proto); + } + + /* Sector Erase settings. */ + for (i = 0; i < ARRAY_SIZE(sfdp_bfpt_erases); i++) { + const struct sfdp_bfpt_erase *er = &sfdp_bfpt_erases[i]; + u32 erasesize; + u8 opcode; + + half = bfpt.dwords[er->dword] >> er->shift; + erasesize = half & 0xff; + + /* erasesize == 0 means this Erase Type is not supported. */ + if (!erasesize) + continue; + + erasesize = 1U << erasesize; + opcode = (half >> 8) & 0xff; +#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + if (erasesize == SZ_4K) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + break; + } +#endif + if (!mtd->erasesize || mtd->erasesize < erasesize) { + nor->erase_opcode = opcode; + mtd->erasesize = erasesize; + } + } + + /* Stop here if not JESD216 rev A or later. */ + if (bfpt_header->length < BFPT_DWORD_MAX) + return 0; + + /* Page size: this field specifies 'N' so the page size = 2^N bytes. */ + params->page_size = bfpt.dwords[BFPT_DWORD(11)]; + params->page_size &= BFPT_DWORD11_PAGE_SIZE_MASK; + params->page_size >>= BFPT_DWORD11_PAGE_SIZE_SHIFT; + params->page_size = 1U << params->page_size; + + /* Quad Enable Requirements. */ + switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) { + case BFPT_DWORD15_QER_NONE: + params->quad_enable = NULL; + break; + + case BFPT_DWORD15_QER_SR2_BIT1_BUGGY: + case BFPT_DWORD15_QER_SR2_BIT1_NO_RD: + params->quad_enable = spansion_no_read_cr_quad_enable; + break; + + case BFPT_DWORD15_QER_SR1_BIT6: + params->quad_enable = macronix_quad_enable; + break; + + case BFPT_DWORD15_QER_SR2_BIT7: + params->quad_enable = sr2_bit7_quad_enable; + break; + + case BFPT_DWORD15_QER_SR2_BIT1: + params->quad_enable = spansion_read_cr_quad_enable; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/** + * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. + * @nor: pointer to a 'struct spi_nor' + * @params: pointer to the 'struct spi_nor_flash_parameter' to be + * filled + * + * The Serial Flash Discoverable Parameters are described by the JEDEC JESD216 + * specification. This is a standard which tends to supported by almost all + * (Q)SPI memory manufacturers. Those hard-coded tables allow us to learn at + * runtime the main parameters needed to perform basic SPI flash operations such + * as Fast Read, Page Program or Sector Erase commands. + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_parse_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + const struct sfdp_parameter_header *param_header, *bfpt_header; + struct sfdp_parameter_header *param_headers = NULL; + struct sfdp_header header; + struct device *dev = nor->dev; + size_t psize; + int i, err; + + /* Get the SFDP header. */ + err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header); + if (err < 0) + return err; + + /* Check the SFDP header version. */ + if (le32_to_cpu(header.signature) != SFDP_SIGNATURE || + header.major != SFDP_JESD216_MAJOR || + header.minor < SFDP_JESD216_MINOR) + return -EINVAL; + + /* + * Verify that the first and only mandatory parameter header is a + * Basic Flash Parameter Table header as specified in JESD216. + */ + bfpt_header = &header.bfpt_header; + if (SFDP_PARAM_HEADER_ID(bfpt_header) != SFDP_BFPT_ID || + bfpt_header->major != SFDP_JESD216_MAJOR) + return -EINVAL; + + /* + * Allocate memory then read all parameter headers with a single + * Read SFDP command. These parameter headers will actually be parsed + * twice: a first time to get the latest revision of the basic flash + * parameter table, then a second time to handle the supported optional + * tables. + * Hence we read the parameter headers once for all to reduce the + * processing time. Also we use kmalloc() instead of devm_kmalloc() + * because we don't need to keep these parameter headers: the allocated + * memory is always released with kfree() before exiting this function. + */ + if (header.nph) { + psize = header.nph * sizeof(*param_headers); + + param_headers = kmalloc(psize, GFP_KERNEL); + if (!param_headers) + return -ENOMEM; + + err = spi_nor_read_sfdp(nor, sizeof(header), + psize, param_headers); + if (err < 0) { + dev_err(dev, "failed to read SFDP parameter headers\n"); + goto exit; + } + } + + /* + * Check other parameter headers to get the latest revision of + * the basic flash parameter table. + */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + if (SFDP_PARAM_HEADER_ID(param_header) == SFDP_BFPT_ID && + param_header->major == SFDP_JESD216_MAJOR && + (param_header->minor > bfpt_header->minor || + (param_header->minor == bfpt_header->minor && + param_header->length > bfpt_header->length))) + bfpt_header = param_header; + } + + err = spi_nor_parse_bfpt(nor, bfpt_header, params); + if (err) + goto exit; + + /* Parse other parameter headers. */ + for (i = 0; i < header.nph; i++) { + param_header = ¶m_headers[i]; + + switch (SFDP_PARAM_HEADER_ID(param_header)) { + case SFDP_SECTOR_MAP_ID: + dev_info(dev, "non-uniform erase sector maps are not supported yet.\n"); + break; + + default: + break; + } + + if (err) + goto exit; + } + +exit: + kfree(param_headers); + return err; +} + static int spi_nor_init_params(struct spi_nor *nor, const struct flash_info *info, struct spi_nor_flash_parameter *params) @@ -1646,11 +2372,28 @@ static int spi_nor_init_params(struct spi_nor *nor, break; default: + /* Kept only for backward compatibility purpose. */ params->quad_enable = spansion_quad_enable; break; } } + /* Override the parameters with data read from SFDP tables. */ + nor->addr_width = 0; + nor->mtd.erasesize = 0; + if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) && + !(info->flags & SPI_NOR_SKIP_SFDP)) { + struct spi_nor_flash_parameter sfdp_params; + + memcpy(&sfdp_params, params, sizeof(sfdp_params)); + if (spi_nor_parse_sfdp(nor, &sfdp_params)) { + nor->addr_width = 0; + nor->mtd.erasesize = 0; + } else { + memcpy(params, &sfdp_params, sizeof(*params)); + } + } + return 0; } @@ -1762,6 +2505,10 @@ static int spi_nor_select_erase(struct spi_nor *nor, { struct mtd_info *mtd = &nor->mtd; + /* Do nothing if already configured from SFDP. */ + if (mtd->erasesize) + return 0; + #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS /* prefer "small sector" erase if possible */ if (info->flags & SECT_4K) { @@ -1994,9 +2741,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, if (ret) return ret; - if (info->addr_width) + if (nor->addr_width) { + /* already configured from SFDP */ + } else if (info->addr_width) { nor->addr_width = info->addr_width; - else if (mtd->size > 0x1000000) { + } else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || -- cgit v1.2.3-59-g8ed1b From e8e3edb95ce6a146bc774b6cfad3553f4383edc8 Mon Sep 17 00:00:00 2001 From: Mario Rugiero Date: Mon, 29 May 2017 08:38:41 -0300 Subject: mtd: create per-device and module-scope debugfs entries Several MTD devices are using debugfs entries created in the root. This commit provides the means for a standardized subtree, creating one "mtd" entry at root, and one entry per device inside it, named after the device. The tree is registered in add_mtd_device, and released in del_mtd_device. Devices docg3, mtdswap and nandsim were updated to use this subtree instead of custom ones, and their entries were prefixed with the drivers' names. Signed-off-by: Mario J. Rugiero Acked-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/devices/docg3.c | 49 ++++++++++++++++----------------------------- drivers/mtd/devices/docg3.h | 2 -- drivers/mtd/mtdcore.c | 16 +++++++++++++++ drivers/mtd/mtdswap.c | 18 ++++------------- drivers/mtd/nand/nandsim.c | 48 +++++++++++--------------------------------- include/linux/mtd/mtd.h | 10 +++++++++ 6 files changed, 59 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index b833e6cc684c..84b16133554b 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1809,37 +1809,22 @@ static int dbg_protection_show(struct seq_file *s, void *p) } DEBUGFS_RO_ATTR(protection, dbg_protection_show); -static int __init doc_dbg_register(struct docg3 *docg3) -{ - struct dentry *root, *entry; - - root = debugfs_create_dir("docg3", NULL); - if (!root) - return -ENOMEM; - - entry = debugfs_create_file("flashcontrol", S_IRUSR, root, docg3, - &flashcontrol_fops); - if (entry) - entry = debugfs_create_file("asic_mode", S_IRUSR, root, - docg3, &asic_mode_fops); - if (entry) - entry = debugfs_create_file("device_id", S_IRUSR, root, - docg3, &device_id_fops); - if (entry) - entry = debugfs_create_file("protection", S_IRUSR, root, - docg3, &protection_fops); - if (entry) { - docg3->debugfs_root = root; - return 0; - } else { - debugfs_remove_recursive(root); - return -ENOMEM; - } -} - -static void doc_dbg_unregister(struct docg3 *docg3) +static void __init doc_dbg_register(struct mtd_info *floor) { - debugfs_remove_recursive(docg3->debugfs_root); + struct dentry *root = floor->dbg.dfs_dir; + struct docg3 *docg3 = floor->priv; + + if (IS_ERR_OR_NULL(root)) + return; + + debugfs_create_file("docg3_flashcontrol", S_IRUSR, root, docg3, + &flashcontrol_fops); + debugfs_create_file("docg3_asic_mode", S_IRUSR, root, docg3, + &asic_mode_fops); + debugfs_create_file("docg3_device_id", S_IRUSR, root, docg3, + &device_id_fops); + debugfs_create_file("docg3_protection", S_IRUSR, root, docg3, + &protection_fops); } /** @@ -2114,6 +2099,8 @@ static int __init docg3_probe(struct platform_device *pdev) 0); if (ret) goto err_probe; + + doc_dbg_register(cascade->floors[floor]); } ret = doc_register_sysfs(pdev, cascade); @@ -2121,7 +2108,6 @@ static int __init docg3_probe(struct platform_device *pdev) goto err_probe; platform_set_drvdata(pdev, cascade); - doc_dbg_register(cascade->floors[0]->priv); return 0; notfound: @@ -2148,7 +2134,6 @@ static int docg3_release(struct platform_device *pdev) int floor; doc_unregister_sysfs(pdev, cascade); - doc_dbg_unregister(docg3); for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h index 19fb93f96a3a..e99946575398 100644 --- a/drivers/mtd/devices/docg3.h +++ b/drivers/mtd/devices/docg3.h @@ -299,7 +299,6 @@ struct docg3_cascade { * @oob_autoecc: if 1, use only bytes 0-7, 15, and fill the others with HW ECC * if 0, use all the 16 bytes. * @oob_write_buf: prepared OOB for next page_write - * @debugfs_root: debugfs root node */ struct docg3 { struct device *dev; @@ -312,7 +311,6 @@ struct docg3 { loff_t oob_write_ofs; int oob_autoecc; u8 oob_write_buf[DOC_LAYOUT_OOB_SIZE]; - struct dentry *debugfs_root; }; #define doc_err(fmt, arg...) dev_err(docg3->dev, (fmt), ## arg) diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 956382cea256..f872a99501ed 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -477,6 +478,8 @@ int mtd_pairing_groups(struct mtd_info *mtd) } EXPORT_SYMBOL_GPL(mtd_pairing_groups); +static struct dentry *dfs_dir_mtd; + /** * add_mtd_device - register an MTD device * @mtd: pointer to new MTD device info structure @@ -552,6 +555,14 @@ int add_mtd_device(struct mtd_info *mtd) if (error) goto fail_added; + if (!IS_ERR_OR_NULL(dfs_dir_mtd)) { + mtd->dbg.dfs_dir = debugfs_create_dir(dev_name(&mtd->dev), dfs_dir_mtd); + if (IS_ERR_OR_NULL(mtd->dbg.dfs_dir)) { + pr_debug("mtd device %s won't show data in debugfs\n", + dev_name(&mtd->dev)); + } + } + device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, "mtd%dro", i); @@ -594,6 +605,8 @@ int del_mtd_device(struct mtd_info *mtd) mutex_lock(&mtd_table_mutex); + debugfs_remove_recursive(mtd->dbg.dfs_dir); + if (idr_find(&mtd_idr, mtd->index) != mtd) { ret = -ENODEV; goto out_error; @@ -1811,6 +1824,8 @@ static int __init init_mtd(void) if (ret) goto out_procfs; + dfs_dir_mtd = debugfs_create_dir("mtd", NULL); + return 0; out_procfs: @@ -1826,6 +1841,7 @@ err_reg: static void __exit cleanup_mtd(void) { + debugfs_remove_recursive(dfs_dir_mtd); cleanup_mtdchar(); if (proc_mtd) remove_proc_entry("mtd", NULL); diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index f12879a3d4ff..6b17932fe557 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -138,8 +138,6 @@ struct mtdswap_dev { char *page_buf; char *oob_buf; - - struct dentry *debugfs_root; }; struct mtdswap_oobdata { @@ -1318,26 +1316,19 @@ static int mtdswap_add_debugfs(struct mtdswap_dev *d) struct gendisk *gd = d->mbd_dev->disk; struct device *dev = disk_to_dev(gd); - struct dentry *root; + struct dentry *root = d->mtd->dbg.dfs_dir; struct dentry *dent; - root = debugfs_create_dir(gd->disk_name, NULL); - if (IS_ERR(root)) + if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; - if (!root) { - dev_err(dev, "failed to initialize debugfs\n"); + if (IS_ERR_OR_NULL(root)) return -1; - } - - d->debugfs_root = root; - dent = debugfs_create_file("stats", S_IRUSR, root, d, + dent = debugfs_create_file("mtdswap_stats", S_IRUSR, root, d, &mtdswap_fops); if (!dent) { dev_err(d->dev, "debugfs_create_file failed\n"); - debugfs_remove_recursive(root); - d->debugfs_root = NULL; return -1; } @@ -1540,7 +1531,6 @@ static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev) { struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); - debugfs_remove_recursive(d->debugfs_root); del_mtd_blktrans_dev(dev); mtdswap_cleanup(d); kfree(d); diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 03a0d057bf2f..1ddf0b73c246 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -287,11 +287,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " /* Maximum page cache pages needed to read or write a NAND page to the cache_file */ #define NS_MAX_HELD_PAGES 16 -struct nandsim_debug_info { - struct dentry *dfs_root; - struct dentry *dfs_wear_report; -}; - /* * A union to represent flash memory contents and flash buffer. */ @@ -370,8 +365,6 @@ struct nandsim { void *file_buf; struct page *held_pages[NS_MAX_HELD_PAGES]; int held_cnt; - - struct nandsim_debug_info dbg; }; /* @@ -524,39 +517,23 @@ static const struct file_operations dfs_fops = { */ static int nandsim_debugfs_create(struct nandsim *dev) { - struct nandsim_debug_info *dbg = &dev->dbg; + struct dentry *root = nsmtd->dbg.dfs_dir; struct dentry *dent; if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; - dent = debugfs_create_dir("nandsim", NULL); - if (!dent) { - NS_ERR("cannot create \"nandsim\" debugfs directory\n"); - return -ENODEV; - } - dbg->dfs_root = dent; + if (IS_ERR_OR_NULL(root)) + return -1; - dent = debugfs_create_file("wear_report", S_IRUSR, - dbg->dfs_root, dev, &dfs_fops); - if (!dent) - goto out_remove; - dbg->dfs_wear_report = dent; + dent = debugfs_create_file("nandsim_wear_report", S_IRUSR, + root, dev, &dfs_fops); + if (IS_ERR_OR_NULL(dent)) { + NS_ERR("cannot create \"nandsim_wear_report\" debugfs entry\n"); + return -1; + } return 0; - -out_remove: - debugfs_remove_recursive(dbg->dfs_root); - return -ENODEV; -} - -/** - * nandsim_debugfs_remove - destroy all debugfs files - */ -static void nandsim_debugfs_remove(struct nandsim *ns) -{ - if (IS_ENABLED(CONFIG_DEBUG_FS)) - debugfs_remove_recursive(ns->dbg.dfs_root); } /* @@ -2352,9 +2329,6 @@ static int __init ns_init_module(void) if ((retval = setup_wear_reporting(nsmtd)) != 0) goto err_exit; - if ((retval = nandsim_debugfs_create(nand)) != 0) - goto err_exit; - if ((retval = init_nandsim(nsmtd)) != 0) goto err_exit; @@ -2370,6 +2344,9 @@ static int __init ns_init_module(void) if (retval != 0) goto err_exit; + if ((retval = nandsim_debugfs_create(nand)) != 0) + goto err_exit; + return 0; err_exit: @@ -2395,7 +2372,6 @@ static void __exit ns_cleanup_module(void) struct nandsim *ns = nand_get_controller_data(chip); int i; - nandsim_debugfs_remove(ns); free_nandsim(ns); /* Free nandsim private resources */ nand_release(nsmtd); /* Unregister driver */ for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index f8a2ef239c60..6cd0f6b7658b 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -206,6 +206,15 @@ struct mtd_pairing_scheme { struct module; /* only needed for owner field in mtd_info */ +/** + * struct mtd_debug_info - debugging information for an MTD device. + * + * @dfs_dir: direntry object of the MTD device debugfs directory + */ +struct mtd_debug_info { + struct dentry *dfs_dir; +}; + struct mtd_info { u_char type; uint32_t flags; @@ -346,6 +355,7 @@ struct mtd_info { struct module *owner; struct device dev; int usecount; + struct mtd_debug_info dbg; }; int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, -- cgit v1.2.3-59-g8ed1b From 1fbef470f3691a4a8afc4937c4ad1901e42901c4 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 24 Jul 2017 17:00:46 -0700 Subject: mtd: mtdswap: remove unused variables 'dev' and 'gd' This was changed recently (commit e8e3edb95ce6 ("mtd: create per-device and module-scope debugfs entries")) and some compilers are complaining: drivers//mtd/mtdswap.c: In function 'mtdswap_add_debugfs': >> drivers//mtd/mtdswap.c:1317: warning: unused variable 'dev' And once we kill 'dev', 'gd' is also unused. Cc: Mario J. Rugiero Signed-off-by: Brian Norris --- drivers/mtd/mtdswap.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 6b17932fe557..7d9080e33865 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1313,9 +1313,6 @@ static const struct file_operations mtdswap_fops = { static int mtdswap_add_debugfs(struct mtdswap_dev *d) { - struct gendisk *gd = d->mbd_dev->disk; - struct device *dev = disk_to_dev(gd); - struct dentry *root = d->mtd->dbg.dfs_dir; struct dentry *dent; -- cgit v1.2.3-59-g8ed1b From fe602838a66d34f3d1de71feab92b403e244db8c Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 29 Jun 2017 14:45:42 +0300 Subject: mtd: spi-nor: intel-spi: Add support for Intel Denverton SPI serial flash controller Intel Denverton exposes the SPI serial flash controller as a PCI device instead of being part of the LPC chip as previous generations did. Signed-off-by: Mika Westerberg Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/Kconfig | 16 ++++++++ drivers/mtd/spi-nor/Makefile | 1 + drivers/mtd/spi-nor/intel-spi-pci.c | 82 +++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 drivers/mtd/spi-nor/intel-spi-pci.c (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 293c8a4d1e49..69c638dd0484 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -89,6 +89,22 @@ config SPI_NXP_SPIFI config SPI_INTEL_SPI tristate +config SPI_INTEL_SPI_PCI + tristate "Intel PCH/PCU SPI flash PCI driver" if EXPERT + depends on X86 && PCI + select SPI_INTEL_SPI + help + This enables PCI support for the Intel PCH/PCU SPI controller in + master mode. This controller is present in modern Intel hardware + and is used to hold BIOS and other persistent settings. Using + this driver it is possible to upgrade BIOS directly from Linux. + + Say N here unless you know what you are doing. Overwriting the + SPI flash may render the system unbootable. + + To compile this driver as a module, choose M here: the module + will be called intel-spi-pci. + config SPI_INTEL_SPI_PLATFORM tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT depends on X86 diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 285aab86c7ca..c5f171de0e1a 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o +obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o \ No newline at end of file diff --git a/drivers/mtd/spi-nor/intel-spi-pci.c b/drivers/mtd/spi-nor/intel-spi-pci.c new file mode 100644 index 000000000000..e82652335ede --- /dev/null +++ b/drivers/mtd/spi-nor/intel-spi-pci.c @@ -0,0 +1,82 @@ +/* + * Intel PCH/PCU SPI flash PCI driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg + * + * 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. + */ + +#include +#include +#include +#include + +#include "intel-spi.h" + +#define BCR 0xdc +#define BCR_WPD BIT(0) + +static const struct intel_spi_boardinfo bxt_info = { + .type = INTEL_SPI_BXT, +}; + +static int intel_spi_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_spi_boardinfo *info; + struct intel_spi *ispi; + u32 bcr; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + /* Try to make the chip read/write */ + pci_read_config_dword(pdev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(pdev, BCR, bcr); + pci_read_config_dword(pdev, BCR, &bcr); + } + info->writeable = !!(bcr & BCR_WPD); + + ispi = intel_spi_probe(&pdev->dev, &pdev->resource[0], info); + if (IS_ERR(ispi)) + return PTR_ERR(ispi); + + pci_set_drvdata(pdev, ispi); + return 0; +} + +static void intel_spi_pci_remove(struct pci_dev *pdev) +{ + intel_spi_remove(pci_get_drvdata(pdev)); +} + +static const struct pci_device_id intel_spi_pci_ids[] = { + { PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info }, + { }, +}; +MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids); + +static struct pci_driver intel_spi_pci_driver = { + .name = "intel-spi", + .id_table = intel_spi_pci_ids, + .probe = intel_spi_pci_probe, + .remove = intel_spi_pci_remove, +}; + +module_pci_driver(intel_spi_pci_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash PCI driver"); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From c4b3eacc1dfef5f36dbdf9a99be37834d3e23ed0 Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Mon, 17 Jul 2017 17:54:07 +0200 Subject: mtd: spi-nor: Recover from Spansion/Cypress errors S25FL{128|256|512}S datasheets say: "When P_ERR or E_ERR bits are set to one, the WIP bit will remain set to one indicating the device remains busy and unable to receive new operation commands. A Clear Status Register (CLSR) command must be received to return the device to standby mode." Current spi-nor code works until first error occurs, but write/erase errors are not just rare hardware failures, they also occur if user tries to flash write-protected areas. After such attempt no SPI command can be executed any more and even read fails. This patch adds support for P_ERR and E_ERR bits in Status Register 1 (so that operation fails immediately and not after a long timeout) and proper recovery from the error condition. Tested on Spansion S25FS128S, which is supported by S25FL129P entry. Signed-off-by: Alexander Sverdlin Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 29 +++++++++++++++++++++-------- include/linux/mtd/spi-nor.h | 5 +++++ 2 files changed, 26 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 196b52f083ae..c70c2ebc8661 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -88,6 +88,7 @@ struct flash_info { */ #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ +#define USE_CLSR BIT(14) /* use CLSR command */ }; #define JEDEC_MFR(info) ((info)->id[0]) @@ -308,8 +309,18 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor) int sr = read_sr(nor); if (sr < 0) return sr; - else - return !(sr & SR_WIP); + + if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) { + if (sr & SR_E_ERR) + dev_err(nor->dev, "Erase Error occurred\n"); + else + dev_err(nor->dev, "Programming Error occurred\n"); + + nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0); + return -EIO; + } + + return !(sr & SR_WIP); } static inline int spi_nor_fsr_ready(struct spi_nor *nor) @@ -1043,15 +1054,15 @@ static const struct flash_info spi_nor_ids[] = { */ { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, @@ -2707,6 +2718,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, nor->flags |= SNOR_F_HAS_SR_TB; if (info->flags & NO_CHIP_ERASE) nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; + if (info->flags & USE_CLSR) + nor->flags |= SNOR_F_USE_CLSR; if (info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 0df3638ff0b8..1f0a7fc7772f 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -105,6 +105,7 @@ /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ +#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ /* Used for Micron flashes only. */ #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ @@ -119,6 +120,9 @@ #define SR_BP2 BIT(4) /* Block protect 2 */ #define SR_TB BIT(5) /* Top/Bottom protect */ #define SR_SRWD BIT(7) /* SR write protect */ +/* Spansion/Cypress specific status bits */ +#define SR_E_ERR BIT(5) +#define SR_P_ERR BIT(6) #define SR_QUAD_EN_MX BIT(6) /* Macronix Quad I/O */ @@ -224,6 +228,7 @@ enum spi_nor_option_flags { SNOR_F_NO_OP_CHIP_ERASE = BIT(2), SNOR_F_S3AN_ADDR_DEFAULT = BIT(3), SNOR_F_READY_XSR_RDY = BIT(4), + SNOR_F_USE_CLSR = BIT(5), }; /** -- cgit v1.2.3-59-g8ed1b From 7fd0db5b6e8cf3788ebe7e8d009391c7a3ea6bb7 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:41:38 -0300 Subject: mtd: atmel-quadspi: Remove unneeded pinctrl header There is no need to include as no pinctrl function is used in this driver, so just remove it. Signed-off-by: Fabio Estevam Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/atmel-quadspi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/atmel-quadspi.c b/drivers/mtd/spi-nor/atmel-quadspi.c index ba76fa8f2031..6c5708bacad8 100644 --- a/drivers/mtd/spi-nor/atmel-quadspi.c +++ b/drivers/mtd/spi-nor/atmel-quadspi.c @@ -35,7 +35,6 @@ #include #include -#include /* QSPI register offsets */ #define QSPI_CR 0x0000 /* Control Register */ -- cgit v1.2.3-59-g8ed1b From eb353aaa7c552ee09a99510775e6be34f41375ce Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:41:39 -0300 Subject: mtd: mtk-quadspi: Remove unneeded pinctrl header There is no need to include as no pinctrl function is used in this driver, so just remove it. Signed-off-by: Fabio Estevam Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/mtk-quadspi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c index 8a20ec4991c8..c258c7adf1c5 100644 --- a/drivers/mtd/spi-nor/mtk-quadspi.c +++ b/drivers/mtd/spi-nor/mtk-quadspi.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From d4cb37e71662dac72049bf7c55a9038bd7d2bcb5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 16 May 2017 00:17:42 +0200 Subject: mtd: nand: Remove support for block locking/unlocking Commit 7d70f334ad2b ("mtd: nand: add lock/unlock routines") introduced support for the Micron LOCK/UNLOCK commands but no one ever used the nand_lock/unlock() functions. Remove support for these vendor-specific operations from the core. If one ever wants to add them back they should be put in nand_micron.c and mtd->_lock/_unlock should be directly assigned from there instead of exporting the functions. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 173 ------------------------------------------- include/linux/mtd/nand.h | 10 --- 2 files changed, 183 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5fa5ddc94834..54d6194fb180 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1239,179 +1239,6 @@ int nand_reset(struct nand_chip *chip, int chipnr) return 0; } -/** - * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * @invert: - * - when = 0, unlock the range of blocks within the lower and - * upper boundary address - * - when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address - * - * Returs unlock status. - */ -static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, - uint64_t len, int invert) -{ - int ret = 0; - int status, page; - struct nand_chip *chip = mtd_to_nand(mtd); - - /* Submit address of first page to unlock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); - - /* Submit address of last page to unlock */ - page = (ofs + len) >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, - (page | invert) & chip->pagemask); - - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; - } - - return ret; -} - -/** - * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * - * Returns unlock status. - */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - int ret = 0; - int chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); - - if (check_offs_len(mtd, ofs, len)) - return -EINVAL; - - /* Align to last block address if size addresses end of the device */ - if (ofs + len == mtd->size) - len -= mtd->erasesize; - - nand_get_device(mtd, FL_UNLOCKING); - - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; - - /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block - */ - nand_reset(chip, chipnr); - - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - pr_debug("%s: device is write protected!\n", - __func__); - ret = -EIO; - goto out; - } - - ret = __nand_unlock(mtd, ofs, len, 0); - -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - return ret; -} -EXPORT_SYMBOL(nand_unlock); - -/** - * nand_lock - [REPLACEABLE] locks all blocks present in the device - * @mtd: mtd info - * @ofs: offset to start unlock from - * @len: length to unlock - * - * This feature is not supported in many NAND parts. 'Micron' NAND parts do - * have this feature, but it allows only to lock all blocks, not for specified - * range for block. Implementing 'lock' feature by making use of 'unlock', for - * now. - * - * Returns lock status. - */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) -{ - int ret = 0; - int chipnr, status, page; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)ofs, len); - - if (check_offs_len(mtd, ofs, len)) - return -EINVAL; - - nand_get_device(mtd, FL_LOCKING); - - /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; - - /* - * Reset the chip. - * If we want to check the WP through READ STATUS and check the bit 7 - * we must reset the chip - * some operation can also clear the bit 7 of status register - * eg. erase/program a locked block - */ - nand_reset(chip, chipnr); - - chip->select_chip(mtd, chipnr); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - pr_debug("%s: device is write protected!\n", - __func__); - status = MTD_ERASE_FAILED; - ret = -EIO; - goto out; - } - - /* Submit address of first page to lock */ - page = ofs >> chip->page_shift; - chip->cmdfunc(mtd, NAND_CMD_LOCK, -1, page & chip->pagemask); - - /* Call wait ready function */ - status = chip->waitfunc(mtd, chip); - /* See if device thinks it succeeded */ - if (status & NAND_STATUS_FAIL) { - pr_debug("%s: error status = 0x%08x\n", - __func__, status); - ret = -EIO; - goto out; - } - - ret = __nand_unlock(mtd, ofs, len, 0x1); - -out: - chip->select_chip(mtd, -1); - nand_release_device(mtd); - - return ret; -} -EXPORT_SYMBOL(nand_lock); - /** * nand_check_erased_buf - check if a buffer contains (almost) only 0xff data * @buf: buffer to test diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 892148c448cc..8a6522e82f03 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -44,12 +44,6 @@ void nand_release(struct mtd_info *mtd); /* Internal helper for board drivers which need to override command function */ void nand_wait_ready(struct mtd_info *mtd); -/* locks all blocks present in the device */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - -/* unlocks specified locked blocks */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - /* The maximum number of NAND chips in an array */ #define NAND_MAX_CHIPS 8 @@ -89,10 +83,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); #define NAND_CMD_SET_FEATURES 0xef #define NAND_CMD_RESET 0xff -#define NAND_CMD_LOCK 0x2a -#define NAND_CMD_UNLOCK1 0x23 -#define NAND_CMD_UNLOCK2 0x24 - /* Extended commands for large page devices */ #define NAND_CMD_READSTART 0x30 #define NAND_CMD_RNDOUTSTART 0xE0 -- cgit v1.2.3-59-g8ed1b From d4092d76a4a4e57b65910899948a83cc8646c5a5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Aug 2017 17:29:10 +0200 Subject: mtd: nand: Rename nand.h into rawnand.h We are planning to share more code between different NAND based devices (SPI NAND, OneNAND and raw NANDs), but before doing that we need to move the existing include/linux/mtd/nand.h file into include/linux/mtd/rawnand.h so we can later create a nand.h header containing all common structure and function prototypes. Signed-off-by: Boris Brezillon Signed-off-by: Peter Pan Acked-by: Vladimir Zapolskiy Acked-by: Alexander Sverdlin Acked-by: Wenyou Yang Acked-by: Krzysztof Kozlowski Acked-by: Han Xu Acked-by: H Hartley Sweeten Acked-by: Shawn Guo Acked-by: Gregory CLEMENT Acked-by: Neil Armstrong Acked-by: Masahiro Yamada Acked-By: Harvey Hunt Acked-by: Tony Lindgren Acked-by: Krzysztof Halasa --- Documentation/driver-api/mtdnand.rst | 8 +- MAINTAINERS | 2 +- arch/arm/mach-davinci/board-da850-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-evm.c | 2 +- arch/arm/mach-davinci/board-dm355-leopard.c | 2 +- arch/arm/mach-davinci/board-dm365-evm.c | 2 +- arch/arm/mach-davinci/board-dm644x-evm.c | 2 +- arch/arm/mach-davinci/board-dm646x-evm.c | 2 +- arch/arm/mach-davinci/board-sffsdr.c | 2 +- arch/arm/mach-dove/dove-db-setup.c | 2 +- arch/arm/mach-ep93xx/snappercl15.c | 2 +- arch/arm/mach-ep93xx/ts72xx.c | 2 +- arch/arm/mach-imx/mach-qong.c | 2 +- arch/arm/mach-ixp4xx/ixdp425-setup.c | 2 +- arch/arm/mach-mmp/aspenite.c | 2 +- arch/arm/mach-omap1/board-fsample.c | 2 +- arch/arm/mach-omap1/board-h2.c | 2 +- arch/arm/mach-omap1/board-h3.c | 2 +- arch/arm/mach-omap1/board-nand.c | 2 +- arch/arm/mach-omap1/board-perseus2.c | 2 +- arch/arm/mach-orion5x/db88f5281-setup.c | 2 +- arch/arm/mach-orion5x/kurobox_pro-setup.c | 2 +- arch/arm/mach-orion5x/ts209-setup.c | 2 +- arch/arm/mach-orion5x/ts78xx-setup.c | 2 +- arch/arm/mach-pxa/balloon3.c | 2 +- arch/arm/mach-pxa/em-x270.c | 2 +- arch/arm/mach-pxa/eseries.c | 2 +- arch/arm/mach-pxa/palmtx.c | 2 +- arch/arm/mach-pxa/tosa.c | 2 +- arch/arm/mach-s3c24xx/common-smdk.c | 2 +- arch/arm/mach-s3c24xx/mach-anubis.c | 2 +- arch/arm/mach-s3c24xx/mach-at2440evb.c | 2 +- arch/arm/mach-s3c24xx/mach-bast.c | 2 +- arch/arm/mach-s3c24xx/mach-gta02.c | 2 +- arch/arm/mach-s3c24xx/mach-jive.c | 2 +- arch/arm/mach-s3c24xx/mach-mini2440.c | 2 +- arch/arm/mach-s3c24xx/mach-osiris.c | 2 +- arch/arm/mach-s3c24xx/mach-qt2410.c | 2 +- arch/arm/mach-s3c24xx/mach-rx3715.c | 2 +- arch/arm/mach-s3c24xx/mach-vstms.c | 2 +- arch/blackfin/mach-bf537/boards/dnp5370.c | 2 +- arch/blackfin/mach-bf537/boards/stamp.c | 2 +- arch/blackfin/mach-bf561/boards/acvilon.c | 2 +- arch/cris/arch-v32/drivers/mach-a3/nandflash.c | 2 +- arch/cris/arch-v32/drivers/mach-fs/nandflash.c | 2 +- arch/mips/alchemy/devboards/db1200.c | 2 +- arch/mips/alchemy/devboards/db1300.c | 2 +- arch/mips/alchemy/devboards/db1550.c | 2 +- arch/mips/include/asm/mach-jz4740/jz4740_nand.h | 2 +- arch/mips/netlogic/xlr/platform-flash.c | 2 +- arch/mips/pnx833x/common/platform.c | 2 +- arch/mips/rb532/devices.c | 2 +- arch/sh/boards/mach-migor/setup.c | 2 +- drivers/mtd/inftlcore.c | 2 +- drivers/mtd/nand/ams-delta.c | 2 +- drivers/mtd/nand/atmel/nand-controller.c | 2 +- drivers/mtd/nand/atmel/pmecc.c | 2 +- drivers/mtd/nand/au1550nd.c | 2 +- drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h | 2 +- drivers/mtd/nand/bf5xx_nand.c | 2 +- drivers/mtd/nand/brcmnand/brcmnand.c | 2 +- drivers/mtd/nand/cafe_nand.c | 2 +- drivers/mtd/nand/cmx270_nand.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/davinci_nand.c | 2 +- drivers/mtd/nand/denali.h | 2 +- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/nand/docg4.c | 2 +- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/fsl_ifc_nand.c | 2 +- drivers/mtd/nand/fsl_upm.c | 2 +- drivers/mtd/nand/fsmc_nand.c | 2 +- drivers/mtd/nand/gpio.c | 2 +- drivers/mtd/nand/gpmi-nand/gpmi-nand.h | 2 +- drivers/mtd/nand/hisi504_nand.c | 2 +- drivers/mtd/nand/jz4740_nand.c | 2 +- drivers/mtd/nand/jz4780_nand.c | 2 +- drivers/mtd/nand/lpc32xx_mlc.c | 2 +- drivers/mtd/nand/lpc32xx_slc.c | 2 +- drivers/mtd/nand/mpc5121_nfc.c | 2 +- drivers/mtd/nand/mtk_nand.c | 2 +- drivers/mtd/nand/mxc_nand.c | 2 +- drivers/mtd/nand/nand_amd.c | 2 +- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand/nand_bbt.c | 2 +- drivers/mtd/nand/nand_bch.c | 2 +- drivers/mtd/nand/nand_ecc.c | 2 +- drivers/mtd/nand/nand_hynix.c | 2 +- drivers/mtd/nand/nand_ids.c | 2 +- drivers/mtd/nand/nand_macronix.c | 2 +- drivers/mtd/nand/nand_micron.c | 2 +- drivers/mtd/nand/nand_samsung.c | 2 +- drivers/mtd/nand/nand_timings.c | 2 +- drivers/mtd/nand/nand_toshiba.c | 2 +- drivers/mtd/nand/nandsim.c | 2 +- drivers/mtd/nand/ndfc.c | 2 +- drivers/mtd/nand/nuc900_nand.c | 2 +- drivers/mtd/nand/omap2.c | 2 +- drivers/mtd/nand/orion_nand.c | 2 +- drivers/mtd/nand/oxnas_nand.c | 2 +- drivers/mtd/nand/pasemi_nand.c | 2 +- drivers/mtd/nand/plat_nand.c | 2 +- drivers/mtd/nand/pxa3xx_nand.c | 2 +- drivers/mtd/nand/qcom_nandc.c | 2 +- drivers/mtd/nand/r852.h | 2 +- drivers/mtd/nand/s3c2410.c | 2 +- drivers/mtd/nand/sh_flctl.c | 2 +- drivers/mtd/nand/sharpsl.c | 2 +- drivers/mtd/nand/sm_common.c | 2 +- drivers/mtd/nand/socrates_nand.c | 2 +- drivers/mtd/nand/sunxi_nand.c | 2 +- drivers/mtd/nand/tango_nand.c | 2 +- drivers/mtd/nand/tmio_nand.c | 2 +- drivers/mtd/nand/txx9ndfmc.c | 2 +- drivers/mtd/nand/vf610_nfc.c | 2 +- drivers/mtd/nand/xway_nand.c | 2 +- drivers/mtd/nftlcore.c | 2 +- drivers/mtd/nftlmount.c | 2 +- drivers/mtd/ssfdc.c | 2 +- drivers/mtd/tests/nandbiterrs.c | 2 +- drivers/staging/mt29f_spinand/mt29f_spinand.c | 2 +- fs/jffs2/wbuf.c | 2 +- include/linux/mtd/nand-gpio.h | 2 +- include/linux/mtd/nand.h | 1331 ----------------------- include/linux/mtd/rawnand.h | 1329 ++++++++++++++++++++++ include/linux/mtd/sh_flctl.h | 2 +- include/linux/mtd/sharpsl.h | 2 +- include/linux/platform_data/mtd-davinci.h | 2 +- include/linux/platform_data/mtd-nand-s3c2410.h | 2 +- 129 files changed, 1459 insertions(+), 1461 deletions(-) delete mode 100644 include/linux/mtd/nand.h create mode 100644 include/linux/mtd/rawnand.h (limited to 'drivers') diff --git a/Documentation/driver-api/mtdnand.rst b/Documentation/driver-api/mtdnand.rst index e9afa586d15e..2a5191b6d445 100644 --- a/Documentation/driver-api/mtdnand.rst +++ b/Documentation/driver-api/mtdnand.rst @@ -516,7 +516,7 @@ mirrored table is performed. The most important field in the nand_bbt_descr structure is the options field. The options define most of the table properties. Use the -predefined constants from nand.h to define the options. +predefined constants from rawnand.h to define the options. - Number of bits per block @@ -843,7 +843,7 @@ Chip option constants Constants for chip id table ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These constants are defined in nand.h. They are OR-ed together to +These constants are defined in rawnand.h. They are OR-ed together to describe the chip functionality:: /* Buswitdh is 16 bit */ @@ -865,7 +865,7 @@ describe the chip functionality:: Constants for runtime options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These constants are defined in nand.h. They are OR-ed together to +These constants are defined in rawnand.h. They are OR-ed together to describe the functionality:: /* The hw ecc generator provides a syndrome instead a ecc value on read @@ -956,7 +956,7 @@ developer. Each struct member has a short description which is marked with an [XXX] identifier. See the chapter "Documentation hints" for an explanation. -.. kernel-doc:: include/linux/mtd/nand.h +.. kernel-doc:: include/linux/mtd/rawnand.h :internal: Public Functions Provided diff --git a/MAINTAINERS b/MAINTAINERS index 205d3977ac46..bffb38373550 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9034,7 +9034,7 @@ T: git git://git.infradead.org/linux-mtd.git nand/fixes T: git git://git.infradead.org/l2-mtd.git nand/next S: Maintained F: drivers/mtd/nand/ -F: include/linux/mtd/nand*.h +F: include/linux/mtd/*nand*.h NATSEMI ETHERNET DRIVER (DP8381x) S: Orphan diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index b5625d009288..f54410388194 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 18296a99c4d2..62e7bc3018f0 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index 284ff27c1b32..be997243447b 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 0464999b7137..e75741fb2c1d 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 70e00dbeec96..b07c9b18d427 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 1d76e7480a42..cb0a41e83582 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-davinci/board-sffsdr.c b/arch/arm/mach-davinci/board-sffsdr.c index 41c7c9615791..d85accf7f760 100644 --- a/arch/arm/mach-davinci/board-sffsdr.c +++ b/arch/arm/mach-davinci/board-sffsdr.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index bcb678fd2415..8971c3c0f0fe 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c index b2db791b3b38..8b29398f4dc7 100644 --- a/arch/arm/mach-ep93xx/snappercl15.c +++ b/arch/arm/mach-ep93xx/snappercl15.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 55b186ef863a..8745162ec05d 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c index 8c2cbd693d21..42a700053103 100644 --- a/arch/arm/mach-imx/mach-qong.c +++ b/arch/arm/mach-imx/mach-qong.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index 508c2d7786e2..93b89291c06b 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c index 5db0edf716dd..d2283009a5ff 100644 --- a/arch/arm/mach-mmp/aspenite.c +++ b/arch/arm/mach-mmp/aspenite.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c index fad95b74bb65..b93ad58b0a63 100644 --- a/arch/arm/mach-omap1/board-fsample.c +++ b/arch/arm/mach-omap1/board-fsample.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 675254ee4b1e..a444b139bff5 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index e62f9d454f10..a618a49a30b8 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c index 7684f9203474..1bffbb4e050f 100644 --- a/arch/arm/mach-omap1/board-nand.c +++ b/arch/arm/mach-omap1/board-nand.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "common.h" diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 150b57ba42bf..e994a78bdd09 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index 12f74b46e2ff..3f5863de766a 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c index 9dc3f59bed9c..83d43cff4bd7 100644 --- a/arch/arm/mach-orion5x/kurobox_pro-setup.c +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c index 7bd671b2854c..0c315515dd2d 100644 --- a/arch/arm/mach-orion5x/ts209-setup.c +++ b/arch/arm/mach-orion5x/ts209-setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index 7ef80a8304c0..94778739e38f 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index 1467c1d1e541..d6d92f388f14 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c index 811a7317f3ea..6d28035ebba5 100644 --- a/arch/arm/mach-pxa/em-x270.c +++ b/arch/arm/mach-pxa/em-x270.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index fa9d71d194f0..91f7c3e40065 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c index 36646975b5d2..47e3e38e9bec 100644 --- a/arch/arm/mach-pxa/palmtx.c +++ b/arch/arm/mach-pxa/palmtx.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 13de6602966f..6a386fd6363e 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c index 9e0bc46e90ec..0e116c92bf01 100644 --- a/arch/arm/mach-s3c24xx/common-smdk.c +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index 029ef1b58925..c14cab361922 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index 7b28eb623fc1..ebdbafb9382a 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index 5185036765db..704dc84b3480 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index b0ed401da3a3..afe18baf0c84 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index f5b5c49b56ac..17821976f769 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 71af8d2fd320..15140d34f927 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index 70b0eb7d3134..a6657e720430 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 868c82087403..84e3a9c53184 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index a39fb9780dd3..b5ba615cf9dd 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c index f5e6322145fa..1adc957edf0f 100644 --- a/arch/arm/mach-s3c24xx/mach-vstms.c +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/dnp5370.c b/arch/blackfin/mach-bf537/boards/dnp5370.c index e79b3b810c39..c4a8ffb15417 100644 --- a/arch/blackfin/mach-bf537/boards/dnp5370.c +++ b/arch/blackfin/mach-bf537/boards/dnp5370.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c index 7528148dc492..400e6693643e 100644 --- a/arch/blackfin/mach-bf537/boards/stamp.c +++ b/arch/blackfin/mach-bf537/boards/stamp.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/blackfin/mach-bf561/boards/acvilon.c b/arch/blackfin/mach-bf561/boards/acvilon.c index 37f8f25a1347..696cc9d7820a 100644 --- a/arch/blackfin/mach-bf561/boards/acvilon.c +++ b/arch/blackfin/mach-bf561/boards/acvilon.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c index 3f646c787e58..925a98eb6d68 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c index a74540514bdb..53b56a429dde 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index 992442a03d8b..83831002c832 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index a5504f57cb00..3e7fbdbdb3c4 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index 1c01d6eadb08..421bd5793f7e 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h index 7f7b0fc554da..f381d465e768 100644 --- a/arch/mips/include/asm/mach-jz4740/jz4740_nand.h +++ b/arch/mips/include/asm/mach-jz4740/jz4740_nand.h @@ -16,7 +16,7 @@ #ifndef __ASM_MACH_JZ4740_JZ4740_NAND_H__ #define __ASM_MACH_JZ4740_JZ4740_NAND_H__ -#include +#include #include #define JZ_NAND_NUM_BANKS 4 diff --git a/arch/mips/netlogic/xlr/platform-flash.c b/arch/mips/netlogic/xlr/platform-flash.c index f03131fec41d..4d1b4c003376 100644 --- a/arch/mips/netlogic/xlr/platform-flash.c +++ b/arch/mips/netlogic/xlr/platform-flash.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include diff --git a/arch/mips/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c index 7cf4eb50fc72..a7a4e9f5146d 100644 --- a/arch/mips/pnx833x/common/platform.c +++ b/arch/mips/pnx833x/common/platform.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index 0966adccf520..32ea3e6731d6 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 5de60a77eaa1..0bcbe58b11e9 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 8db740d6eb08..57ef1fb42a04 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 5d6c26f3cf7f..dcec9cf4983f 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index d922a88e407f..6606270b9b9b 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -59,7 +59,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/atmel/pmecc.c b/drivers/mtd/nand/atmel/pmecc.c index 55a8ee5306ea..27a969a8f105 100644 --- a/drivers/mtd/nand/atmel/pmecc.c +++ b/drivers/mtd/nand/atmel/pmecc.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 9bf6d9915694..9d4a28fa6b73 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h index 8ea75710a854..c8834767ab6d 100644 --- a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h +++ b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h @@ -6,7 +6,7 @@ #endif #include -#include +#include struct bcm47xxnflash { struct bcma_drv_cc *cc; diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 3962f55bd034..5655dca6ce43 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 7419c5ce63f8..e0eb51d8c012 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 2fd733eba0a3..bc558c438a57 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -13,7 +13,7 @@ #include #undef DEBUG #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 949b9400dcb7..1fc435f994e1 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -18,7 +18,7 @@ * CM-X270 board. */ -#include +#include #include #include #include diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 594b28684138..d48877540f14 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 7b26e53b95b1..ccc8c43abcff 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 237cc706b0fb..9239e6793e6e 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -21,7 +21,7 @@ #define __DENALI_H__ #include -#include +#include #define DEVICE_RESET 0x0 #define DEVICE_RESET__BANK(bank) BIT(bank) diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index a023ab9e9cbf..c3aa53caab5c 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index a27a84fbfb84..2436cbc71662 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index b9ac16f05057..17db2f90aa2c 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 59408ec2c69f..9e03bac7f34c 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index d85fa2555b68..a88e2cf66e0f 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 9d8b051d3187..eac15d9bf49e 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 85294f150f4f..fd3648952b5a 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h index 9df0ad64e7e0..a45e4ce13d10 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -17,7 +17,7 @@ #ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H #define __DRIVERS_MTD_NAND_GPMI_NAND_H -#include +#include #include #include #include diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 530caa80b1b6..d9ee1a7e6956 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 0d06a1f07d82..ad827d4af3e9 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/jz4780_nand.c b/drivers/mtd/nand/jz4780_nand.c index 8bc835f71b26..e69f6ae4c539 100644 --- a/drivers/mtd/nand/jz4780_nand.c +++ b/drivers/mtd/nand/jz4780_nand.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 846a66c1b133..bffa01cd0d38 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index a0669a33f8fe..7c8402f023df 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 0e86fb6277c3..b6b97cc9fba6 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c index f7ae99464375..d86a7d131cc0 100644 --- a/drivers/mtd/nand/mtk_nand.c +++ b/drivers/mtd/nand/mtk_nand.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a764d5ca7536..30c71915fd7b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_amd.c b/drivers/mtd/nand/nand_amd.c index 170403a3bfa8..22f060f38123 100644 --- a/drivers/mtd/nand/nand_amd.c +++ b/drivers/mtd/nand/nand_amd.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void amd_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5fa5ddc94834..8093df278692 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 7695efea65f2..2915b6739bf8 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 44763f87eae4..505441c9373b 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index d1770b066396..7613a0388044 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #else diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c index b12dc7325378..b735cc8ec104 100644 --- a/drivers/mtd/nand/nand_hynix.c +++ b/drivers/mtd/nand/nand_hynix.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 92e2cf8e9ff9..5423c3bb388e 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -6,7 +6,7 @@ * published by the Free Software Foundation. * */ -#include +#include #include #define LP_OPTIONS 0 diff --git a/drivers/mtd/nand/nand_macronix.c b/drivers/mtd/nand/nand_macronix.c index 84855c3e1a02..d290ff2a6d2f 100644 --- a/drivers/mtd/nand/nand_macronix.c +++ b/drivers/mtd/nand/nand_macronix.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static int macronix_nand_init(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_micron.c b/drivers/mtd/nand/nand_micron.c index c30ab60f8e1b..abf6a3c376e8 100644 --- a/drivers/mtd/nand/nand_micron.c +++ b/drivers/mtd/nand/nand_micron.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include /* * Special Micron status bit that indicates when the block has been diff --git a/drivers/mtd/nand/nand_samsung.c b/drivers/mtd/nand/nand_samsung.c index 1e0755997762..d348f0129ae7 100644 --- a/drivers/mtd/nand/nand_samsung.c +++ b/drivers/mtd/nand/nand_samsung.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void samsung_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index f06312df3669..90228b9735bd 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include static const struct nand_data_interface onfi_sdr_timings[] = { /* Mode 0 */ diff --git a/drivers/mtd/nand/nand_toshiba.c b/drivers/mtd/nand/nand_toshiba.c index fa787ba38dcd..57df857074e6 100644 --- a/drivers/mtd/nand/nand_toshiba.c +++ b/drivers/mtd/nand/nand_toshiba.c @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include static void toshiba_nand_decode_id(struct nand_chip *chip) { diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 03a0d057bf2f..5ba46354bf0f 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 28e6118362f7..d8a806894937 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -22,7 +22,7 @@ * */ #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 8f64011d32ef..7bb4d2ea9342 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #define REG_FMICSR 0x00 diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 084934a9f19c..54540c8fa1a2 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 209170ed2b76..c48c872f29ee 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c index 1b207aac840c..f14eec3886d9 100644 --- a/drivers/mtd/nand/oxnas_nand.c +++ b/drivers/mtd/nand/oxnas_nand.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 074b8b01289e..a47a7e4bd25a 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 791de3e4bbb6..925a1323604d 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include struct plat_nand_data { diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 74dae4bbdac8..85cff68643e0 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 88af7145a51a..d2751b3a2972 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/r852.h b/drivers/mtd/nand/r852.h index d042ddb71a8b..8713c57f6207 100644 --- a/drivers/mtd/nand/r852.h +++ b/drivers/mtd/nand/r852.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 9e0c849607b9..4c383eeec6f6 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 891ac7b99305..2637b9052fe7 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 064ca1757589..737efe83cd36 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 5939dff253c2..c378705c6e2b 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -7,7 +7,7 @@ * published by the Free Software Foundation. */ #include -#include +#include #include #include #include "sm_common.h" diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 72369bd079af..575997d0ef8a 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index d0b6f8f9f297..393d5dce633d 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 9d40b793b1c4..766906f03943 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index fc5e773f8b60..c9dd682fb353 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index 0a14fda2e41b..b567d212fe7d 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 744ab10e8962..8ba9b6de5fa6 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c index ddee4005248c..9926b4e3d69d 100644 --- a/drivers/mtd/nand/xway_nand.c +++ b/drivers/mtd/nand/xway_nand.c @@ -7,7 +7,7 @@ * Copyright © 2016 Hauke Mehrtens */ -#include +#include #include #include diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index e21161353e76..1f1a61168b3d 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index a5dfbfbebfca..184c8fbfe465 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #define SECTORSIZE 512 diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 41b13d1cdcc4..95f0bf95f095 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include struct ssfdcr_record { diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index f26dec896afa..5f03b8c885a9 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include "mtd_test.h" diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index a4e3ae8f0c85..13eaf16ecd16 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include "mt29f_spinand.h" diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b25d28a21212..48d9522e209c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/mtd/nand-gpio.h b/include/linux/mtd/nand-gpio.h index 51534e50f7fc..be4f45d89be2 100644 --- a/include/linux/mtd/nand-gpio.h +++ b/include/linux/mtd/nand-gpio.h @@ -1,7 +1,7 @@ #ifndef __LINUX_MTD_NAND_GPIO_H #define __LINUX_MTD_NAND_GPIO_H -#include +#include struct gpio_nand_platdata { int gpio_nce; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h deleted file mode 100644 index 892148c448cc..000000000000 --- a/include/linux/mtd/nand.h +++ /dev/null @@ -1,1331 +0,0 @@ -/* - * linux/include/linux/mtd/nand.h - * - * Copyright © 2000-2010 David Woodhouse - * Steven J. Hill - * Thomas Gleixner - * - * 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. - * - * Info: - * Contains standard defines and IDs for NAND flash devices - * - * Changelog: - * See git changelog. - */ -#ifndef __LINUX_MTD_NAND_H -#define __LINUX_MTD_NAND_H - -#include -#include -#include -#include -#include - -struct mtd_info; -struct nand_flash_dev; -struct device_node; - -/* Scan and identify a NAND device */ -int nand_scan(struct mtd_info *mtd, int max_chips); -/* - * Separate phases of nand_scan(), allowing board driver to intervene - * and override command or ECC setup according to flash type. - */ -int nand_scan_ident(struct mtd_info *mtd, int max_chips, - struct nand_flash_dev *table); -int nand_scan_tail(struct mtd_info *mtd); - -/* Unregister the MTD device and free resources held by the NAND device */ -void nand_release(struct mtd_info *mtd); - -/* Internal helper for board drivers which need to override command function */ -void nand_wait_ready(struct mtd_info *mtd); - -/* locks all blocks present in the device */ -int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - -/* unlocks specified locked blocks */ -int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); - -/* The maximum number of NAND chips in an array */ -#define NAND_MAX_CHIPS 8 - -/* - * Constants for hardware specific CLE/ALE/NCE function - * - * These are bits which can be or'ed to set/clear multiple - * bits in one go. - */ -/* Select the chip by setting nCE to low */ -#define NAND_NCE 0x01 -/* Select the command latch by setting CLE to high */ -#define NAND_CLE 0x02 -/* Select the address latch by setting ALE to high */ -#define NAND_ALE 0x04 - -#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) -#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) -#define NAND_CTRL_CHANGE 0x80 - -/* - * Standard NAND flash commands - */ -#define NAND_CMD_READ0 0 -#define NAND_CMD_READ1 1 -#define NAND_CMD_RNDOUT 5 -#define NAND_CMD_PAGEPROG 0x10 -#define NAND_CMD_READOOB 0x50 -#define NAND_CMD_ERASE1 0x60 -#define NAND_CMD_STATUS 0x70 -#define NAND_CMD_SEQIN 0x80 -#define NAND_CMD_RNDIN 0x85 -#define NAND_CMD_READID 0x90 -#define NAND_CMD_ERASE2 0xd0 -#define NAND_CMD_PARAM 0xec -#define NAND_CMD_GET_FEATURES 0xee -#define NAND_CMD_SET_FEATURES 0xef -#define NAND_CMD_RESET 0xff - -#define NAND_CMD_LOCK 0x2a -#define NAND_CMD_UNLOCK1 0x23 -#define NAND_CMD_UNLOCK2 0x24 - -/* Extended commands for large page devices */ -#define NAND_CMD_READSTART 0x30 -#define NAND_CMD_RNDOUTSTART 0xE0 -#define NAND_CMD_CACHEDPROG 0x15 - -#define NAND_CMD_NONE -1 - -/* Status bits */ -#define NAND_STATUS_FAIL 0x01 -#define NAND_STATUS_FAIL_N1 0x02 -#define NAND_STATUS_TRUE_READY 0x20 -#define NAND_STATUS_READY 0x40 -#define NAND_STATUS_WP 0x80 - -#define NAND_DATA_IFACE_CHECK_ONLY -1 - -/* - * Constants for ECC_MODES - */ -typedef enum { - NAND_ECC_NONE, - NAND_ECC_SOFT, - NAND_ECC_HW, - NAND_ECC_HW_SYNDROME, - NAND_ECC_HW_OOB_FIRST, - NAND_ECC_ON_DIE, -} nand_ecc_modes_t; - -enum nand_ecc_algo { - NAND_ECC_UNKNOWN, - NAND_ECC_HAMMING, - NAND_ECC_BCH, -}; - -/* - * Constants for Hardware ECC - */ -/* Reset Hardware ECC for read */ -#define NAND_ECC_READ 0 -/* Reset Hardware ECC for write */ -#define NAND_ECC_WRITE 1 -/* Enable Hardware ECC before syndrome is read back from flash */ -#define NAND_ECC_READSYN 2 - -/* - * Enable generic NAND 'page erased' check. This check is only done when - * ecc.correct() returns -EBADMSG. - * Set this flag if your implementation does not fix bitflips in erased - * pages and you want to rely on the default implementation. - */ -#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) -#define NAND_ECC_MAXIMIZE BIT(1) -/* - * If your controller already sends the required NAND commands when - * reading or writing a page, then the framework is not supposed to - * send READ0 and SEQIN/PAGEPROG respectively. - */ -#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2) - -/* Bit mask for flags passed to do_nand_read_ecc */ -#define NAND_GET_DEVICE 0x80 - - -/* - * Option constants for bizarre disfunctionality and real - * features. - */ -/* Buswidth is 16 bit */ -#define NAND_BUSWIDTH_16 0x00000002 -/* Chip has cache program function */ -#define NAND_CACHEPRG 0x00000008 -/* - * Chip requires ready check on read (for auto-incremented sequential read). - * True only for small page devices; large page devices do not support - * autoincrement. - */ -#define NAND_NEED_READRDY 0x00000100 - -/* Chip does not allow subpage writes */ -#define NAND_NO_SUBPAGE_WRITE 0x00000200 - -/* Device is one of 'new' xD cards that expose fake nand command set */ -#define NAND_BROKEN_XD 0x00000400 - -/* Device behaves just like nand, but is readonly */ -#define NAND_ROM 0x00000800 - -/* Device supports subpage reads */ -#define NAND_SUBPAGE_READ 0x00001000 - -/* - * Some MLC NANDs need data scrambling to limit bitflips caused by repeated - * patterns. - */ -#define NAND_NEED_SCRAMBLING 0x00002000 - -/* Options valid for Samsung large page devices */ -#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG - -/* Macros to identify the above */ -#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) -#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) -#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE) - -/* Non chip related options */ -/* This option skips the bbt scan during initialization. */ -#define NAND_SKIP_BBTSCAN 0x00010000 -/* - * This option is defined if the board driver allocates its own buffers - * (e.g. because it needs them DMA-coherent). - */ -#define NAND_OWN_BUFFERS 0x00020000 -/* Chip may not exist, so silence any errors in scan */ -#define NAND_SCAN_SILENT_NODEV 0x00040000 -/* - * Autodetect nand buswidth with readid/onfi. - * This suppose the driver will configure the hardware in 8 bits mode - * when calling nand_scan_ident, and update its configuration - * before calling nand_scan_tail. - */ -#define NAND_BUSWIDTH_AUTO 0x00080000 -/* - * This option could be defined by controller drivers to protect against - * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers - */ -#define NAND_USE_BOUNCE_BUFFER 0x00100000 - -/* - * In case your controller is implementing ->cmd_ctrl() and is relying on the - * default ->cmdfunc() implementation, you may want to let the core handle the - * tCCS delay which is required when a column change (RNDIN or RNDOUT) is - * requested. - * If your controller already takes care of this delay, you don't need to set - * this flag. - */ -#define NAND_WAIT_TCCS 0x00200000 - -/* Options set by nand scan */ -/* Nand scan has allocated controller struct */ -#define NAND_CONTROLLER_ALLOC 0x80000000 - -/* Cell info constants */ -#define NAND_CI_CHIPNR_MSK 0x03 -#define NAND_CI_CELLTYPE_MSK 0x0C -#define NAND_CI_CELLTYPE_SHIFT 2 - -/* Keep gcc happy */ -struct nand_chip; - -/* ONFI features */ -#define ONFI_FEATURE_16_BIT_BUS (1 << 0) -#define ONFI_FEATURE_EXT_PARAM_PAGE (1 << 7) - -/* ONFI timing mode, used in both asynchronous and synchronous mode */ -#define ONFI_TIMING_MODE_0 (1 << 0) -#define ONFI_TIMING_MODE_1 (1 << 1) -#define ONFI_TIMING_MODE_2 (1 << 2) -#define ONFI_TIMING_MODE_3 (1 << 3) -#define ONFI_TIMING_MODE_4 (1 << 4) -#define ONFI_TIMING_MODE_5 (1 << 5) -#define ONFI_TIMING_MODE_UNKNOWN (1 << 6) - -/* ONFI feature address */ -#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 - -/* Vendor-specific feature address (Micron) */ -#define ONFI_FEATURE_ADDR_READ_RETRY 0x89 -#define ONFI_FEATURE_ON_DIE_ECC 0x90 -#define ONFI_FEATURE_ON_DIE_ECC_EN BIT(3) - -/* ONFI subfeature parameters length */ -#define ONFI_SUBFEATURE_PARAM_LEN 4 - -/* ONFI optional commands SET/GET FEATURES supported? */ -#define ONFI_OPT_CMD_SET_GET_FEATURES (1 << 2) - -struct nand_onfi_params { - /* rev info and features block */ - /* 'O' 'N' 'F' 'I' */ - u8 sig[4]; - __le16 revision; - __le16 features; - __le16 opt_cmd; - u8 reserved0[2]; - __le16 ext_param_page_length; /* since ONFI 2.1 */ - u8 num_of_param_pages; /* since ONFI 2.1 */ - u8 reserved1[17]; - - /* manufacturer information block */ - char manufacturer[12]; - char model[20]; - u8 jedec_id; - __le16 date_code; - u8 reserved2[13]; - - /* memory organization block */ - __le32 byte_per_page; - __le16 spare_bytes_per_page; - __le32 data_bytes_per_ppage; - __le16 spare_bytes_per_ppage; - __le32 pages_per_block; - __le32 blocks_per_lun; - u8 lun_count; - u8 addr_cycles; - u8 bits_per_cell; - __le16 bb_per_lun; - __le16 block_endurance; - u8 guaranteed_good_blocks; - __le16 guaranteed_block_endurance; - u8 programs_per_page; - u8 ppage_attr; - u8 ecc_bits; - u8 interleaved_bits; - u8 interleaved_ops; - u8 reserved3[13]; - - /* electrical parameter block */ - u8 io_pin_capacitance_max; - __le16 async_timing_mode; - __le16 program_cache_timing_mode; - __le16 t_prog; - __le16 t_bers; - __le16 t_r; - __le16 t_ccs; - __le16 src_sync_timing_mode; - u8 src_ssync_features; - __le16 clk_pin_capacitance_typ; - __le16 io_pin_capacitance_typ; - __le16 input_pin_capacitance_typ; - u8 input_pin_capacitance_max; - u8 driver_strength_support; - __le16 t_int_r; - __le16 t_adl; - u8 reserved4[8]; - - /* vendor */ - __le16 vendor_revision; - u8 vendor[88]; - - __le16 crc; -} __packed; - -#define ONFI_CRC_BASE 0x4F4E - -/* Extended ECC information Block Definition (since ONFI 2.1) */ -struct onfi_ext_ecc_info { - u8 ecc_bits; - u8 codeword_size; - __le16 bb_per_lun; - __le16 block_endurance; - u8 reserved[2]; -} __packed; - -#define ONFI_SECTION_TYPE_0 0 /* Unused section. */ -#define ONFI_SECTION_TYPE_1 1 /* for additional sections. */ -#define ONFI_SECTION_TYPE_2 2 /* for ECC information. */ -struct onfi_ext_section { - u8 type; - u8 length; -} __packed; - -#define ONFI_EXT_SECTION_MAX 8 - -/* Extended Parameter Page Definition (since ONFI 2.1) */ -struct onfi_ext_param_page { - __le16 crc; - u8 sig[4]; /* 'E' 'P' 'P' 'S' */ - u8 reserved0[10]; - struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX]; - - /* - * The actual size of the Extended Parameter Page is in - * @ext_param_page_length of nand_onfi_params{}. - * The following are the variable length sections. - * So we do not add any fields below. Please see the ONFI spec. - */ -} __packed; - -struct jedec_ecc_info { - u8 ecc_bits; - u8 codeword_size; - __le16 bb_per_lun; - __le16 block_endurance; - u8 reserved[2]; -} __packed; - -/* JEDEC features */ -#define JEDEC_FEATURE_16_BIT_BUS (1 << 0) - -struct nand_jedec_params { - /* rev info and features block */ - /* 'J' 'E' 'S' 'D' */ - u8 sig[4]; - __le16 revision; - __le16 features; - u8 opt_cmd[3]; - __le16 sec_cmd; - u8 num_of_param_pages; - u8 reserved0[18]; - - /* manufacturer information block */ - char manufacturer[12]; - char model[20]; - u8 jedec_id[6]; - u8 reserved1[10]; - - /* memory organization block */ - __le32 byte_per_page; - __le16 spare_bytes_per_page; - u8 reserved2[6]; - __le32 pages_per_block; - __le32 blocks_per_lun; - u8 lun_count; - u8 addr_cycles; - u8 bits_per_cell; - u8 programs_per_page; - u8 multi_plane_addr; - u8 multi_plane_op_attr; - u8 reserved3[38]; - - /* electrical parameter block */ - __le16 async_sdr_speed_grade; - __le16 toggle_ddr_speed_grade; - __le16 sync_ddr_speed_grade; - u8 async_sdr_features; - u8 toggle_ddr_features; - u8 sync_ddr_features; - __le16 t_prog; - __le16 t_bers; - __le16 t_r; - __le16 t_r_multi_plane; - __le16 t_ccs; - __le16 io_pin_capacitance_typ; - __le16 input_pin_capacitance_typ; - __le16 clk_pin_capacitance_typ; - u8 driver_strength_support; - __le16 t_adl; - u8 reserved4[36]; - - /* ECC and endurance block */ - u8 guaranteed_good_blocks; - __le16 guaranteed_block_endurance; - struct jedec_ecc_info ecc_info[4]; - u8 reserved5[29]; - - /* reserved */ - u8 reserved6[148]; - - /* vendor */ - __le16 vendor_rev_num; - u8 reserved7[88]; - - /* CRC for Parameter Page */ - __le16 crc; -} __packed; - -/** - * struct nand_id - NAND id structure - * @data: buffer containing the id bytes. Currently 8 bytes large, but can - * be extended if required. - * @len: ID length. - */ -struct nand_id { - u8 data[8]; - int len; -}; - -/** - * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices - * @lock: protection lock - * @active: the mtd device which holds the controller currently - * @wq: wait queue to sleep on if a NAND operation is in - * progress used instead of the per chip wait queue - * when a hw controller is available. - */ -struct nand_hw_control { - spinlock_t lock; - struct nand_chip *active; - wait_queue_head_t wq; -}; - -static inline void nand_hw_control_init(struct nand_hw_control *nfc) -{ - nfc->active = NULL; - spin_lock_init(&nfc->lock); - init_waitqueue_head(&nfc->wq); -} - -/** - * struct nand_ecc_step_info - ECC step information of ECC engine - * @stepsize: data bytes per ECC step - * @strengths: array of supported strengths - * @nstrengths: number of supported strengths - */ -struct nand_ecc_step_info { - int stepsize; - const int *strengths; - int nstrengths; -}; - -/** - * struct nand_ecc_caps - capability of ECC engine - * @stepinfos: array of ECC step information - * @nstepinfos: number of ECC step information - * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step - */ -struct nand_ecc_caps { - const struct nand_ecc_step_info *stepinfos; - int nstepinfos; - int (*calc_ecc_bytes)(int step_size, int strength); -}; - -/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */ -#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...) \ -static const int __name##_strengths[] = { __VA_ARGS__ }; \ -static const struct nand_ecc_step_info __name##_stepinfo = { \ - .stepsize = __step, \ - .strengths = __name##_strengths, \ - .nstrengths = ARRAY_SIZE(__name##_strengths), \ -}; \ -static const struct nand_ecc_caps __name = { \ - .stepinfos = &__name##_stepinfo, \ - .nstepinfos = 1, \ - .calc_ecc_bytes = __calc, \ -} - -/** - * struct nand_ecc_ctrl - Control structure for ECC - * @mode: ECC mode - * @algo: ECC algorithm - * @steps: number of ECC steps per page - * @size: data bytes per ECC step - * @bytes: ECC bytes per step - * @strength: max number of correctible bits per ECC step - * @total: total number of ECC bytes per page - * @prepad: padding information for syndrome based ECC generators - * @postpad: padding information for syndrome based ECC generators - * @options: ECC specific options (see NAND_ECC_XXX flags defined above) - * @priv: pointer to private ECC control data - * @hwctl: function to control hardware ECC generator. Must only - * be provided if an hardware ECC is available - * @calculate: function for ECC calculation or readback from ECC hardware - * @correct: function for ECC correction, matching to ECC generator (sw/hw). - * Should return a positive number representing the number of - * corrected bitflips, -EBADMSG if the number of bitflips exceed - * ECC strength, or any other error code if the error is not - * directly related to correction. - * If -EBADMSG is returned the input buffers should be left - * untouched. - * @read_page_raw: function to read a raw page without ECC. This function - * should hide the specific layout used by the ECC - * controller and always return contiguous in-band and - * out-of-band data even if they're not stored - * contiguously on the NAND chip (e.g. - * NAND_ECC_HW_SYNDROME interleaves in-band and - * out-of-band data). - * @write_page_raw: function to write a raw page without ECC. This function - * should hide the specific layout used by the ECC - * controller and consider the passed data as contiguous - * in-band and out-of-band data. ECC controller is - * responsible for doing the appropriate transformations - * to adapt to its specific layout (e.g. - * NAND_ECC_HW_SYNDROME interleaves in-band and - * out-of-band data). - * @read_page: function to read a page according to the ECC generator - * requirements; returns maximum number of bitflips corrected in - * any single ECC step, -EIO hw error - * @read_subpage: function to read parts of the page covered by ECC; - * returns same as read_page() - * @write_subpage: function to write parts of the page covered by ECC. - * @write_page: function to write a page according to the ECC generator - * requirements. - * @write_oob_raw: function to write chip OOB data without ECC - * @read_oob_raw: function to read chip OOB data without ECC - * @read_oob: function to read chip OOB data - * @write_oob: function to write chip OOB data - */ -struct nand_ecc_ctrl { - nand_ecc_modes_t mode; - enum nand_ecc_algo algo; - int steps; - int size; - int bytes; - int total; - int strength; - int prepad; - int postpad; - unsigned int options; - void *priv; - void (*hwctl)(struct mtd_info *mtd, int mode); - int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code); - int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, - uint8_t *calc_ecc); - int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page); - int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page); - int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page); - int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offs, uint32_t len, uint8_t *buf, int page); - int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, uint32_t data_len, - const uint8_t *data_buf, int oob_required, int page); - int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page); - int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, - int page); - int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, - int page); - int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page); - int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, - int page); -}; - -static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc) -{ - return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS); -} - -/** - * struct nand_buffers - buffer structure for read/write - * @ecccalc: buffer pointer for calculated ECC, size is oobsize. - * @ecccode: buffer pointer for ECC read from flash, size is oobsize. - * @databuf: buffer pointer for data, size is (page size + oobsize). - * - * Do not change the order of buffers. databuf and oobrbuf must be in - * consecutive order. - */ -struct nand_buffers { - uint8_t *ecccalc; - uint8_t *ecccode; - uint8_t *databuf; -}; - -/** - * struct nand_sdr_timings - SDR NAND chip timings - * - * This struct defines the timing requirements of a SDR NAND chip. - * These information can be found in every NAND datasheets and the timings - * meaning are described in the ONFI specifications: - * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing - * Parameters) - * - * All these timings are expressed in picoseconds. - * - * @tBERS_max: Block erase time - * @tCCS_min: Change column setup time - * @tPROG_max: Page program time - * @tR_max: Page read time - * @tALH_min: ALE hold time - * @tADL_min: ALE to data loading time - * @tALS_min: ALE setup time - * @tAR_min: ALE to RE# delay - * @tCEA_max: CE# access time - * @tCEH_min: CE# high hold time - * @tCH_min: CE# hold time - * @tCHZ_max: CE# high to output hi-Z - * @tCLH_min: CLE hold time - * @tCLR_min: CLE to RE# delay - * @tCLS_min: CLE setup time - * @tCOH_min: CE# high to output hold - * @tCS_min: CE# setup time - * @tDH_min: Data hold time - * @tDS_min: Data setup time - * @tFEAT_max: Busy time for Set Features and Get Features - * @tIR_min: Output hi-Z to RE# low - * @tITC_max: Interface and Timing Mode Change time - * @tRC_min: RE# cycle time - * @tREA_max: RE# access time - * @tREH_min: RE# high hold time - * @tRHOH_min: RE# high to output hold - * @tRHW_min: RE# high to WE# low - * @tRHZ_max: RE# high to output hi-Z - * @tRLOH_min: RE# low to output hold - * @tRP_min: RE# pulse width - * @tRR_min: Ready to RE# low (data only) - * @tRST_max: Device reset time, measured from the falling edge of R/B# to the - * rising edge of R/B#. - * @tWB_max: WE# high to SR[6] low - * @tWC_min: WE# cycle time - * @tWH_min: WE# high hold time - * @tWHR_min: WE# high to RE# low - * @tWP_min: WE# pulse width - * @tWW_min: WP# transition to WE# low - */ -struct nand_sdr_timings { - u32 tBERS_max; - u32 tCCS_min; - u32 tPROG_max; - u32 tR_max; - u32 tALH_min; - u32 tADL_min; - u32 tALS_min; - u32 tAR_min; - u32 tCEA_max; - u32 tCEH_min; - u32 tCH_min; - u32 tCHZ_max; - u32 tCLH_min; - u32 tCLR_min; - u32 tCLS_min; - u32 tCOH_min; - u32 tCS_min; - u32 tDH_min; - u32 tDS_min; - u32 tFEAT_max; - u32 tIR_min; - u32 tITC_max; - u32 tRC_min; - u32 tREA_max; - u32 tREH_min; - u32 tRHOH_min; - u32 tRHW_min; - u32 tRHZ_max; - u32 tRLOH_min; - u32 tRP_min; - u32 tRR_min; - u64 tRST_max; - u32 tWB_max; - u32 tWC_min; - u32 tWH_min; - u32 tWHR_min; - u32 tWP_min; - u32 tWW_min; -}; - -/** - * enum nand_data_interface_type - NAND interface timing type - * @NAND_SDR_IFACE: Single Data Rate interface - */ -enum nand_data_interface_type { - NAND_SDR_IFACE, -}; - -/** - * struct nand_data_interface - NAND interface timing - * @type: type of the timing - * @timings: The timing, type according to @type - */ -struct nand_data_interface { - enum nand_data_interface_type type; - union { - struct nand_sdr_timings sdr; - } timings; -}; - -/** - * nand_get_sdr_timings - get SDR timing from data interface - * @conf: The data interface - */ -static inline const struct nand_sdr_timings * -nand_get_sdr_timings(const struct nand_data_interface *conf) -{ - if (conf->type != NAND_SDR_IFACE) - return ERR_PTR(-EINVAL); - - return &conf->timings.sdr; -} - -/** - * struct nand_manufacturer_ops - NAND Manufacturer operations - * @detect: detect the NAND memory organization and capabilities - * @init: initialize all vendor specific fields (like the ->read_retry() - * implementation) if any. - * @cleanup: the ->init() function may have allocated resources, ->cleanup() - * is here to let vendor specific code release those resources. - */ -struct nand_manufacturer_ops { - void (*detect)(struct nand_chip *chip); - int (*init)(struct nand_chip *chip); - void (*cleanup)(struct nand_chip *chip); -}; - -/** - * struct nand_chip - NAND Private Flash Chip Data - * @mtd: MTD device registered to the MTD framework - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the - * flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the - * 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 - * @block_bad: [REPLACEABLE] check if a block is bad, using OOB markers - * @block_markbad: [REPLACEABLE] mark a block bad - * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling - * ALE/CLE/nCE. Also used to write command and address - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing - * device ready/busy line. If set to NULL no access to - * ready/busy is available and the ready/busy information - * is read from the chip status register. - * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing - * 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 - * @buf_align: minimum buffer alignment required by a platform - * @hwcontrol: platform-specific hardware control structure - * @erase: [REPLACEABLE] erase function - * @scan_bbt: [REPLACEABLE] function to scan bad block table - * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring - * data from array to read regs (tR). - * @state: [INTERN] the current state of the NAND device - * @oob_poi: "poison value buffer," used for laying out OOB data - * before writing - * @page_shift: [INTERN] number of address bits in a page (column - * address bits). - * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock - * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry - * @chip_shift: [INTERN] number of address bits in one chip - * @options: [BOARDSPECIFIC] various chip options. They can partly - * be set to inform nand_scan about special functionality. - * See the defines for further explanation. - * @bbt_options: [INTERN] bad block specific options. All options used - * here must come from bbm.h. By default, these options - * will be copied to the appropriate nand_bbt_descr's. - * @badblockpos: [INTERN] position of the bad block marker in the oob - * area. - * @badblockbits: [INTERN] minimum number of set bits in a good block's - * bad block marker position; i.e., BBM == 11110111b is - * not bad when badblockbits == 7 - * @bits_per_cell: [INTERN] number of bits per cell. i.e., 1 means SLC. - * @ecc_strength_ds: [INTERN] ECC correctability from the datasheet. - * Minimum amount of bit errors per @ecc_step_ds guaranteed - * to be correctable. If unknown, set to zero. - * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, - * also from the datasheet. It is the recommended ECC step - * size, if known; if unknown, set to zero. - * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is - * set to the actually used ONFI mode if the chip is - * ONFI compliant or deduced from the datasheet if - * the NAND chip is not ONFI compliant. - * @numchips: [INTERN] number of physical chips - * @chipsize: [INTERN] the size of one chip for multichip arrays - * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 - * @pagebuf: [INTERN] holds the pagenumber which is currently in - * data_buf. - * @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is - * currently in data_buf. - * @subpagesize: [INTERN] holds the subpagesize - * @id: [INTERN] holds NAND ID - * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), - * non 0 if ONFI supported. - * @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded), - * non 0 if JEDEC supported. - * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is - * supported, 0 otherwise. - * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is - * supported, 0 otherwise. - * @max_bb_per_die: [INTERN] the max number of bad blocks each die of a - * this nand device will encounter their life times. - * @blocks_per_die: [INTERN] The number of PEBs in a die - * @data_interface: [INTERN] NAND interface timing information - * @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 - * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If - * chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this - * means the configuration should not be applied but - * only checked. - * @bbt: [INTERN] bad block table pointer - * @bbt_td: [REPLACEABLE] bad block table descriptor for flash - * lookup. - * @bbt_md: [REPLACEABLE] bad block table mirror descriptor - * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial - * bad block scan. - * @controller: [REPLACEABLE] a pointer to a hardware controller - * structure which is shared among multiple independent - * devices. - * @priv: [OPTIONAL] pointer to private chip data - * @manufacturer: [INTERN] Contains manufacturer information - */ - -struct nand_chip { - struct mtd_info mtd; - void __iomem *IO_ADDR_R; - void __iomem *IO_ADDR_W; - - 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); - int (*block_bad)(struct mtd_info *mtd, loff_t ofs); - int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); - void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); - int (*dev_ready)(struct mtd_info *mtd); - void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, - int page_addr); - int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); - int (*erase)(struct mtd_info *mtd, int page); - int (*scan_bbt)(struct mtd_info *mtd); - int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *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 (*setup_data_interface)(struct mtd_info *mtd, int chipnr, - const struct nand_data_interface *conf); - - - int chip_delay; - unsigned int options; - unsigned int bbt_options; - - int page_shift; - int phys_erase_shift; - int bbt_erase_shift; - int chip_shift; - int numchips; - uint64_t chipsize; - int pagemask; - int pagebuf; - unsigned int pagebuf_bitflips; - int subpagesize; - uint8_t bits_per_cell; - uint16_t ecc_strength_ds; - uint16_t ecc_step_ds; - int onfi_timing_mode_default; - int badblockpos; - int badblockbits; - - struct nand_id id; - int onfi_version; - int jedec_version; - union { - struct nand_onfi_params onfi_params; - struct nand_jedec_params jedec_params; - }; - u16 max_bb_per_die; - u32 blocks_per_die; - - struct nand_data_interface *data_interface; - - int read_retries; - - flstate_t state; - - uint8_t *oob_poi; - struct nand_hw_control *controller; - - struct nand_ecc_ctrl ecc; - struct nand_buffers *buffers; - unsigned long buf_align; - struct nand_hw_control hwcontrol; - - uint8_t *bbt; - struct nand_bbt_descr *bbt_td; - struct nand_bbt_descr *bbt_md; - - struct nand_bbt_descr *badblock_pattern; - - void *priv; - - struct { - const struct nand_manufacturer *desc; - void *priv; - } manufacturer; -}; - -extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; -extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; - -static inline void nand_set_flash_node(struct nand_chip *chip, - struct device_node *np) -{ - mtd_set_of_node(&chip->mtd, np); -} - -static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) -{ - return mtd_get_of_node(&chip->mtd); -} - -static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) -{ - return container_of(mtd, struct nand_chip, mtd); -} - -static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) -{ - return &chip->mtd; -} - -static inline void *nand_get_controller_data(struct nand_chip *chip) -{ - return chip->priv; -} - -static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) -{ - chip->priv = priv; -} - -static inline void nand_set_manufacturer_data(struct nand_chip *chip, - void *priv) -{ - chip->manufacturer.priv = priv; -} - -static inline void *nand_get_manufacturer_data(struct nand_chip *chip) -{ - return chip->manufacturer.priv; -} - -/* - * NAND Flash Manufacturer ID Codes - */ -#define NAND_MFR_TOSHIBA 0x98 -#define NAND_MFR_ESMT 0xc8 -#define NAND_MFR_SAMSUNG 0xec -#define NAND_MFR_FUJITSU 0x04 -#define NAND_MFR_NATIONAL 0x8f -#define NAND_MFR_RENESAS 0x07 -#define NAND_MFR_STMICRO 0x20 -#define NAND_MFR_HYNIX 0xad -#define NAND_MFR_MICRON 0x2c -#define NAND_MFR_AMD 0x01 -#define NAND_MFR_MACRONIX 0xc2 -#define NAND_MFR_EON 0x92 -#define NAND_MFR_SANDISK 0x45 -#define NAND_MFR_INTEL 0x89 -#define NAND_MFR_ATO 0x9b -#define NAND_MFR_WINBOND 0xef - -/* The maximum expected count of bytes in the NAND ID sequence */ -#define NAND_MAX_ID_LEN 8 - -/* - * A helper for defining older NAND chips where the second ID byte fully - * defined the chip, including the geometry (chip size, eraseblock size, page - * size). All these chips have 512 bytes NAND page size. - */ -#define LEGACY_ID_NAND(nm, devid, chipsz, erasesz, opts) \ - { .name = (nm), {{ .dev_id = (devid) }}, .pagesize = 512, \ - .chipsize = (chipsz), .erasesize = (erasesz), .options = (opts) } - -/* - * A helper for defining newer chips which report their page size and - * eraseblock size via the extended ID bytes. - * - * The real difference between LEGACY_ID_NAND and EXTENDED_ID_NAND is that with - * EXTENDED_ID_NAND, manufacturers overloaded the same device ID so that the - * device ID now only represented a particular total chip size (and voltage, - * buswidth), and the page size, eraseblock size, and OOB size could vary while - * using the same device ID. - */ -#define EXTENDED_ID_NAND(nm, devid, chipsz, opts) \ - { .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \ - .options = (opts) } - -#define NAND_ECC_INFO(_strength, _step) \ - { .strength_ds = (_strength), .step_ds = (_step) } -#define NAND_ECC_STRENGTH(type) ((type)->ecc.strength_ds) -#define NAND_ECC_STEP(type) ((type)->ecc.step_ds) - -/** - * struct nand_flash_dev - NAND Flash Device ID Structure - * @name: a human-readable name of the NAND chip - * @dev_id: the device ID (the second byte of the full chip ID array) - * @mfr_id: manufecturer ID part of the full chip ID array (refers the same - * memory address as @id[0]) - * @dev_id: device ID part of the full chip ID array (refers the same memory - * address as @id[1]) - * @id: full device ID array - * @pagesize: size of the NAND page in bytes; if 0, then the real page size (as - * well as the eraseblock size) is determined from the extended NAND - * chip ID array) - * @chipsize: total chip size in MiB - * @erasesize: eraseblock size in bytes (determined from the extended ID if 0) - * @options: stores various chip bit options - * @id_len: The valid length of the @id. - * @oobsize: OOB size - * @ecc: ECC correctability and step information from the datasheet. - * @ecc.strength_ds: The ECC correctability from the datasheet, same as the - * @ecc_strength_ds in nand_chip{}. - * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the - * @ecc_step_ds in nand_chip{}, also from the datasheet. - * For example, the "4bit ECC for each 512Byte" can be set with - * NAND_ECC_INFO(4, 512). - * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND - * reset. Should be deduced from timings described - * in the datasheet. - * - */ -struct nand_flash_dev { - char *name; - union { - struct { - uint8_t mfr_id; - uint8_t dev_id; - }; - uint8_t id[NAND_MAX_ID_LEN]; - }; - unsigned int pagesize; - unsigned int chipsize; - unsigned int erasesize; - unsigned int options; - uint16_t id_len; - uint16_t oobsize; - struct { - uint16_t strength_ds; - uint16_t step_ds; - } ecc; - int onfi_timing_mode_default; -}; - -/** - * struct nand_manufacturer - NAND Flash Manufacturer structure - * @name: Manufacturer name - * @id: manufacturer ID code of device. - * @ops: manufacturer operations -*/ -struct nand_manufacturer { - int id; - char *name; - const struct nand_manufacturer_ops *ops; -}; - -const struct nand_manufacturer *nand_get_manufacturer(u8 id); - -static inline const char * -nand_manufacturer_name(const struct nand_manufacturer *manufacturer) -{ - return manufacturer ? manufacturer->name : "Unknown"; -} - -extern struct nand_flash_dev nand_flash_ids[]; - -extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; -extern const struct nand_manufacturer_ops samsung_nand_manuf_ops; -extern const struct nand_manufacturer_ops hynix_nand_manuf_ops; -extern const struct nand_manufacturer_ops micron_nand_manuf_ops; -extern const struct nand_manufacturer_ops amd_nand_manuf_ops; -extern const struct nand_manufacturer_ops macronix_nand_manuf_ops; - -int nand_default_bbt(struct mtd_info *mtd); -int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs); -int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs); -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); -int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, - int allowbbt); -int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf); - -/** - * struct platform_nand_chip - chip level device structure - * @nr_chips: max. number of chips to scan for - * @chip_offset: chip number offset - * @nr_partitions: number of partitions pointed to by partitions (or zero) - * @partitions: mtd partition list - * @chip_delay: R/B delay value in us - * @options: Option flags, e.g. 16bit buswidth - * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH - * @part_probe_types: NULL-terminated array of probe types - */ -struct platform_nand_chip { - int nr_chips; - int chip_offset; - int nr_partitions; - struct mtd_partition *partitions; - int chip_delay; - unsigned int options; - unsigned int bbt_options; - const char **part_probe_types; -}; - -/* Keep gcc happy */ -struct platform_device; - -/** - * struct platform_nand_ctrl - controller level device structure - * @probe: platform specific function to probe/setup hardware - * @remove: platform specific function to remove/teardown hardware - * @hwcontrol: platform specific hardware control structure - * @dev_ready: platform specific function to read ready/busy pin - * @select_chip: platform specific chip select function - * @cmd_ctrl: platform specific function for controlling - * ALE/CLE/nCE. Also used to write command and address - * @write_buf: platform specific function for write buffer - * @read_buf: platform specific function for read buffer - * @read_byte: platform specific function to read one byte from chip - * @priv: private data to transport driver specific settings - * - * All fields are optional and depend on the hardware driver requirements - */ -struct platform_nand_ctrl { - int (*probe)(struct platform_device *pdev); - void (*remove)(struct platform_device *pdev); - void (*hwcontrol)(struct mtd_info *mtd, int cmd); - int (*dev_ready)(struct mtd_info *mtd); - void (*select_chip)(struct mtd_info *mtd, int chip); - void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); - 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); - unsigned char (*read_byte)(struct mtd_info *mtd); - void *priv; -}; - -/** - * struct platform_nand_data - container structure for platform-specific data - * @chip: chip level chip structure - * @ctrl: controller level device structure - */ -struct platform_nand_data { - struct platform_nand_chip chip; - struct platform_nand_ctrl ctrl; -}; - -/* return the supported features. */ -static inline int onfi_feature(struct nand_chip *chip) -{ - return chip->onfi_version ? le16_to_cpu(chip->onfi_params.features) : 0; -} - -/* return the supported asynchronous timing mode. */ -static inline int onfi_get_async_timing_mode(struct nand_chip *chip) -{ - if (!chip->onfi_version) - return ONFI_TIMING_MODE_UNKNOWN; - return le16_to_cpu(chip->onfi_params.async_timing_mode); -} - -/* return the supported synchronous timing mode. */ -static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) -{ - if (!chip->onfi_version) - return ONFI_TIMING_MODE_UNKNOWN; - return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); -} - -int onfi_init_data_interface(struct nand_chip *chip, - struct nand_data_interface *iface, - enum nand_data_interface_type type, - int timing_mode); - -/* - * Check if it is a SLC nand. - * The !nand_is_slc() can be used to check the MLC/TLC nand chips. - * We do not distinguish the MLC and TLC now. - */ -static inline bool nand_is_slc(struct nand_chip *chip) -{ - return chip->bits_per_cell == 1; -} - -/** - * Check if the opcode's address should be sent only on the lower 8 bits - * @command: opcode to check - */ -static inline int nand_opcode_8bits(unsigned int command) -{ - switch (command) { - case NAND_CMD_READID: - case NAND_CMD_PARAM: - case NAND_CMD_GET_FEATURES: - case NAND_CMD_SET_FEATURES: - return 1; - default: - break; - } - return 0; -} - -/* return the supported JEDEC features. */ -static inline int jedec_feature(struct nand_chip *chip) -{ - return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) - : 0; -} - -/* get timing characteristics from ONFI timing mode. */ -const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); -/* get data interface from ONFI timing mode 0, used after reset. */ -const struct nand_data_interface *nand_get_default_data_interface(void); - -int nand_check_erased_ecc_chunk(void *data, int datalen, - void *ecc, int ecclen, - void *extraoob, int extraooblen, - int threshold); - -int nand_check_ecc_caps(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail); - -int nand_match_ecc_req(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail); - -int nand_maximize_ecc(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail); - -/* Default write_oob implementation */ -int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); - -/* Default write_oob syndrome implementation */ -int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page); - -/* Default read_oob implementation */ -int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); - -/* Default read_oob syndrome implementation */ -int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page); - -/* Stub used by drivers that do not support GET/SET FEATURES operations */ -int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd, - struct nand_chip *chip, int addr, - u8 *subfeature_param); - -/* Default read_page_raw implementation */ -int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page); - -/* Default write_page_raw implementation */ -int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int oob_required, int page); - -/* Reset and initialize a NAND device */ -int nand_reset(struct nand_chip *chip, int chipnr); - -/* Free resources held by the NAND device */ -void nand_cleanup(struct nand_chip *chip); - -/* Default extended ID decoding function */ -void nand_decode_ext_id(struct nand_chip *chip); -#endif /* __LINUX_MTD_NAND_H */ diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h new file mode 100644 index 000000000000..b371dc0914a7 --- /dev/null +++ b/include/linux/mtd/rawnand.h @@ -0,0 +1,1329 @@ +/* + * Copyright © 2000-2010 David Woodhouse + * Steven J. Hill + * Thomas Gleixner + * + * 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. + * + * Info: + * Contains standard defines and IDs for NAND flash devices + * + * Changelog: + * See git changelog. + */ +#ifndef __LINUX_MTD_RAWNAND_H +#define __LINUX_MTD_RAWNAND_H + +#include +#include +#include +#include +#include + +struct mtd_info; +struct nand_flash_dev; +struct device_node; + +/* Scan and identify a NAND device */ +int nand_scan(struct mtd_info *mtd, int max_chips); +/* + * Separate phases of nand_scan(), allowing board driver to intervene + * and override command or ECC setup according to flash type. + */ +int nand_scan_ident(struct mtd_info *mtd, int max_chips, + struct nand_flash_dev *table); +int nand_scan_tail(struct mtd_info *mtd); + +/* Unregister the MTD device and free resources held by the NAND device */ +void nand_release(struct mtd_info *mtd); + +/* Internal helper for board drivers which need to override command function */ +void nand_wait_ready(struct mtd_info *mtd); + +/* locks all blocks present in the device */ +int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); + +/* unlocks specified locked blocks */ +int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); + +/* The maximum number of NAND chips in an array */ +#define NAND_MAX_CHIPS 8 + +/* + * Constants for hardware specific CLE/ALE/NCE function + * + * These are bits which can be or'ed to set/clear multiple + * bits in one go. + */ +/* Select the chip by setting nCE to low */ +#define NAND_NCE 0x01 +/* Select the command latch by setting CLE to high */ +#define NAND_CLE 0x02 +/* Select the address latch by setting ALE to high */ +#define NAND_ALE 0x04 + +#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) +#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) +#define NAND_CTRL_CHANGE 0x80 + +/* + * Standard NAND flash commands + */ +#define NAND_CMD_READ0 0 +#define NAND_CMD_READ1 1 +#define NAND_CMD_RNDOUT 5 +#define NAND_CMD_PAGEPROG 0x10 +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_ERASE1 0x60 +#define NAND_CMD_STATUS 0x70 +#define NAND_CMD_SEQIN 0x80 +#define NAND_CMD_RNDIN 0x85 +#define NAND_CMD_READID 0x90 +#define NAND_CMD_ERASE2 0xd0 +#define NAND_CMD_PARAM 0xec +#define NAND_CMD_GET_FEATURES 0xee +#define NAND_CMD_SET_FEATURES 0xef +#define NAND_CMD_RESET 0xff + +#define NAND_CMD_LOCK 0x2a +#define NAND_CMD_UNLOCK1 0x23 +#define NAND_CMD_UNLOCK2 0x24 + +/* Extended commands for large page devices */ +#define NAND_CMD_READSTART 0x30 +#define NAND_CMD_RNDOUTSTART 0xE0 +#define NAND_CMD_CACHEDPROG 0x15 + +#define NAND_CMD_NONE -1 + +/* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + +#define NAND_DATA_IFACE_CHECK_ONLY -1 + +/* + * Constants for ECC_MODES + */ +typedef enum { + NAND_ECC_NONE, + NAND_ECC_SOFT, + NAND_ECC_HW, + NAND_ECC_HW_SYNDROME, + NAND_ECC_HW_OOB_FIRST, + NAND_ECC_ON_DIE, +} nand_ecc_modes_t; + +enum nand_ecc_algo { + NAND_ECC_UNKNOWN, + NAND_ECC_HAMMING, + NAND_ECC_BCH, +}; + +/* + * Constants for Hardware ECC + */ +/* Reset Hardware ECC for read */ +#define NAND_ECC_READ 0 +/* Reset Hardware ECC for write */ +#define NAND_ECC_WRITE 1 +/* Enable Hardware ECC before syndrome is read back from flash */ +#define NAND_ECC_READSYN 2 + +/* + * Enable generic NAND 'page erased' check. This check is only done when + * ecc.correct() returns -EBADMSG. + * Set this flag if your implementation does not fix bitflips in erased + * pages and you want to rely on the default implementation. + */ +#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) +#define NAND_ECC_MAXIMIZE BIT(1) +/* + * If your controller already sends the required NAND commands when + * reading or writing a page, then the framework is not supposed to + * send READ0 and SEQIN/PAGEPROG respectively. + */ +#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2) + +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + + +/* + * Option constants for bizarre disfunctionality and real + * features. + */ +/* Buswidth is 16 bit */ +#define NAND_BUSWIDTH_16 0x00000002 +/* Chip has cache program function */ +#define NAND_CACHEPRG 0x00000008 +/* + * Chip requires ready check on read (for auto-incremented sequential read). + * True only for small page devices; large page devices do not support + * autoincrement. + */ +#define NAND_NEED_READRDY 0x00000100 + +/* Chip does not allow subpage writes */ +#define NAND_NO_SUBPAGE_WRITE 0x00000200 + +/* Device is one of 'new' xD cards that expose fake nand command set */ +#define NAND_BROKEN_XD 0x00000400 + +/* Device behaves just like nand, but is readonly */ +#define NAND_ROM 0x00000800 + +/* Device supports subpage reads */ +#define NAND_SUBPAGE_READ 0x00001000 + +/* + * Some MLC NANDs need data scrambling to limit bitflips caused by repeated + * patterns. + */ +#define NAND_NEED_SCRAMBLING 0x00002000 + +/* Options valid for Samsung large page devices */ +#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG + +/* Macros to identify the above */ +#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) +#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) +#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE) + +/* Non chip related options */ +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00010000 +/* + * This option is defined if the board driver allocates its own buffers + * (e.g. because it needs them DMA-coherent). + */ +#define NAND_OWN_BUFFERS 0x00020000 +/* Chip may not exist, so silence any errors in scan */ +#define NAND_SCAN_SILENT_NODEV 0x00040000 +/* + * Autodetect nand buswidth with readid/onfi. + * This suppose the driver will configure the hardware in 8 bits mode + * when calling nand_scan_ident, and update its configuration + * before calling nand_scan_tail. + */ +#define NAND_BUSWIDTH_AUTO 0x00080000 +/* + * This option could be defined by controller drivers to protect against + * kmap'ed, vmalloc'ed highmem buffers being passed from upper layers + */ +#define NAND_USE_BOUNCE_BUFFER 0x00100000 + +/* + * In case your controller is implementing ->cmd_ctrl() and is relying on the + * default ->cmdfunc() implementation, you may want to let the core handle the + * tCCS delay which is required when a column change (RNDIN or RNDOUT) is + * requested. + * If your controller already takes care of this delay, you don't need to set + * this flag. + */ +#define NAND_WAIT_TCCS 0x00200000 + +/* Options set by nand scan */ +/* Nand scan has allocated controller struct */ +#define NAND_CONTROLLER_ALLOC 0x80000000 + +/* Cell info constants */ +#define NAND_CI_CHIPNR_MSK 0x03 +#define NAND_CI_CELLTYPE_MSK 0x0C +#define NAND_CI_CELLTYPE_SHIFT 2 + +/* Keep gcc happy */ +struct nand_chip; + +/* ONFI features */ +#define ONFI_FEATURE_16_BIT_BUS (1 << 0) +#define ONFI_FEATURE_EXT_PARAM_PAGE (1 << 7) + +/* ONFI timing mode, used in both asynchronous and synchronous mode */ +#define ONFI_TIMING_MODE_0 (1 << 0) +#define ONFI_TIMING_MODE_1 (1 << 1) +#define ONFI_TIMING_MODE_2 (1 << 2) +#define ONFI_TIMING_MODE_3 (1 << 3) +#define ONFI_TIMING_MODE_4 (1 << 4) +#define ONFI_TIMING_MODE_5 (1 << 5) +#define ONFI_TIMING_MODE_UNKNOWN (1 << 6) + +/* ONFI feature address */ +#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 + +/* Vendor-specific feature address (Micron) */ +#define ONFI_FEATURE_ADDR_READ_RETRY 0x89 +#define ONFI_FEATURE_ON_DIE_ECC 0x90 +#define ONFI_FEATURE_ON_DIE_ECC_EN BIT(3) + +/* ONFI subfeature parameters length */ +#define ONFI_SUBFEATURE_PARAM_LEN 4 + +/* ONFI optional commands SET/GET FEATURES supported? */ +#define ONFI_OPT_CMD_SET_GET_FEATURES (1 << 2) + +struct nand_onfi_params { + /* rev info and features block */ + /* 'O' 'N' 'F' 'I' */ + u8 sig[4]; + __le16 revision; + __le16 features; + __le16 opt_cmd; + u8 reserved0[2]; + __le16 ext_param_page_length; /* since ONFI 2.1 */ + u8 num_of_param_pages; /* since ONFI 2.1 */ + u8 reserved1[17]; + + /* manufacturer information block */ + char manufacturer[12]; + char model[20]; + u8 jedec_id; + __le16 date_code; + u8 reserved2[13]; + + /* memory organization block */ + __le32 byte_per_page; + __le16 spare_bytes_per_page; + __le32 data_bytes_per_ppage; + __le16 spare_bytes_per_ppage; + __le32 pages_per_block; + __le32 blocks_per_lun; + u8 lun_count; + u8 addr_cycles; + u8 bits_per_cell; + __le16 bb_per_lun; + __le16 block_endurance; + u8 guaranteed_good_blocks; + __le16 guaranteed_block_endurance; + u8 programs_per_page; + u8 ppage_attr; + u8 ecc_bits; + u8 interleaved_bits; + u8 interleaved_ops; + u8 reserved3[13]; + + /* electrical parameter block */ + u8 io_pin_capacitance_max; + __le16 async_timing_mode; + __le16 program_cache_timing_mode; + __le16 t_prog; + __le16 t_bers; + __le16 t_r; + __le16 t_ccs; + __le16 src_sync_timing_mode; + u8 src_ssync_features; + __le16 clk_pin_capacitance_typ; + __le16 io_pin_capacitance_typ; + __le16 input_pin_capacitance_typ; + u8 input_pin_capacitance_max; + u8 driver_strength_support; + __le16 t_int_r; + __le16 t_adl; + u8 reserved4[8]; + + /* vendor */ + __le16 vendor_revision; + u8 vendor[88]; + + __le16 crc; +} __packed; + +#define ONFI_CRC_BASE 0x4F4E + +/* Extended ECC information Block Definition (since ONFI 2.1) */ +struct onfi_ext_ecc_info { + u8 ecc_bits; + u8 codeword_size; + __le16 bb_per_lun; + __le16 block_endurance; + u8 reserved[2]; +} __packed; + +#define ONFI_SECTION_TYPE_0 0 /* Unused section. */ +#define ONFI_SECTION_TYPE_1 1 /* for additional sections. */ +#define ONFI_SECTION_TYPE_2 2 /* for ECC information. */ +struct onfi_ext_section { + u8 type; + u8 length; +} __packed; + +#define ONFI_EXT_SECTION_MAX 8 + +/* Extended Parameter Page Definition (since ONFI 2.1) */ +struct onfi_ext_param_page { + __le16 crc; + u8 sig[4]; /* 'E' 'P' 'P' 'S' */ + u8 reserved0[10]; + struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX]; + + /* + * The actual size of the Extended Parameter Page is in + * @ext_param_page_length of nand_onfi_params{}. + * The following are the variable length sections. + * So we do not add any fields below. Please see the ONFI spec. + */ +} __packed; + +struct jedec_ecc_info { + u8 ecc_bits; + u8 codeword_size; + __le16 bb_per_lun; + __le16 block_endurance; + u8 reserved[2]; +} __packed; + +/* JEDEC features */ +#define JEDEC_FEATURE_16_BIT_BUS (1 << 0) + +struct nand_jedec_params { + /* rev info and features block */ + /* 'J' 'E' 'S' 'D' */ + u8 sig[4]; + __le16 revision; + __le16 features; + u8 opt_cmd[3]; + __le16 sec_cmd; + u8 num_of_param_pages; + u8 reserved0[18]; + + /* manufacturer information block */ + char manufacturer[12]; + char model[20]; + u8 jedec_id[6]; + u8 reserved1[10]; + + /* memory organization block */ + __le32 byte_per_page; + __le16 spare_bytes_per_page; + u8 reserved2[6]; + __le32 pages_per_block; + __le32 blocks_per_lun; + u8 lun_count; + u8 addr_cycles; + u8 bits_per_cell; + u8 programs_per_page; + u8 multi_plane_addr; + u8 multi_plane_op_attr; + u8 reserved3[38]; + + /* electrical parameter block */ + __le16 async_sdr_speed_grade; + __le16 toggle_ddr_speed_grade; + __le16 sync_ddr_speed_grade; + u8 async_sdr_features; + u8 toggle_ddr_features; + u8 sync_ddr_features; + __le16 t_prog; + __le16 t_bers; + __le16 t_r; + __le16 t_r_multi_plane; + __le16 t_ccs; + __le16 io_pin_capacitance_typ; + __le16 input_pin_capacitance_typ; + __le16 clk_pin_capacitance_typ; + u8 driver_strength_support; + __le16 t_adl; + u8 reserved4[36]; + + /* ECC and endurance block */ + u8 guaranteed_good_blocks; + __le16 guaranteed_block_endurance; + struct jedec_ecc_info ecc_info[4]; + u8 reserved5[29]; + + /* reserved */ + u8 reserved6[148]; + + /* vendor */ + __le16 vendor_rev_num; + u8 reserved7[88]; + + /* CRC for Parameter Page */ + __le16 crc; +} __packed; + +/** + * struct nand_id - NAND id structure + * @data: buffer containing the id bytes. Currently 8 bytes large, but can + * be extended if required. + * @len: ID length. + */ +struct nand_id { + u8 data[8]; + int len; +}; + +/** + * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices + * @lock: protection lock + * @active: the mtd device which holds the controller currently + * @wq: wait queue to sleep on if a NAND operation is in + * progress used instead of the per chip wait queue + * when a hw controller is available. + */ +struct nand_hw_control { + spinlock_t lock; + struct nand_chip *active; + wait_queue_head_t wq; +}; + +static inline void nand_hw_control_init(struct nand_hw_control *nfc) +{ + nfc->active = NULL; + spin_lock_init(&nfc->lock); + init_waitqueue_head(&nfc->wq); +} + +/** + * struct nand_ecc_step_info - ECC step information of ECC engine + * @stepsize: data bytes per ECC step + * @strengths: array of supported strengths + * @nstrengths: number of supported strengths + */ +struct nand_ecc_step_info { + int stepsize; + const int *strengths; + int nstrengths; +}; + +/** + * struct nand_ecc_caps - capability of ECC engine + * @stepinfos: array of ECC step information + * @nstepinfos: number of ECC step information + * @calc_ecc_bytes: driver's hook to calculate ECC bytes per step + */ +struct nand_ecc_caps { + const struct nand_ecc_step_info *stepinfos; + int nstepinfos; + int (*calc_ecc_bytes)(int step_size, int strength); +}; + +/* a shorthand to generate struct nand_ecc_caps with only one ECC stepsize */ +#define NAND_ECC_CAPS_SINGLE(__name, __calc, __step, ...) \ +static const int __name##_strengths[] = { __VA_ARGS__ }; \ +static const struct nand_ecc_step_info __name##_stepinfo = { \ + .stepsize = __step, \ + .strengths = __name##_strengths, \ + .nstrengths = ARRAY_SIZE(__name##_strengths), \ +}; \ +static const struct nand_ecc_caps __name = { \ + .stepinfos = &__name##_stepinfo, \ + .nstepinfos = 1, \ + .calc_ecc_bytes = __calc, \ +} + +/** + * struct nand_ecc_ctrl - Control structure for ECC + * @mode: ECC mode + * @algo: ECC algorithm + * @steps: number of ECC steps per page + * @size: data bytes per ECC step + * @bytes: ECC bytes per step + * @strength: max number of correctible bits per ECC step + * @total: total number of ECC bytes per page + * @prepad: padding information for syndrome based ECC generators + * @postpad: padding information for syndrome based ECC generators + * @options: ECC specific options (see NAND_ECC_XXX flags defined above) + * @priv: pointer to private ECC control data + * @hwctl: function to control hardware ECC generator. Must only + * be provided if an hardware ECC is available + * @calculate: function for ECC calculation or readback from ECC hardware + * @correct: function for ECC correction, matching to ECC generator (sw/hw). + * Should return a positive number representing the number of + * corrected bitflips, -EBADMSG if the number of bitflips exceed + * ECC strength, or any other error code if the error is not + * directly related to correction. + * If -EBADMSG is returned the input buffers should be left + * untouched. + * @read_page_raw: function to read a raw page without ECC. This function + * should hide the specific layout used by the ECC + * controller and always return contiguous in-band and + * out-of-band data even if they're not stored + * contiguously on the NAND chip (e.g. + * NAND_ECC_HW_SYNDROME interleaves in-band and + * out-of-band data). + * @write_page_raw: function to write a raw page without ECC. This function + * should hide the specific layout used by the ECC + * controller and consider the passed data as contiguous + * in-band and out-of-band data. ECC controller is + * responsible for doing the appropriate transformations + * to adapt to its specific layout (e.g. + * NAND_ECC_HW_SYNDROME interleaves in-band and + * out-of-band data). + * @read_page: function to read a page according to the ECC generator + * requirements; returns maximum number of bitflips corrected in + * any single ECC step, -EIO hw error + * @read_subpage: function to read parts of the page covered by ECC; + * returns same as read_page() + * @write_subpage: function to write parts of the page covered by ECC. + * @write_page: function to write a page according to the ECC generator + * requirements. + * @write_oob_raw: function to write chip OOB data without ECC + * @read_oob_raw: function to read chip OOB data without ECC + * @read_oob: function to read chip OOB data + * @write_oob: function to write chip OOB data + */ +struct nand_ecc_ctrl { + nand_ecc_modes_t mode; + enum nand_ecc_algo algo; + int steps; + int size; + int bytes; + int total; + int strength; + int prepad; + int postpad; + unsigned int options; + void *priv; + void (*hwctl)(struct mtd_info *mtd, int mode); + int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, + uint8_t *ecc_code); + int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, + uint8_t *calc_ecc); + int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page); + int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page); + int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page); + int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offs, uint32_t len, uint8_t *buf, int page); + int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip, + uint32_t offset, uint32_t data_len, + const uint8_t *data_buf, int oob_required, int page); + int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page); + int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page); + int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page); + int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page); + int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, + int page); +}; + +static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc) +{ + return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS); +} + +/** + * struct nand_buffers - buffer structure for read/write + * @ecccalc: buffer pointer for calculated ECC, size is oobsize. + * @ecccode: buffer pointer for ECC read from flash, size is oobsize. + * @databuf: buffer pointer for data, size is (page size + oobsize). + * + * Do not change the order of buffers. databuf and oobrbuf must be in + * consecutive order. + */ +struct nand_buffers { + uint8_t *ecccalc; + uint8_t *ecccode; + uint8_t *databuf; +}; + +/** + * struct nand_sdr_timings - SDR NAND chip timings + * + * This struct defines the timing requirements of a SDR NAND chip. + * These information can be found in every NAND datasheets and the timings + * meaning are described in the ONFI specifications: + * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing + * Parameters) + * + * All these timings are expressed in picoseconds. + * + * @tBERS_max: Block erase time + * @tCCS_min: Change column setup time + * @tPROG_max: Page program time + * @tR_max: Page read time + * @tALH_min: ALE hold time + * @tADL_min: ALE to data loading time + * @tALS_min: ALE setup time + * @tAR_min: ALE to RE# delay + * @tCEA_max: CE# access time + * @tCEH_min: CE# high hold time + * @tCH_min: CE# hold time + * @tCHZ_max: CE# high to output hi-Z + * @tCLH_min: CLE hold time + * @tCLR_min: CLE to RE# delay + * @tCLS_min: CLE setup time + * @tCOH_min: CE# high to output hold + * @tCS_min: CE# setup time + * @tDH_min: Data hold time + * @tDS_min: Data setup time + * @tFEAT_max: Busy time for Set Features and Get Features + * @tIR_min: Output hi-Z to RE# low + * @tITC_max: Interface and Timing Mode Change time + * @tRC_min: RE# cycle time + * @tREA_max: RE# access time + * @tREH_min: RE# high hold time + * @tRHOH_min: RE# high to output hold + * @tRHW_min: RE# high to WE# low + * @tRHZ_max: RE# high to output hi-Z + * @tRLOH_min: RE# low to output hold + * @tRP_min: RE# pulse width + * @tRR_min: Ready to RE# low (data only) + * @tRST_max: Device reset time, measured from the falling edge of R/B# to the + * rising edge of R/B#. + * @tWB_max: WE# high to SR[6] low + * @tWC_min: WE# cycle time + * @tWH_min: WE# high hold time + * @tWHR_min: WE# high to RE# low + * @tWP_min: WE# pulse width + * @tWW_min: WP# transition to WE# low + */ +struct nand_sdr_timings { + u32 tBERS_max; + u32 tCCS_min; + u32 tPROG_max; + u32 tR_max; + u32 tALH_min; + u32 tADL_min; + u32 tALS_min; + u32 tAR_min; + u32 tCEA_max; + u32 tCEH_min; + u32 tCH_min; + u32 tCHZ_max; + u32 tCLH_min; + u32 tCLR_min; + u32 tCLS_min; + u32 tCOH_min; + u32 tCS_min; + u32 tDH_min; + u32 tDS_min; + u32 tFEAT_max; + u32 tIR_min; + u32 tITC_max; + u32 tRC_min; + u32 tREA_max; + u32 tREH_min; + u32 tRHOH_min; + u32 tRHW_min; + u32 tRHZ_max; + u32 tRLOH_min; + u32 tRP_min; + u32 tRR_min; + u64 tRST_max; + u32 tWB_max; + u32 tWC_min; + u32 tWH_min; + u32 tWHR_min; + u32 tWP_min; + u32 tWW_min; +}; + +/** + * enum nand_data_interface_type - NAND interface timing type + * @NAND_SDR_IFACE: Single Data Rate interface + */ +enum nand_data_interface_type { + NAND_SDR_IFACE, +}; + +/** + * struct nand_data_interface - NAND interface timing + * @type: type of the timing + * @timings: The timing, type according to @type + */ +struct nand_data_interface { + enum nand_data_interface_type type; + union { + struct nand_sdr_timings sdr; + } timings; +}; + +/** + * nand_get_sdr_timings - get SDR timing from data interface + * @conf: The data interface + */ +static inline const struct nand_sdr_timings * +nand_get_sdr_timings(const struct nand_data_interface *conf) +{ + if (conf->type != NAND_SDR_IFACE) + return ERR_PTR(-EINVAL); + + return &conf->timings.sdr; +} + +/** + * struct nand_manufacturer_ops - NAND Manufacturer operations + * @detect: detect the NAND memory organization and capabilities + * @init: initialize all vendor specific fields (like the ->read_retry() + * implementation) if any. + * @cleanup: the ->init() function may have allocated resources, ->cleanup() + * is here to let vendor specific code release those resources. + */ +struct nand_manufacturer_ops { + void (*detect)(struct nand_chip *chip); + int (*init)(struct nand_chip *chip); + void (*cleanup)(struct nand_chip *chip); +}; + +/** + * struct nand_chip - NAND Private Flash Chip Data + * @mtd: MTD device registered to the MTD framework + * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the + * flash device + * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the + * 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 + * @block_bad: [REPLACEABLE] check if a block is bad, using OOB markers + * @block_markbad: [REPLACEABLE] mark a block bad + * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling + * ALE/CLE/nCE. Also used to write command and address + * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing + * device ready/busy line. If set to NULL no access to + * ready/busy is available and the ready/busy information + * is read from the chip status register. + * @cmdfunc: [REPLACEABLE] hardwarespecific function for writing + * 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 + * @buf_align: minimum buffer alignment required by a platform + * @hwcontrol: platform-specific hardware control structure + * @erase: [REPLACEABLE] erase function + * @scan_bbt: [REPLACEABLE] function to scan bad block table + * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring + * data from array to read regs (tR). + * @state: [INTERN] the current state of the NAND device + * @oob_poi: "poison value buffer," used for laying out OOB data + * before writing + * @page_shift: [INTERN] number of address bits in a page (column + * address bits). + * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock + * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry + * @chip_shift: [INTERN] number of address bits in one chip + * @options: [BOARDSPECIFIC] various chip options. They can partly + * be set to inform nand_scan about special functionality. + * See the defines for further explanation. + * @bbt_options: [INTERN] bad block specific options. All options used + * here must come from bbm.h. By default, these options + * will be copied to the appropriate nand_bbt_descr's. + * @badblockpos: [INTERN] position of the bad block marker in the oob + * area. + * @badblockbits: [INTERN] minimum number of set bits in a good block's + * bad block marker position; i.e., BBM == 11110111b is + * not bad when badblockbits == 7 + * @bits_per_cell: [INTERN] number of bits per cell. i.e., 1 means SLC. + * @ecc_strength_ds: [INTERN] ECC correctability from the datasheet. + * Minimum amount of bit errors per @ecc_step_ds guaranteed + * to be correctable. If unknown, set to zero. + * @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds, + * also from the datasheet. It is the recommended ECC step + * size, if known; if unknown, set to zero. + * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is + * set to the actually used ONFI mode if the chip is + * ONFI compliant or deduced from the datasheet if + * the NAND chip is not ONFI compliant. + * @numchips: [INTERN] number of physical chips + * @chipsize: [INTERN] the size of one chip for multichip arrays + * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 + * @pagebuf: [INTERN] holds the pagenumber which is currently in + * data_buf. + * @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is + * currently in data_buf. + * @subpagesize: [INTERN] holds the subpagesize + * @id: [INTERN] holds NAND ID + * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), + * non 0 if ONFI supported. + * @jedec_version: [INTERN] holds the chip JEDEC version (BCD encoded), + * non 0 if JEDEC supported. + * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is + * supported, 0 otherwise. + * @jedec_params: [INTERN] holds the JEDEC parameter page when JEDEC is + * supported, 0 otherwise. + * @max_bb_per_die: [INTERN] the max number of bad blocks each die of a + * this nand device will encounter their life times. + * @blocks_per_die: [INTERN] The number of PEBs in a die + * @data_interface: [INTERN] NAND interface timing information + * @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 + * @setup_data_interface: [OPTIONAL] setup the data interface and timing. If + * chipnr is set to %NAND_DATA_IFACE_CHECK_ONLY this + * means the configuration should not be applied but + * only checked. + * @bbt: [INTERN] bad block table pointer + * @bbt_td: [REPLACEABLE] bad block table descriptor for flash + * lookup. + * @bbt_md: [REPLACEABLE] bad block table mirror descriptor + * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial + * bad block scan. + * @controller: [REPLACEABLE] a pointer to a hardware controller + * structure which is shared among multiple independent + * devices. + * @priv: [OPTIONAL] pointer to private chip data + * @manufacturer: [INTERN] Contains manufacturer information + */ + +struct nand_chip { + struct mtd_info mtd; + void __iomem *IO_ADDR_R; + void __iomem *IO_ADDR_W; + + 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); + int (*block_bad)(struct mtd_info *mtd, loff_t ofs); + int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); + void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); + int (*dev_ready)(struct mtd_info *mtd); + void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, + int page_addr); + int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); + int (*erase)(struct mtd_info *mtd, int page); + int (*scan_bbt)(struct mtd_info *mtd); + int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *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 (*setup_data_interface)(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf); + + + int chip_delay; + unsigned int options; + unsigned int bbt_options; + + int page_shift; + int phys_erase_shift; + int bbt_erase_shift; + int chip_shift; + int numchips; + uint64_t chipsize; + int pagemask; + int pagebuf; + unsigned int pagebuf_bitflips; + int subpagesize; + uint8_t bits_per_cell; + uint16_t ecc_strength_ds; + uint16_t ecc_step_ds; + int onfi_timing_mode_default; + int badblockpos; + int badblockbits; + + struct nand_id id; + int onfi_version; + int jedec_version; + union { + struct nand_onfi_params onfi_params; + struct nand_jedec_params jedec_params; + }; + u16 max_bb_per_die; + u32 blocks_per_die; + + struct nand_data_interface *data_interface; + + int read_retries; + + flstate_t state; + + uint8_t *oob_poi; + struct nand_hw_control *controller; + + struct nand_ecc_ctrl ecc; + struct nand_buffers *buffers; + unsigned long buf_align; + struct nand_hw_control hwcontrol; + + uint8_t *bbt; + struct nand_bbt_descr *bbt_td; + struct nand_bbt_descr *bbt_md; + + struct nand_bbt_descr *badblock_pattern; + + void *priv; + + struct { + const struct nand_manufacturer *desc; + void *priv; + } manufacturer; +}; + +extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; +extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; + +static inline void nand_set_flash_node(struct nand_chip *chip, + struct device_node *np) +{ + mtd_set_of_node(&chip->mtd, np); +} + +static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) +{ + return mtd_get_of_node(&chip->mtd); +} + +static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) +{ + return container_of(mtd, struct nand_chip, mtd); +} + +static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) +{ + return &chip->mtd; +} + +static inline void *nand_get_controller_data(struct nand_chip *chip) +{ + return chip->priv; +} + +static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) +{ + chip->priv = priv; +} + +static inline void nand_set_manufacturer_data(struct nand_chip *chip, + void *priv) +{ + chip->manufacturer.priv = priv; +} + +static inline void *nand_get_manufacturer_data(struct nand_chip *chip) +{ + return chip->manufacturer.priv; +} + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_ESMT 0xc8 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c +#define NAND_MFR_AMD 0x01 +#define NAND_MFR_MACRONIX 0xc2 +#define NAND_MFR_EON 0x92 +#define NAND_MFR_SANDISK 0x45 +#define NAND_MFR_INTEL 0x89 +#define NAND_MFR_ATO 0x9b +#define NAND_MFR_WINBOND 0xef + +/* The maximum expected count of bytes in the NAND ID sequence */ +#define NAND_MAX_ID_LEN 8 + +/* + * A helper for defining older NAND chips where the second ID byte fully + * defined the chip, including the geometry (chip size, eraseblock size, page + * size). All these chips have 512 bytes NAND page size. + */ +#define LEGACY_ID_NAND(nm, devid, chipsz, erasesz, opts) \ + { .name = (nm), {{ .dev_id = (devid) }}, .pagesize = 512, \ + .chipsize = (chipsz), .erasesize = (erasesz), .options = (opts) } + +/* + * A helper for defining newer chips which report their page size and + * eraseblock size via the extended ID bytes. + * + * The real difference between LEGACY_ID_NAND and EXTENDED_ID_NAND is that with + * EXTENDED_ID_NAND, manufacturers overloaded the same device ID so that the + * device ID now only represented a particular total chip size (and voltage, + * buswidth), and the page size, eraseblock size, and OOB size could vary while + * using the same device ID. + */ +#define EXTENDED_ID_NAND(nm, devid, chipsz, opts) \ + { .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \ + .options = (opts) } + +#define NAND_ECC_INFO(_strength, _step) \ + { .strength_ds = (_strength), .step_ds = (_step) } +#define NAND_ECC_STRENGTH(type) ((type)->ecc.strength_ds) +#define NAND_ECC_STEP(type) ((type)->ecc.step_ds) + +/** + * struct nand_flash_dev - NAND Flash Device ID Structure + * @name: a human-readable name of the NAND chip + * @dev_id: the device ID (the second byte of the full chip ID array) + * @mfr_id: manufecturer ID part of the full chip ID array (refers the same + * memory address as @id[0]) + * @dev_id: device ID part of the full chip ID array (refers the same memory + * address as @id[1]) + * @id: full device ID array + * @pagesize: size of the NAND page in bytes; if 0, then the real page size (as + * well as the eraseblock size) is determined from the extended NAND + * chip ID array) + * @chipsize: total chip size in MiB + * @erasesize: eraseblock size in bytes (determined from the extended ID if 0) + * @options: stores various chip bit options + * @id_len: The valid length of the @id. + * @oobsize: OOB size + * @ecc: ECC correctability and step information from the datasheet. + * @ecc.strength_ds: The ECC correctability from the datasheet, same as the + * @ecc_strength_ds in nand_chip{}. + * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the + * @ecc_step_ds in nand_chip{}, also from the datasheet. + * For example, the "4bit ECC for each 512Byte" can be set with + * NAND_ECC_INFO(4, 512). + * @onfi_timing_mode_default: the default ONFI timing mode entered after a NAND + * reset. Should be deduced from timings described + * in the datasheet. + * + */ +struct nand_flash_dev { + char *name; + union { + struct { + uint8_t mfr_id; + uint8_t dev_id; + }; + uint8_t id[NAND_MAX_ID_LEN]; + }; + unsigned int pagesize; + unsigned int chipsize; + unsigned int erasesize; + unsigned int options; + uint16_t id_len; + uint16_t oobsize; + struct { + uint16_t strength_ds; + uint16_t step_ds; + } ecc; + int onfi_timing_mode_default; +}; + +/** + * struct nand_manufacturer - NAND Flash Manufacturer structure + * @name: Manufacturer name + * @id: manufacturer ID code of device. + * @ops: manufacturer operations +*/ +struct nand_manufacturer { + int id; + char *name; + const struct nand_manufacturer_ops *ops; +}; + +const struct nand_manufacturer *nand_get_manufacturer(u8 id); + +static inline const char * +nand_manufacturer_name(const struct nand_manufacturer *manufacturer) +{ + return manufacturer ? manufacturer->name : "Unknown"; +} + +extern struct nand_flash_dev nand_flash_ids[]; + +extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; +extern const struct nand_manufacturer_ops samsung_nand_manuf_ops; +extern const struct nand_manufacturer_ops hynix_nand_manuf_ops; +extern const struct nand_manufacturer_ops micron_nand_manuf_ops; +extern const struct nand_manufacturer_ops amd_nand_manuf_ops; +extern const struct nand_manufacturer_ops macronix_nand_manuf_ops; + +int nand_default_bbt(struct mtd_info *mtd); +int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs); +int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs); +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); +int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, + int allowbbt); +int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, uint8_t *buf); + +/** + * struct platform_nand_chip - chip level device structure + * @nr_chips: max. number of chips to scan for + * @chip_offset: chip number offset + * @nr_partitions: number of partitions pointed to by partitions (or zero) + * @partitions: mtd partition list + * @chip_delay: R/B delay value in us + * @options: Option flags, e.g. 16bit buswidth + * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH + * @part_probe_types: NULL-terminated array of probe types + */ +struct platform_nand_chip { + int nr_chips; + int chip_offset; + int nr_partitions; + struct mtd_partition *partitions; + int chip_delay; + unsigned int options; + unsigned int bbt_options; + const char **part_probe_types; +}; + +/* Keep gcc happy */ +struct platform_device; + +/** + * struct platform_nand_ctrl - controller level device structure + * @probe: platform specific function to probe/setup hardware + * @remove: platform specific function to remove/teardown hardware + * @hwcontrol: platform specific hardware control structure + * @dev_ready: platform specific function to read ready/busy pin + * @select_chip: platform specific chip select function + * @cmd_ctrl: platform specific function for controlling + * ALE/CLE/nCE. Also used to write command and address + * @write_buf: platform specific function for write buffer + * @read_buf: platform specific function for read buffer + * @read_byte: platform specific function to read one byte from chip + * @priv: private data to transport driver specific settings + * + * All fields are optional and depend on the hardware driver requirements + */ +struct platform_nand_ctrl { + int (*probe)(struct platform_device *pdev); + void (*remove)(struct platform_device *pdev); + void (*hwcontrol)(struct mtd_info *mtd, int cmd); + int (*dev_ready)(struct mtd_info *mtd); + void (*select_chip)(struct mtd_info *mtd, int chip); + void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); + 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); + unsigned char (*read_byte)(struct mtd_info *mtd); + void *priv; +}; + +/** + * struct platform_nand_data - container structure for platform-specific data + * @chip: chip level chip structure + * @ctrl: controller level device structure + */ +struct platform_nand_data { + struct platform_nand_chip chip; + struct platform_nand_ctrl ctrl; +}; + +/* return the supported features. */ +static inline int onfi_feature(struct nand_chip *chip) +{ + return chip->onfi_version ? le16_to_cpu(chip->onfi_params.features) : 0; +} + +/* return the supported asynchronous timing mode. */ +static inline int onfi_get_async_timing_mode(struct nand_chip *chip) +{ + if (!chip->onfi_version) + return ONFI_TIMING_MODE_UNKNOWN; + return le16_to_cpu(chip->onfi_params.async_timing_mode); +} + +/* return the supported synchronous timing mode. */ +static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) +{ + if (!chip->onfi_version) + return ONFI_TIMING_MODE_UNKNOWN; + return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); +} + +int onfi_init_data_interface(struct nand_chip *chip, + struct nand_data_interface *iface, + enum nand_data_interface_type type, + int timing_mode); + +/* + * Check if it is a SLC nand. + * The !nand_is_slc() can be used to check the MLC/TLC nand chips. + * We do not distinguish the MLC and TLC now. + */ +static inline bool nand_is_slc(struct nand_chip *chip) +{ + return chip->bits_per_cell == 1; +} + +/** + * Check if the opcode's address should be sent only on the lower 8 bits + * @command: opcode to check + */ +static inline int nand_opcode_8bits(unsigned int command) +{ + switch (command) { + case NAND_CMD_READID: + case NAND_CMD_PARAM: + case NAND_CMD_GET_FEATURES: + case NAND_CMD_SET_FEATURES: + return 1; + default: + break; + } + return 0; +} + +/* return the supported JEDEC features. */ +static inline int jedec_feature(struct nand_chip *chip) +{ + return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features) + : 0; +} + +/* get timing characteristics from ONFI timing mode. */ +const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode); +/* get data interface from ONFI timing mode 0, used after reset. */ +const struct nand_data_interface *nand_get_default_data_interface(void); + +int nand_check_erased_ecc_chunk(void *data, int datalen, + void *ecc, int ecclen, + void *extraoob, int extraooblen, + int threshold); + +int nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +int nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail); + +/* Default write_oob implementation */ +int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); + +/* Default write_oob syndrome implementation */ +int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + int page); + +/* Default read_oob implementation */ +int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page); + +/* Default read_oob syndrome implementation */ +int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, + int page); + +/* Stub used by drivers that do not support GET/SET FEATURES operations */ +int nand_onfi_get_set_features_notsupp(struct mtd_info *mtd, + struct nand_chip *chip, int addr, + u8 *subfeature_param); + +/* Default read_page_raw implementation */ +int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page); + +/* Default write_page_raw implementation */ +int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required, int page); + +/* Reset and initialize a NAND device */ +int nand_reset(struct nand_chip *chip, int chipnr); + +/* Free resources held by the NAND device */ +void nand_cleanup(struct nand_chip *chip); + +/* Default extended ID decoding function */ +void nand_decode_ext_id(struct nand_chip *chip); +#endif /* __LINUX_MTD_RAWNAND_H */ diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 2251add65fa7..c759d403cbc0 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h index 65e91d0fa981..72a79c7d0e08 100644 --- a/include/linux/mtd/sharpsl.h +++ b/include/linux/mtd/sharpsl.h @@ -8,7 +8,7 @@ * published by the Free Software Foundation. */ -#include +#include #include #include diff --git a/include/linux/platform_data/mtd-davinci.h b/include/linux/platform_data/mtd-davinci.h index 1cf555aef896..f1a2cf655bdb 100644 --- a/include/linux/platform_data/mtd-davinci.h +++ b/include/linux/platform_data/mtd-davinci.h @@ -28,7 +28,7 @@ #ifndef __ARCH_ARM_DAVINCI_NAND_H #define __ARCH_ARM_DAVINCI_NAND_H -#include +#include #define NANDFCR_OFFSET 0x60 #define NANDFSR_OFFSET 0x64 diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h index f01659026b26..f8c553f92655 100644 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ b/include/linux/platform_data/mtd-nand-s3c2410.h @@ -12,7 +12,7 @@ #ifndef __MTD_NAND_S3C2410_H #define __MTD_NAND_S3C2410_H -#include +#include /** * struct s3c2410_nand_set - define a set of one or more nand chips -- cgit v1.2.3-59-g8ed1b From 811cb897564625f196258f15bab485b9bbdd7a36 Mon Sep 17 00:00:00 2001 From: Cédric Le Goater Date: Wed, 2 Aug 2017 10:51:51 +0200 Subject: mtd: spi-nor: aspeed: set 4B setting for all chips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver made the wrong assumption that the 4B setting was autodetected for all chips of the AST2500 FMC flash controller. This is only the case for the CS0. Signed-off-by: Cédric Le Goater Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/aspeed-smc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c index 0106357421bd..8d3cbe27efb6 100644 --- a/drivers/mtd/spi-nor/aspeed-smc.c +++ b/drivers/mtd/spi-nor/aspeed-smc.c @@ -621,19 +621,18 @@ static void aspeed_smc_chip_set_type(struct aspeed_smc_chip *chip, int type) } /* - * The AST2500 FMC flash controller should be strapped by hardware, or - * autodetected, but the AST2500 SPI flash needs to be set. + * The first chip of the AST2500 FMC flash controller is strapped by + * hardware, or autodetected, but other chips need to be set. Enforce + * the 4B setting for all chips. */ static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip) { struct aspeed_smc_controller *controller = chip->controller; u32 reg; - if (chip->controller->info == &spi_2500_info) { - reg = readl(controller->regs + CE_CONTROL_REG); - reg |= 1 << chip->cs; - writel(reg, controller->regs + CE_CONTROL_REG); - } + reg = readl(controller->regs + CE_CONTROL_REG); + reg |= 1 << chip->cs; + writel(reg, controller->regs + CE_CONTROL_REG); } /* -- cgit v1.2.3-59-g8ed1b From 18ba7101a4e9dee804ed2da6e56ce40f73c8a97f Mon Sep 17 00:00:00 2001 From: Matthew Gerlach Date: Tue, 8 Aug 2017 15:58:26 -0700 Subject: mtd: spi-nor: fix "No newline at end of file" Add a newline to the end of drivers/spi-nor/Makefile to get rid the message, "No newline at end of file", produced by git. This fix will allow subsequent changes to the file to be able to produce clean patches. Signed-off-by: Matthew Gerlach Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index c5f171de0e1a..7d84c5108e17 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -9,4 +9,4 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o -obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o \ No newline at end of file +obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o -- cgit v1.2.3-59-g8ed1b From 90cc62f3431b558ea10b0248e3ba85f656bf61f5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Thu, 6 Jul 2017 17:25:50 -0500 Subject: mtd: spear_smi: add NULL check on devm_kzalloc() return value Check return value from call to devm_kzalloc() in order to prevent a NULL pointer dereference. This issue was detected using Coccinelle and the following semantic patch: @@ expression x; identifier fld; @@ * x = devm_kzalloc(...); ... when != x == NULL x->fld Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/devices/spear_smi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/spear_smi.c b/drivers/mtd/devices/spear_smi.c index dd5069876537..ddf478976013 100644 --- a/drivers/mtd/devices/spear_smi.c +++ b/drivers/mtd/devices/spear_smi.c @@ -775,6 +775,8 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev, pdata->board_flash_info = devm_kzalloc(&pdev->dev, sizeof(*pdata->board_flash_info), GFP_KERNEL); + if (!pdata->board_flash_info) + return -ENOMEM; /* Fill structs for each subnode (flash device) */ while ((pp = of_get_next_child(np, pp))) { -- cgit v1.2.3-59-g8ed1b From ab8d531910e287c44f2fd584f5853426c287131c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Jul 2017 22:07:38 +0200 Subject: mtd: physmap_of: Drop unnecessary static Drop static on a local variable, when the variable is initialized before any possible use. Thus, the static has no benefit. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @bad exists@ position p; identifier x; type T; @@ static T x@p; ... x = <+...x...+> @@ identifier x; expression e; type T; position p != bad.p; @@ -static T x@p; ... when != x when strict ?x = e; // Signed-off-by: Julia Lawall Signed-off-by: Boris Brezillon --- drivers/mtd/maps/physmap_of_versatile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of_versatile.c b/drivers/mtd/maps/physmap_of_versatile.c index 8c6ccded9be8..03f2b6e7bc7e 100644 --- a/drivers/mtd/maps/physmap_of_versatile.c +++ b/drivers/mtd/maps/physmap_of_versatile.c @@ -97,7 +97,7 @@ static const struct of_device_id ebi_match[] = { static int ap_flash_init(struct platform_device *pdev) { struct device_node *ebi; - static void __iomem *ebi_base; + void __iomem *ebi_base; u32 val; int ret; -- cgit v1.2.3-59-g8ed1b From 1d70607750b7fdb4926e121e3bdf0530b5947d6e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2017 16:43:17 -0500 Subject: mtd: Convert to using %pOF instead of full_name Now that we have a custom printf format specifier, convert users of full_name to use %pOF instead. This is preparation to remove storing of the full path string for each node. Signed-off-by: Rob Herring Cc: David Woodhouse Cc: Brian Norris Cc: Boris Brezillon Cc: Marek Vasut Cc: Richard Weinberger Cc: Cyrille Pitchen Cc: linux-mtd@lists.infradead.org Signed-off-by: Boris Brezillon --- drivers/mtd/maps/physmap_of_core.c | 4 ++-- drivers/mtd/maps/sun_uflash.c | 4 ++-- drivers/mtd/ofpart.c | 23 +++++++++++------------ drivers/mtd/spi-nor/hisi-sfc.c | 8 ++++---- 4 files changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index 62fa6836f218..1343c34092ca 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -178,8 +178,8 @@ static int of_flash_probe(struct platform_device *dev) */ p = of_get_property(dp, "reg", &count); if (!p || count % reg_tuple_size != 0) { - dev_err(&dev->dev, "Malformed reg property on %s\n", - dev->dev.of_node->full_name); + dev_err(&dev->dev, "Malformed reg property on %pOF\n", + dev->dev.of_node); err = -EINVAL; goto err_flash_remove; } diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 414956eca0c9..1e73bba6e286 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -55,8 +55,8 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp) /* Non-CFI userflash device-- once I find one we * can work on supporting it. */ - printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n", - dp->full_name, (unsigned long long)op->resource[0].start); + printk(KERN_ERR PFX "Unsupported device at %pOF, 0x%llx\n", + dp, (unsigned long long)op->resource[0].start); return -ENODEV; } diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 2861c7079d7b..6bdf4e525677 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -50,8 +50,8 @@ static int parse_ofpart_partitions(struct mtd_info *master, * when using another parser), so don't be louder than * KERN_DEBUG */ - pr_debug("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n", - master->name, mtd_node->full_name); + pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n", + master->name, mtd_node); ofpart_node = mtd_node; dedicated = false; } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) { @@ -87,9 +87,9 @@ static int parse_ofpart_partitions(struct mtd_info *master, reg = of_get_property(pp, "reg", &len); if (!reg) { if (dedicated) { - pr_debug("%s: ofpart partition %s (%s) missing reg property.\n", - master->name, pp->full_name, - mtd_node->full_name); + pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", + master->name, pp, + mtd_node); goto ofpart_fail; } else { nr_parts--; @@ -100,9 +100,9 @@ static int parse_ofpart_partitions(struct mtd_info *master, a_cells = of_n_addr_cells(pp); s_cells = of_n_size_cells(pp); if (len / 4 != a_cells + s_cells) { - pr_debug("%s: ofpart partition %s (%s) error parsing reg property.\n", - master->name, pp->full_name, - mtd_node->full_name); + pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", + master->name, pp, + mtd_node); goto ofpart_fail; } @@ -131,8 +131,8 @@ static int parse_ofpart_partitions(struct mtd_info *master, return nr_parts; ofpart_fail: - pr_err("%s: error parsing ofpart partition %s (%s)\n", - master->name, pp->full_name, mtd_node->full_name); + pr_err("%s: error parsing ofpart partition %pOF (%pOF)\n", + master->name, pp, mtd_node); ret = -EINVAL; ofpart_none: of_node_put(pp); @@ -166,8 +166,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, if (!part) return 0; /* No partitions found */ - pr_warn("Device tree uses obsolete partition map binding: %s\n", - dp->full_name); + pr_warn("Device tree uses obsolete partition map binding: %pOF\n", dp); nr_parts = plen / sizeof(part[0]); diff --git a/drivers/mtd/spi-nor/hisi-sfc.c b/drivers/mtd/spi-nor/hisi-sfc.c index d1106832b9d5..04f9fb5cd9b6 100644 --- a/drivers/mtd/spi-nor/hisi-sfc.c +++ b/drivers/mtd/spi-nor/hisi-sfc.c @@ -355,16 +355,16 @@ static int hisi_spi_nor_register(struct device_node *np, ret = of_property_read_u32(np, "reg", &priv->chipselect); if (ret) { - dev_err(dev, "There's no reg property for %s\n", - np->full_name); + dev_err(dev, "There's no reg property for %pOF\n", + np); return ret; } ret = of_property_read_u32(np, "spi-max-frequency", &priv->clkrate); if (ret) { - dev_err(dev, "There's no spi-max-frequency property for %s\n", - np->full_name); + dev_err(dev, "There's no spi-max-frequency property for %pOF\n", + np); return ret; } priv->host = host; -- cgit v1.2.3-59-g8ed1b From 680025932f226eef8e905a4e2a84512970b62622 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:05 +0530 Subject: mtd: ichxrom: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/ichxrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index 976d42f63aef..1888c5bf13f8 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -323,7 +323,7 @@ static void ichxrom_remove_one(struct pci_dev *pdev) ichxrom_cleanup(window); } -static struct pci_device_id ichxrom_pci_tbl[] = { +static const struct pci_device_id ichxrom_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, @@ -351,7 +351,7 @@ static struct pci_driver ichxrom_driver = { static int __init init_ichxrom(void) { struct pci_dev *pdev; - struct pci_device_id *id; + const struct pci_device_id *id; pdev = NULL; for (id = ichxrom_pci_tbl; id->vendor; id++) { -- cgit v1.2.3-59-g8ed1b From 30105a2c35061bd989d293a4637d9705221b282f Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:06 +0530 Subject: mtd: amd76xrom: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/amd76xrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index f2b68667ea59..26de0a1d08cf 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -296,7 +296,7 @@ static void amd76xrom_remove_one(struct pci_dev *pdev) amd76xrom_cleanup(window); } -static struct pci_device_id amd76xrom_pci_tbl[] = { +static const struct pci_device_id amd76xrom_pci_tbl[] = { { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, @@ -319,7 +319,7 @@ static struct pci_driver amd76xrom_driver = { static int __init init_amd76xrom(void) { struct pci_dev *pdev; - struct pci_device_id *id; + const struct pci_device_id *id; pdev = NULL; for(id = amd76xrom_pci_tbl; id->vendor; id++) { pdev = pci_get_device(id->vendor, id->device, NULL); -- cgit v1.2.3-59-g8ed1b From 01cac4d2b5a0fdf5316ff611f73e8e23c308d50a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:07 +0530 Subject: mtd: esb2rom: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/esb2rom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 9646b0766ce0..da9f6d76ce1d 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -384,7 +384,7 @@ static void esb2rom_remove_one(struct pci_dev *pdev) esb2rom_cleanup(window); } -static struct pci_device_id esb2rom_pci_tbl[] = { +static const struct pci_device_id esb2rom_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, @@ -414,7 +414,7 @@ static struct pci_driver esb2rom_driver = { static int __init init_esb2rom(void) { struct pci_dev *pdev; - struct pci_device_id *id; + const struct pci_device_id *id; int retVal; pdev = NULL; -- cgit v1.2.3-59-g8ed1b From 1372734425529cdb11940eb06cd1cc864e88da12 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:08 +0530 Subject: mtd: ck804xrom: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/ck804xrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 4f206a99164c..584962ec49f8 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -326,7 +326,7 @@ static void ck804xrom_remove_one(struct pci_dev *pdev) ck804xrom_cleanup(window); } -static struct pci_device_id ck804xrom_pci_tbl[] = { +static const struct pci_device_id ck804xrom_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0051), .driver_data = DEV_CK804 }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0360), .driver_data = DEV_MCP55 }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, 0x0361), .driver_data = DEV_MCP55 }, @@ -353,7 +353,7 @@ static struct pci_driver ck804xrom_driver = { static int __init init_ck804xrom(void) { struct pci_dev *pdev; - struct pci_device_id *id; + const struct pci_device_id *id; int retVal; pdev = NULL; -- cgit v1.2.3-59-g8ed1b From 4f558d636b0de9aa5d0acaf87a7f83c965ced6d7 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:09 +0530 Subject: mtd: intel_vr_nor: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/intel_vr_nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index 8bf79775e7c1..dd5d6855f543 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -170,7 +170,7 @@ static int vr_nor_init_maps(struct vr_nor_mtd *p) return err; } -static struct pci_device_id vr_nor_pci_ids[] = { +static const struct pci_device_id vr_nor_pci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)}, {0,} }; -- cgit v1.2.3-59-g8ed1b From d64dc9c8470da1582bf0d853c8a4ae05ad31815b Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 3 Aug 2017 21:52:10 +0530 Subject: mtd: pci: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/maps/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index eb0242e0b2d9..7b3bb40aff72 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -228,7 +228,7 @@ static struct mtd_pci_info intel_dc21285_info = { * PCI device ID table */ -static struct pci_device_id mtd_pci_ids[] = { +static const struct pci_device_id mtd_pci_ids[] = { { .vendor = PCI_VENDOR_ID_INTEL, .device = 0x530d, -- cgit v1.2.3-59-g8ed1b From 871e7c01ca55fdc714691206f041e48f695f444c Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sun, 6 Aug 2017 14:55:01 +0200 Subject: mtd: physmap_of: Fix resources leak in 'of_flash_probe()' If 'of_flash_probe_gemini()' or 'of_flash_probe_versatile()' fail, we must reslease some resources, as already done in all error handling paths in this function. Signed-off-by: Christophe JAILLET Signed-off-by: Boris Brezillon --- drivers/mtd/maps/physmap_of_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of_core.c b/drivers/mtd/maps/physmap_of_core.c index 1343c34092ca..b1bd4faecfb2 100644 --- a/drivers/mtd/maps/physmap_of_core.c +++ b/drivers/mtd/maps/physmap_of_core.c @@ -235,10 +235,10 @@ static int of_flash_probe(struct platform_device *dev) err = of_flash_probe_gemini(dev, dp, &info->list[i].map); if (err) - return err; + goto err_out; err = of_flash_probe_versatile(dev, dp, &info->list[i].map); if (err) - return err; + goto err_out; err = -ENOMEM; info->list[i].map.virt = ioremap(info->list[i].map.phys, -- cgit v1.2.3-59-g8ed1b From 2acc717b7a196c355f3a126a9ac4e9df784113e7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 8 Aug 2017 21:05:10 +0200 Subject: mtd: physmap_of: Retire Gemini pad control I wrote a proper pin control driver for the Gemini. Retire this SoC-specific pad control and rely on the pin controller to manage this. Signed-off-by: Linus Walleij Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/maps/physmap_of_gemini.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c index 05b286b5289f..4ed1a6bb4d3c 100644 --- a/drivers/mtd/maps/physmap_of_gemini.c +++ b/drivers/mtd/maps/physmap_of_gemini.c @@ -43,13 +43,6 @@ #define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */ -/* Miscellaneous Control Register */ -#define GLOBAL_MISC_CTRL 0x30 -#define FLASH_PADS_MASK 0x07 -#define NAND_PADS_DISABLE BIT(2) -#define PFLASH_PADS_DISABLE BIT(1) -#define SFLASH_PADS_DISABLE BIT(0) - static const struct of_device_id syscon_match[] = { { .compatible = "cortina,gemini-syscon" }, { }, @@ -102,15 +95,6 @@ int of_flash_probe_gemini(struct platform_device *pdev, map->bankwidth * 8); } - /* Activate parallel (NOR flash) mode */ - ret = regmap_update_bits(rmap, GLOBAL_MISC_CTRL, - FLASH_PADS_MASK, - SFLASH_PADS_DISABLE | NAND_PADS_DISABLE); - if (ret) { - dev_err(dev, "unable to set up physmap pads\n"); - return -ENODEV; - } - dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n"); return 0; -- cgit v1.2.3-59-g8ed1b From 75864b301c91bf41ec2fb49ce4efb62fcb48b954 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 19 Aug 2017 13:52:17 +0530 Subject: mtd: make device_type const Make this const as it is only stored in the type field of a device structure, which is const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index f872a99501ed..e7ea842ba3db 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -340,7 +340,7 @@ static struct attribute *mtd_attrs[] = { }; ATTRIBUTE_GROUPS(mtd); -static struct device_type mtd_devtype = { +static const struct device_type mtd_devtype = { .name = "mtd", .groups = mtd_groups, .release = mtd_release, -- cgit v1.2.3-59-g8ed1b From 18f7ce2f449504c31a2f2caaeb65430812dc3c43 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 22 Aug 2017 12:51:16 +0300 Subject: mtd: spi-nor: add support for Microchip sst26vf064b QSPI memory Add support for Microchip sst26vf064b QSPI memory. Signed-off-by: Claudiu Beznea Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index c70c2ebc8661..cf1d4a15e10a 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1092,6 +1092,7 @@ static const struct flash_info spi_nor_ids[] = { { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8, SECT_4K) }, { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, + { "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, /* ST Microelectronics -- newer production may have feature updates */ { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, -- cgit v1.2.3-59-g8ed1b From f84674b82af2c3ea68b9032d1244f364e46cc75d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 2 Jun 2017 12:18:24 +0200 Subject: mtd: nand: Fix various memory leaks in core The nand_scan_ident() function is not expected to allocate resources, and people are usually not calling nand_cleanup() if something fails between nand_scan_ident() and nand_scan_tail(). Move all functions that may allocate resource to the nand_scan_tail() path to prevent such resource leaks. Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 118 ++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 54d6194fb180..abcb15fba484 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3856,7 +3856,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) const struct nand_manufacturer *manufacturer; struct mtd_info *mtd = nand_to_mtd(chip); int busw; - int i, ret; + int i; u8 *id_data = chip->id.data; u8 maf_id, dev_id; @@ -3997,10 +3997,6 @@ ident_done: if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - ret = nand_manufacturer_init(chip); - if (ret) - return ret; - pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id); @@ -4208,23 +4204,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return ret; } - /* Initialize the ->data_interface field. */ - ret = nand_init_data_interface(chip); - if (ret) - goto err_nand_init; - - /* - * Setup the data interface correctly on the chip and controller side. - * This explicit call to nand_setup_data_interface() is only required - * for the first die, because nand_reset() has been called before - * ->data_interface and ->default_onfi_timing_mode were set. - * For the other dies, nand_reset() will automatically switch to the - * best mode for us. - */ - ret = nand_setup_data_interface(chip, 0); - if (ret) - goto err_nand_init; - nand_maf_id = chip->id.data[0]; nand_dev_id = chip->id.data[1]; @@ -4254,12 +4233,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, mtd->size = i * chip->chipsize; return 0; - -err_nand_init: - /* Free manufacturer priv data. */ - nand_manufacturer_cleanup(chip); - - return ret; } EXPORT_SYMBOL(nand_scan_ident); @@ -4646,55 +4619,60 @@ int nand_scan_tail(struct mtd_info *mtd) struct nand_chip *chip = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; struct nand_buffers *nbuf = NULL; - int ret; + int ret, i; /* New bad blocks should be marked in OOB, flash-based BBT, or both */ if (WARN_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && !(chip->bbt_options & NAND_BBT_USE_FLASH))) { - ret = -EINVAL; - goto err_ident; + return -EINVAL; } if (invalid_ecc_page_accessors(chip)) { pr_err("Invalid ECC page accessors setup\n"); - ret = -EINVAL; - goto err_ident; + return -EINVAL; } if (!(chip->options & NAND_OWN_BUFFERS)) { nbuf = kzalloc(sizeof(*nbuf), GFP_KERNEL); - if (!nbuf) { - ret = -ENOMEM; - goto err_ident; - } + if (!nbuf) + return -ENOMEM; nbuf->ecccalc = kmalloc(mtd->oobsize, GFP_KERNEL); if (!nbuf->ecccalc) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } nbuf->ecccode = kmalloc(mtd->oobsize, GFP_KERNEL); if (!nbuf->ecccode) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } nbuf->databuf = kmalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL); if (!nbuf->databuf) { ret = -ENOMEM; - goto err_free; + goto err_free_nbuf; } chip->buffers = nbuf; - } else { - if (!chip->buffers) { - ret = -ENOMEM; - goto err_ident; - } + } else if (!chip->buffers) { + return -ENOMEM; } + /* + * FIXME: some NAND manufacturer drivers expect the first die to be + * selected when manufacturer->init() is called. They should be fixed + * to explictly select the relevant die when interacting with the NAND + * chip. + */ + chip->select_chip(mtd, 0); + ret = nand_manufacturer_init(chip); + chip->select_chip(mtd, -1); + if (ret) + goto err_free_nbuf; + /* Set the internal oob buffer location, just after the page data */ chip->oob_poi = chip->buffers->databuf + mtd->writesize; @@ -4716,7 +4694,7 @@ int nand_scan_tail(struct mtd_info *mtd) WARN(1, "No oob scheme defined for oobsize %d\n", mtd->oobsize); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } } @@ -4731,7 +4709,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->calculate || !ecc->correct || !ecc->hwctl) { WARN(1, "No ECC functions supplied; hardware ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } if (!ecc->read_page) ecc->read_page = nand_read_page_hwecc_oob_first; @@ -4763,7 +4741,7 @@ int nand_scan_tail(struct mtd_info *mtd) ecc->write_page == nand_write_page_hwecc)) { WARN(1, "No ECC functions supplied; hardware ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* Use standard syndrome read/write page function? */ if (!ecc->read_page) @@ -4783,7 +4761,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->strength) { WARN(1, "Driver must set ecc.strength when using hardware ECC\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } break; } @@ -4796,7 +4774,7 @@ int nand_scan_tail(struct mtd_info *mtd) ret = nand_set_ecc_soft_ops(mtd); if (ret) { ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } break; @@ -4804,7 +4782,7 @@ int nand_scan_tail(struct mtd_info *mtd) if (!ecc->read_page || !ecc->write_page) { WARN(1, "No ECC functions supplied; on-die ECC not possible\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } if (!ecc->read_oob) ecc->read_oob = nand_read_oob_std; @@ -4828,7 +4806,7 @@ int nand_scan_tail(struct mtd_info *mtd) default: WARN(1, "Invalid NAND_ECC_MODE %d\n", ecc->mode); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* For many systems, the standard OOB write also works for raw */ @@ -4849,13 +4827,13 @@ int nand_scan_tail(struct mtd_info *mtd) if (ecc->steps * ecc->size != mtd->writesize) { WARN(1, "Invalid ECC parameters\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } ecc->total = ecc->steps * ecc->bytes; if (ecc->total > mtd->oobsize) { WARN(1, "Total number of ECC bytes exceeded oobsize\n"); ret = -EINVAL; - goto err_free; + goto err_nand_manuf_cleanup; } /* @@ -4937,6 +4915,21 @@ int nand_scan_tail(struct mtd_info *mtd) if (!mtd->bitflip_threshold) mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); + /* Initialize the ->data_interface field. */ + ret = nand_init_data_interface(chip); + if (ret) + goto err_nand_manuf_cleanup; + + /* Enter fastest possible mode on all dies. */ + for (i = 0; i < chip->numchips; i++) { + chip->select_chip(mtd, i); + ret = nand_setup_data_interface(chip, i); + chip->select_chip(mtd, -1); + + if (ret) + goto err_nand_data_iface_cleanup; + } + /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; @@ -4944,10 +4937,17 @@ int nand_scan_tail(struct mtd_info *mtd) /* Build bad block table */ ret = chip->scan_bbt(mtd); if (ret) - goto err_free; + goto err_nand_data_iface_cleanup; + return 0; -err_free: +err_nand_data_iface_cleanup: + nand_release_data_interface(chip); + +err_nand_manuf_cleanup: + nand_manufacturer_cleanup(chip); + +err_free_nbuf: if (nbuf) { kfree(nbuf->databuf); kfree(nbuf->ecccode); @@ -4955,12 +4955,6 @@ err_free: kfree(nbuf); } -err_ident: - /* Clean up nand_scan_ident(). */ - - /* Free manufacturer priv data. */ - nand_manufacturer_cleanup(chip); - return ret; } EXPORT_SYMBOL(nand_scan_tail); -- cgit v1.2.3-59-g8ed1b From 5158bd5597e4c0939db3ecefbcbf492c425e611c Mon Sep 17 00:00:00 2001 From: Jean-Louis Thekekara Date: Thu, 29 Jun 2017 19:08:30 +0200 Subject: mtd: nand: remove hard-coded NAND ids length This commit removes hard-coded '8' used for looping into struct nand_chip.id.data array. NAND_MAX_ID_LEN has been introduced by Artem Bityutskiy in 53552d22bfe1f for defining ids length in nand_flash_ids[] list. This commit unifies ids length in nand base driver. Signed-off-by: Jean-Louis Thekekara Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 4 ++-- include/linux/mtd/nand.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index abcb15fba484..ab2804379b0d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3886,7 +3886,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read entire ID string */ - for (i = 0; i < 8; i++) + for (i = 0; i < ARRAY_SIZE(chip->id.data); i++) id_data[i] = chip->read_byte(mtd); if (id_data[0] != maf_id || id_data[1] != dev_id) { @@ -3895,7 +3895,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return -ENODEV; } - chip->id.len = nand_id_len(id_data, 8); + chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data)); /* Try to identify manufacturer */ manufacturer = nand_get_manufacturer(maf_id); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 8a6522e82f03..297684013977 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -439,14 +439,16 @@ struct nand_jedec_params { __le16 crc; } __packed; +/* The maximum expected count of bytes in the NAND ID sequence */ +#define NAND_MAX_ID_LEN 8 + /** * struct nand_id - NAND id structure - * @data: buffer containing the id bytes. Currently 8 bytes large, but can - * be extended if required. + * @data: buffer containing the id bytes. * @len: ID length. */ struct nand_id { - u8 data[8]; + u8 data[NAND_MAX_ID_LEN]; int len; }; @@ -1018,8 +1020,6 @@ static inline void *nand_get_manufacturer_data(struct nand_chip *chip) #define NAND_MFR_ATO 0x9b #define NAND_MFR_WINBOND 0xef -/* The maximum expected count of bytes in the NAND ID sequence */ -#define NAND_MAX_ID_LEN 8 /* * A helper for defining older NAND chips where the second ID byte fully -- cgit v1.2.3-59-g8ed1b From 03fba86b63b95cf4377dd6cf8eaca9b225ed4a2d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:54:07 -0300 Subject: mtd: nand: vf610: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 744ab10e8962..9e496727e781 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -814,12 +814,16 @@ static int vf610_nfc_suspend(struct device *dev) static int vf610_nfc_resume(struct device *dev) { + int err; + struct mtd_info *mtd = dev_get_drvdata(dev); struct vf610_nfc *nfc = mtd_to_nfc(mtd); pinctrl_pm_select_default_state(dev); - clk_prepare_enable(nfc->clk); + err = clk_prepare_enable(nfc->clk); + if (err) + return err; vf610_nfc_preinit_controller(nfc); vf610_nfc_init_controller(nfc); -- cgit v1.2.3-59-g8ed1b From f7b8103ec33e53b73b60551ca7bb8f5350d06d6d Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 17 Jul 2017 21:54:08 -0300 Subject: mtd: nand: vf610: Remove unneeded pinctrl_pm_select_default_state() pinctrl_pm_select_default_state() is already the default pinctrl state and since pinctrl_pm_select_sleep_state() is not used in this driver, there is no need to explicitly call pinctrl_pm_select_default_state(). Signed-off-by: Fabio Estevam Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 9e496727e781..b88a0c91b455 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -819,8 +818,6 @@ static int vf610_nfc_resume(struct device *dev) struct mtd_info *mtd = dev_get_drvdata(dev); struct vf610_nfc *nfc = mtd_to_nfc(mtd); - pinctrl_pm_select_default_state(dev); - err = clk_prepare_enable(nfc->clk); if (err) return err; -- cgit v1.2.3-59-g8ed1b From 10777de570016471fd929869c7830a7772893e39 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 3 Aug 2017 17:56:39 +0200 Subject: mtd: nand: qcom: fix config error for BCH The configuration for BCH is not correct in the current driver. The ECC_CFG_ECC_DISABLE bit defines whether to enable or disable the BCH ECC in which 0x1 : BCH_DISABLED 0x0 : BCH_ENABLED But currently host->bch_enabled is being assigned to BCH_DISABLED. Fixes: c76b78d8ec05a ("mtd: nand: Qualcomm NAND controller driver") Cc: stable@vger.kernel.org Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 88af7145a51a..9c4c1ccb5d0f 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -1893,7 +1893,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) | wide_bus << WIDE_FLASH | 1 << DEV0_CFG1_ECC_DISABLE; - host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE + host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE | 0 << ECC_SW_RESET | host->cw_data << ECC_NUM_DATA_BYTES | 1 << ECC_FORCE_CLK_OPEN -- cgit v1.2.3-59-g8ed1b From e806423aca5bf52b1e14e83befa9d4bac8c17ee1 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:53 +0530 Subject: mtd: nand: qcom: remove redundant chip select compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the compatible “qcom,nandcs” is being used for each connected NAND device to support for multiple NAND devices in the same bus. The same thing can be achieved by looking reg property for each sub nodes which contains the chip select number so this patch removes the use of “qcom,nandcs” for specifying NAND device sub nodes. Since there is no user for this driver currently in so changing compatible string is safe. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 9c4c1ccb5d0f..ec5ec2c4b688 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2127,22 +2127,20 @@ static int qcom_nandc_probe(struct platform_device *pdev) goto err_setup; for_each_available_child_of_node(dn, child) { - if (of_device_is_compatible(child, "qcom,nandcs")) { - host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - of_node_put(child); - ret = -ENOMEM; - goto err_cs_init; - } - - ret = qcom_nand_host_init(nandc, host, child); - if (ret) { - devm_kfree(dev, host); - continue; - } + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + of_node_put(child); + ret = -ENOMEM; + goto err_cs_init; + } - list_add_tail(&host->node, &nandc->host_list); + ret = qcom_nand_host_init(nandc, host, child); + if (ret) { + devm_kfree(dev, host); + continue; } + + list_add_tail(&host->node, &nandc->host_list); } if (list_empty(&nandc->host_list)) { -- cgit v1.2.3-59-g8ed1b From bde4330aad1b775853431f9abe014a909c945726 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:55 +0530 Subject: mtd: nand: qcom: reorganize nand page read Each NAND page consist of multiple codewords. Following is sequence for NAND page read according to hardware guide. 1. Program Power-up configuration, page row, page column address and flash configuration registers. 2. Write NAND_FLASH_CMD followed by NANC_EXEC_CMD for each codeword. 3. Read NAND_FLASH_STATUS for each codeword. The step 1 should be done once for each page and step 2,3 should be done for each codeword. Currently, all the 3 steps are being done for each codeword which is wrong. Now this patch reorganizes read page functions to configure page specific register once and per codeword specific registers for each NAND ECC step. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index ec5ec2c4b688..97a4c080ce7a 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -602,15 +602,23 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, } /* - * helper to prepare dma descriptors to configure registers needed for reading a - * codeword/step in a page + * Helper to prepare DMA descriptors for configuring registers + * before reading a NAND page. */ -static void config_cw_read(struct qcom_nand_controller *nandc) +static void config_nand_page_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 3); + write_reg_dma(nandc, NAND_ADDR0, 2); write_reg_dma(nandc, NAND_DEV0_CFG0, 3); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); +} +/* + * Helper to prepare DMA descriptors for configuring registers + * before reading each codeword in NAND page. + */ +static void config_nand_cw_read(struct qcom_nand_controller *nandc) +{ + write_reg_dma(nandc, NAND_FLASH_CMD, 1); write_reg_dma(nandc, NAND_EXEC_CMD, 1); read_reg_dma(nandc, NAND_FLASH_STATUS, 2); @@ -618,9 +626,15 @@ static void config_cw_read(struct qcom_nand_controller *nandc) } /* - * helpers to prepare dma descriptors used to configure registers needed for - * writing a codeword/step in a page + * Helper to prepare dma descriptors to configure registers needed for reading a + * single codeword in page */ +static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) +{ + config_nand_page_read(nandc); + config_nand_cw_read(nandc); +} + static void config_cw_write_pre(struct qcom_nand_controller *nandc) { write_reg_dma(nandc, NAND_FLASH_CMD, 3); @@ -689,7 +703,7 @@ static int nandc_param(struct qcom_nand_host *host) nandc->buf_count = 512; memset(nandc->data_buffer, 0xff, nandc->buf_count); - config_cw_read(nandc); + config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, nandc->buf_count); @@ -1102,6 +1116,8 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, struct nand_ecc_ctrl *ecc = &chip->ecc; int i, ret; + config_nand_page_read(nandc); + /* queue cmd descs for each codeword */ for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -1115,7 +1131,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_size = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_read(nandc); + config_nand_cw_read(nandc); if (data_buf) read_data_dma(nandc, FLASH_BUF_ACC, data_buf, @@ -1175,7 +1191,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, true); - config_cw_read(nandc); + config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size); @@ -1225,6 +1241,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, host->use_ecc = false; update_rw_regs(host, ecc->steps, true); + config_nand_page_read(nandc); for (i = 0; i < ecc->steps; i++) { int data_size1, data_size2, oob_size1, oob_size2; @@ -1243,7 +1260,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_read(nandc); + config_nand_cw_read(nandc); read_data_dma(nandc, reg_off, data_buf, data_size1); reg_off += data_size1; -- cgit v1.2.3-59-g8ed1b From 77cc5364770387380dd5353625986576209de21c Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:56 +0530 Subject: mtd: nand: qcom: reorganize nand page write Each NAND page consist of multiple codewords. Following is sequence for NAND page write according to hardware guide. 1. Program Power-up configuration, page row, page column address and flash configuration registers. 2. Write NAND_FLASH_CMD followed by NANC_EXEC_CMD for each codeword. 3. Read NAND_FLASH_STATUS for each codeword. The step 1 should be done once for each page and step 2,3 should be done for each codeword. Currently, all the 3 steps are being done for each codeword which is wrong. Now this patch reorganizes page write functions to configure page specific register once and per codeword specific registers for each NAND ECC step. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 97a4c080ce7a..52c0287730e8 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -635,15 +635,24 @@ static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) config_nand_cw_read(nandc); } -static void config_cw_write_pre(struct qcom_nand_controller *nandc) +/* + * Helper to prepare DMA descriptors used to configure registers needed for + * before writing a NAND page. + */ +static void config_nand_page_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 3); + write_reg_dma(nandc, NAND_ADDR0, 2); write_reg_dma(nandc, NAND_DEV0_CFG0, 3); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); } -static void config_cw_write_post(struct qcom_nand_controller *nandc) +/* + * Helper to prepare DMA descriptors for configuring registers + * before writing each codeword in NAND page. + */ +static void config_nand_cw_write(struct qcom_nand_controller *nandc) { + write_reg_dma(nandc, NAND_FLASH_CMD, 1); write_reg_dma(nandc, NAND_EXEC_CMD, 1); read_reg_dma(nandc, NAND_FLASH_STATUS, 1); @@ -1326,6 +1335,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, host->use_ecc = true; update_rw_regs(host, ecc->steps, false); + config_nand_page_write(nandc); for (i = 0; i < ecc->steps; i++) { int data_size, oob_size; @@ -1339,7 +1349,6 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_size = ecc->bytes; } - config_cw_write_pre(nandc); write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size); @@ -1357,7 +1366,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_buf, oob_size); } - config_cw_write_post(nandc); + config_nand_cw_write(nandc); data_buf += data_size; oob_buf += oob_size; @@ -1390,6 +1399,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, host->use_ecc = false; update_rw_regs(host, ecc->steps, false); + config_nand_page_write(nandc); for (i = 0; i < ecc->steps; i++) { int data_size1, data_size2, oob_size1, oob_size2; @@ -1408,8 +1418,6 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - config_cw_write_pre(nandc); - write_data_dma(nandc, reg_off, data_buf, data_size1); reg_off += data_size1; data_buf += data_size1; @@ -1425,7 +1433,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, write_data_dma(nandc, reg_off, oob_buf, oob_size2); oob_buf += oob_size2; - config_cw_write_post(nandc); + config_nand_cw_write(nandc); } ret = submit_descs(nandc); @@ -1475,10 +1483,10 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, false); - config_cw_write_pre(nandc); + config_nand_page_write(nandc); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, data_size + oob_size); - config_cw_write_post(nandc); + config_nand_cw_write(nandc); ret = submit_descs(nandc); @@ -1560,9 +1568,9 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) set_address(host, host->cw_size * (ecc->steps - 1), page); update_rw_regs(host, 1, false); - config_cw_write_pre(nandc); + config_nand_page_write(nandc); write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size); - config_cw_write_post(nandc); + config_nand_cw_write(nandc); ret = submit_descs(nandc); -- cgit v1.2.3-59-g8ed1b From eb6df28ef63d0ac9d8bb86483d8840fa95da4a8b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:57 +0530 Subject: mtd: nand: qcom: remove memset for clearing read register buffer The memset in clear_read_regs is overhead. All the register data will be filled by DMA during NAND operation so making these register variables zero is not required. Signed-off-by: Abhishek Sahu Reviewed-by: Archit Taneja Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 52c0287730e8..02be4ac0f101 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -823,8 +823,6 @@ static void free_descs(struct qcom_nand_controller *nandc) static void clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; - memset(nandc->reg_read_buf, 0, - MAX_REG_RD * sizeof(*nandc->reg_read_buf)); } static void pre_command(struct qcom_nand_host *host, int command) -- cgit v1.2.3-59-g8ed1b From 89f5127c4b0dcd847a2a0b5d0be37ca7366af9e5 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Wed, 19 Jul 2017 17:17:58 +0530 Subject: mtd: nand: qcom: reorganize nand devices probing The NAND controller can support multiple NAND devices having different page sizes. Future code will require us to allocate memory based on the maximum number of codewords among all the devices. We reorganize the NAND device probing such that the ONFI parameters are first read for each connected device to identify the maximum number of codewords possible, and only then proceed with MTD device registration (i.e, call nand_scan_tail and mtd_device_register). This is a reorganization of the existing code and will not change any functionality. Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 88 +++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 02be4ac0f101..0e727d79f2ce 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2057,14 +2057,67 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, return ret; ret = qcom_nand_host_setup(host); - if (ret) - return ret; + + return ret; +} + +static int qcom_nand_mtd_register(struct qcom_nand_controller *nandc, + struct qcom_nand_host *host, + struct device_node *dn) +{ + struct nand_chip *chip = &host->chip; + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; ret = nand_scan_tail(mtd); if (ret) return ret; - return mtd_device_register(mtd, NULL, 0); + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + nand_cleanup(mtd_to_nand(mtd)); + + return ret; +} + +static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) +{ + struct device *dev = nandc->dev; + struct device_node *dn = dev->of_node, *child; + struct qcom_nand_host *host, *tmp; + int ret; + + for_each_available_child_of_node(dn, child) { + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + of_node_put(child); + return -ENOMEM; + } + + ret = qcom_nand_host_init(nandc, host, child); + if (ret) { + devm_kfree(dev, host); + continue; + } + + list_add_tail(&host->node, &nandc->host_list); + } + + if (list_empty(&nandc->host_list)) + return -ENODEV; + + list_for_each_entry_safe(host, tmp, &nandc->host_list, node) { + ret = qcom_nand_mtd_register(nandc, host, child); + if (ret) { + list_del(&host->node); + devm_kfree(dev, host); + } + } + + if (list_empty(&nandc->host_list)) + return -ENODEV; + + return 0; } /* parse custom DT properties here */ @@ -2092,10 +2145,8 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) static int qcom_nandc_probe(struct platform_device *pdev) { struct qcom_nand_controller *nandc; - struct qcom_nand_host *host; const void *dev_data; struct device *dev = &pdev->dev; - struct device_node *dn = dev->of_node, *child; struct resource *res; int ret; @@ -2149,33 +2200,12 @@ static int qcom_nandc_probe(struct platform_device *pdev) if (ret) goto err_setup; - for_each_available_child_of_node(dn, child) { - host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - of_node_put(child); - ret = -ENOMEM; - goto err_cs_init; - } - - ret = qcom_nand_host_init(nandc, host, child); - if (ret) { - devm_kfree(dev, host); - continue; - } - - list_add_tail(&host->node, &nandc->host_list); - } - - if (list_empty(&nandc->host_list)) { - ret = -ENODEV; - goto err_cs_init; - } + ret = qcom_probe_nand_devices(nandc); + if (ret) + goto err_setup; return 0; -err_cs_init: - list_for_each_entry(host, &nandc->host_list, node) - nand_release(nand_to_mtd(&host->chip)); err_setup: clk_disable_unprepare(nandc->aon_clk); err_aon_clk: -- cgit v1.2.3-59-g8ed1b From 1498fbaf700ff100486e864776743a9e14e5169c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 19 Jul 2017 17:31:25 +0200 Subject: mtd: nand: pxa3xx_nand: enable building on mvebu 64-bit platforms The controller supported by the pxa3xx_nand driver is also available on the mvebu 64-bit SoCs, such as the Armada 7K and Armada 8K SoCs. This patch updates the Kconfig dependency to allow building the kernel for this SoC family too. Signed-off-by: Gregory CLEMENT Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dbfa72d61d5a..3f2036f31da4 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -315,7 +315,7 @@ config MTD_NAND_ATMEL config MTD_NAND_PXA3xx tristate "NAND support on PXA3xx and Armada 370/XP" - depends on PXA3xx || ARCH_MMP || PLAT_ORION + depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU help This enables the driver for the NAND flash device found on PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). -- cgit v1.2.3-59-g8ed1b From 55bafbc277dcce7aab0ba28563075f3b517e6134 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 21 Jul 2017 22:38:06 +0200 Subject: mtd: orion-nand: fix build error with ARMv4 orion_nand_read_buf uses an inline assembly with the "ldrd" instruction, which is only available from ARMv5 upwards. This used to be fine, since all users have an ARMv5 or ARMv7 CPU, but now we can also build a multiplatform kernel with ARMv4 support enabled in addition to the "kirkwood" (mvebu) platform. This provides an alternative to call the readsl() function that is supposed to have the same effect and is also optimized for performance. I first posted a version of this patch back in 2014, and there was some discussion about it then. This fixes the bugs identified back then and should be a reasonable alternative for the rare corner case. Link: https://patchwork.kernel.org/patch/4144791/ Cc: Jingoo Han Signed-off-by: Arnd Bergmann Signed-off-by: Boris Brezillon --- drivers/mtd/nand/orion_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 209170ed2b76..41cb7acfc044 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -54,13 +54,16 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct nand_chip *chip = mtd_to_nand(mtd); void __iomem *io_base = chip->IO_ADDR_R; +#if __LINUX_ARM_ARCH__ >= 5 uint64_t *buf64; +#endif int i = 0; while (len && (unsigned long)buf & 7) { *buf++ = readb(io_base); len--; } +#if __LINUX_ARM_ARCH__ >= 5 buf64 = (uint64_t *)buf; while (i < len/8) { /* @@ -74,6 +77,10 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) buf64[i++] = x; } i *= 8; +#else + readsl(io_base, buf, len/4); + i = len / 4 * 4; +#endif while (i < len) buf[i++] = readb(io_base); } -- cgit v1.2.3-59-g8ed1b From c044179ea14db0855edc3d8f82bd998202167368 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:05:09 +0530 Subject: mtd: nand: denali: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali_dt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 47f398edf18f..56e2e177644d 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -118,7 +118,9 @@ static int denali_dt_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no clk available\n"); return PTR_ERR(dt->clk); } - clk_prepare_enable(dt->clk); + ret = clk_prepare_enable(dt->clk); + if (ret) + return ret; denali->clk_x_rate = clk_get_rate(dt->clk); -- cgit v1.2.3-59-g8ed1b From 24c9cd8f8d26194aa1a4077c62df90d657766235 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:07:27 +0530 Subject: mtd: oxnas_nand: Handle clk_prepare_enable/clk_disable_unprepare. - clk_prepare_enable() can fail here and we must check its return value. - oxnas_nand_probe() can fail here and we must disable clock. Signed-off-by: Arvind Yadav Acked-by: Neil Armstrong Signed-off-by: Boris Brezillon --- drivers/mtd/nand/oxnas_nand.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c index 1b207aac840c..7061bb2923b4 100644 --- a/drivers/mtd/nand/oxnas_nand.c +++ b/drivers/mtd/nand/oxnas_nand.c @@ -112,14 +112,19 @@ static int oxnas_nand_probe(struct platform_device *pdev) if (count > 1) return -EINVAL; - clk_prepare_enable(oxnas->clk); + err = clk_prepare_enable(oxnas->clk); + if (err) + return err; + device_reset_optional(&pdev->dev); for_each_child_of_node(np, nand_np) { chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; + if (!chip) { + err = -ENOMEM; + goto err_clk_unprepare; + } chip->controller = &oxnas->base; @@ -139,12 +144,12 @@ static int oxnas_nand_probe(struct platform_device *pdev) /* Scan to find existence of the device */ err = nand_scan(mtd, 1); if (err) - return err; + goto err_clk_unprepare; err = mtd_device_register(mtd, NULL, 0); if (err) { nand_release(mtd); - return err; + goto err_clk_unprepare; } oxnas->chips[nchips] = chip; @@ -152,12 +157,18 @@ static int oxnas_nand_probe(struct platform_device *pdev) } /* Exit if no chips found */ - if (!nchips) - return -ENODEV; + if (!nchips) { + err = -ENODEV; + goto err_clk_unprepare; + } platform_set_drvdata(pdev, oxnas); return 0; + +err_clk_unprepare: + clk_disable_unprepare(oxnas->clk); + return err; } static int oxnas_nand_remove(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 7c94128127ba6ecbaa1e2085088c7337a99aaf51 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:08:06 +0530 Subject: mtd: nand: lpc32xx_slc: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/lpc32xx_slc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index a0669a33f8fe..80c282914586 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -840,7 +840,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_prepare_enable(host->clk); + res = clk_prepare_enable(host->clk); + if (res) + goto err_exit1; /* Set NAND IO addresses and command/ready functions */ chip->IO_ADDR_R = SLC_DATA(host->io_base); @@ -972,9 +974,12 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + int ret; /* Re-enable NAND clock */ - clk_prepare_enable(host->clk); + ret = clk_prepare_enable(host->clk); + if (ret) + return ret; /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); -- cgit v1.2.3-59-g8ed1b From 4d26f012ab591d7671237a6b5e990cbbfd50b0b8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:10:11 +0530 Subject: mtd: nand: lpc32xx_mlc: Handle return value of clk_prepare_enable. clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/nand/lpc32xx_mlc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 846a66c1b133..91ee369681f0 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -705,7 +705,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) res = -ENOENT; goto err_exit1; } - clk_prepare_enable(host->clk); + res = clk_prepare_enable(host->clk); + if (res) + goto err_exit1; nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl; nand_chip->dev_ready = lpc32xx_nand_device_ready; @@ -846,9 +848,12 @@ static int lpc32xx_nand_remove(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev) { struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); + int ret; /* Re-enable NAND clock */ - clk_prepare_enable(host->clk); + ret = clk_prepare_enable(host->clk); + if (ret) + return ret; /* Fresh init of NAND controller */ lpc32xx_nand_setup(host); -- cgit v1.2.3-59-g8ed1b From 481815a6193bb7a1e43f8babecde5155e65f3858 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 1 Aug 2017 17:10:58 +0530 Subject: mtd: st_spi_fsm: Handle clk_prepare_enable/clk_disable_unprepare. - clk_prepare_enable() can fail here and we must check its return value. - stfsm_probe() can fail here and we must disable clock. Signed-off-by: Arvind Yadav Signed-off-by: Boris Brezillon --- drivers/mtd/devices/st_spi_fsm.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 21afd94cd904..7bc29d725200 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -2073,15 +2073,17 @@ static int stfsm_probe(struct platform_device *pdev) ret = stfsm_init(fsm); if (ret) { dev_err(&pdev->dev, "Failed to initialise FSM Controller\n"); - return ret; + goto err_clk_unprepare; } stfsm_fetch_platform_configs(pdev); /* Detect SPI FLASH device */ info = stfsm_jedec_probe(fsm); - if (!info) - return -ENODEV; + if (!info) { + ret = -ENODEV; + goto err_clk_unprepare; + } fsm->info = info; /* Use device size to determine address width */ @@ -2095,11 +2097,11 @@ static int stfsm_probe(struct platform_device *pdev) if (info->config) { ret = info->config(fsm); if (ret) - return ret; + goto err_clk_unprepare; } else { ret = stfsm_prepare_rwe_seqs_default(fsm); if (ret) - return ret; + goto err_clk_unprepare; } fsm->mtd.name = info->name; @@ -2124,6 +2126,10 @@ static int stfsm_probe(struct platform_device *pdev) fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10)); return mtd_device_register(&fsm->mtd, NULL, 0); + +err_clk_unprepare: + clk_disable_unprepare(fsm->clk); + return ret; } static int stfsm_remove(struct platform_device *pdev) @@ -2147,9 +2153,7 @@ static int stfsmfsm_resume(struct device *dev) { struct stfsm *fsm = dev_get_drvdata(dev); - clk_prepare_enable(fsm->clk); - - return 0; + return clk_prepare_enable(fsm->clk); } #endif -- cgit v1.2.3-59-g8ed1b From fcf59f1ff525bc6400a893e2a0820afcf815f4c3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:25:46 +0200 Subject: mtd: nand: sunxi: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Boris Brezillon Cc: Richard Weinberger Cc: David Woodhouse Cc: Brian Norris Cc: Marek Vasut Cc: Cyrille Pitchen Cc: Maxime Ripard Cc: Chen-Yu Tsai Cc: linux-mtd@lists.infradead.org Signed-off-by: Philipp Zabel Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sunxi_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index d0b6f8f9f297..6eb97451f485 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -2208,7 +2208,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev) if (ret) goto out_ahb_clk_unprepare; - nfc->reset = devm_reset_control_get_optional(dev, "ahb"); + nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb"); if (IS_ERR(nfc->reset)) { ret = PTR_ERR(nfc->reset); goto out_mod_clk_unprepare; -- cgit v1.2.3-59-g8ed1b From 3bff08dffe3115a25ce04b95ea75f6d868572c60 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 25 Nov 2016 11:32:32 +0100 Subject: mtd: nand: mxc: Fix mxc_v1 ooblayout Commit a894cf6c5a82 ("mtd: nand: mxc: switch to mtd_ooblayout_ops") introduced a bug in the OOB layout description. Even if the driver claims that 3 ECC bytes are reserved to protect 512 bytes of data, it's actually 5 ECC bytes to protect 512+6 bytes of data (some OOB bytes are also protected using extra ECC bytes). Fix the mxc_v1_ooblayout_{free,ecc}() functions to reflect this behavior. Signed-off-by: Boris Brezillon Fixes: a894cf6c5a82 ("mtd: nand: mxc: switch to mtd_ooblayout_ops") Cc: Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a764d5ca7536..5bedf7bc3d88 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -876,6 +876,8 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) } } +#define MXC_V1_ECCBYTES 5 + static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { @@ -885,7 +887,7 @@ static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section, return -ERANGE; oobregion->offset = (section * 16) + 6; - oobregion->length = nand_chip->ecc.bytes; + oobregion->length = MXC_V1_ECCBYTES; return 0; } @@ -907,8 +909,7 @@ static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section, oobregion->length = 4; } } else { - oobregion->offset = ((section - 1) * 16) + - nand_chip->ecc.bytes + 6; + oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6; if (section < nand_chip->ecc.steps) oobregion->length = (section * 16) + 6 - oobregion->offset; -- cgit v1.2.3-59-g8ed1b From fd213b5bae800dc00a2930dcd07f63ab9bbff3f9 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 5 Aug 2017 14:16:24 +0200 Subject: mtd: nand: hynix: add support for 20nm NAND chips According to the datasheet of the H27UCG8T2BTR the NAND Technology field (6th byte of the "Device Identifier Description", bits 0-2) the following values are possible: - 0x0 = 48nm - 0x1 = 41nm - 0x2 = 32nm - 0x3 = 26nm - 0x4 = 20nm - (all others are reserved) Fix this by extending the mask for this field to allow detecting value 0x4 (20nm) as valid NAND technology. Without this the detection of the ECC requirements fails, because the code assumes that the device is a 48nm device (0x4 & 0x3 = 0x0) and aborts with "Invalid ECC requirements" because it cannot map the "ECC Level". Extending the mask makes the ECC requirement detection code recognize this chip as <= 26nm and sets up the ECC step size and ECC strength correctly. Signed-off-by: Martin Blumenstingl Fixes: 78f3482d7480 ("mtd: nand: hynix: Rework NAND ID decoding to extract more information") Cc: Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_hynix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c index b12dc7325378..bd9a6e343848 100644 --- a/drivers/mtd/nand/nand_hynix.c +++ b/drivers/mtd/nand/nand_hynix.c @@ -477,7 +477,7 @@ static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip, * The ECC requirements field meaning depends on the * NAND technology. */ - u8 nand_tech = chip->id.data[5] & 0x3; + u8 nand_tech = chip->id.data[5] & 0x7; if (nand_tech < 3) { /* > 26nm, reference: H27UBG8T2A datasheet */ @@ -533,7 +533,7 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip, if (nand_tech > 0) chip->options |= NAND_NEED_SCRAMBLING; } else { - nand_tech = chip->id.data[5] & 0x3; + nand_tech = chip->id.data[5] & 0x7; /* < 32nm */ if (nand_tech > 2) -- cgit v1.2.3-59-g8ed1b From 892dd1831392adbdf4e55d0c284c3aea6ba4d855 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 6 Aug 2017 00:14:28 +0300 Subject: mtd: nand: atmel: fix of_irq_get() error check of_irq_get() may return 0 as well as negative error number on failure, while the driver only checks for the negative values. The driver would then call devm_request_irq() for IRQ0 in its probe method and never get a valid interrupt. Check for 'nc->irq <= 0' instead and return -ENXIO from the driver's probe if of_irq_get() returned 0. Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Signed-off-by: Sergei Shtylyov Acked-by: Wenyou Yang Signed-off-by: Boris Brezillon --- drivers/mtd/nand/atmel/nand-controller.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index d922a88e407f..6b9d0ba3d707 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -2078,8 +2078,8 @@ atmel_hsmc_nand_controller_legacy_init(struct atmel_hsmc_nand_controller *nc) } nc->irq = of_irq_get(nand_np, 0); - if (nc->irq < 0) { - ret = nc->irq; + if (nc->irq <= 0) { + ret = nc->irq ?: -ENXIO; if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IRQ number (err = %d)\n", ret); @@ -2168,11 +2168,12 @@ atmel_hsmc_nand_controller_init(struct atmel_hsmc_nand_controller *nc) nc->irq = of_irq_get(np, 0); of_node_put(np); - if (nc->irq < 0) { - if (nc->irq != -EPROBE_DEFER) + if (nc->irq <= 0) { + ret = nc->irq ?: -ENXIO; + if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IRQ number (err = %d)\n", - nc->irq); - return nc->irq; + ret); + return ret; } np = of_parse_phandle(dev->of_node, "atmel,nfc-io", 0); -- cgit v1.2.3-59-g8ed1b From dbf5f6424ed92131b2d5bf363a0176d8a9f531ef Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Tue, 8 Aug 2017 22:35:42 +0800 Subject: mtd: nand: sh_flctl: use dma_mapping_error to check map errors The return value of dma_map_single() should be checked by dma_mapping_error(). However, in function flctl_dma_fifo0_transfer(), its return value is checked against NULL, which could result in failures. Signed-off-by: Pan Bian Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sh_flctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 891ac7b99305..2404d6634bda 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -411,7 +411,7 @@ static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf, dma_addr = dma_map_single(chan->device->dev, buf, len, dir); - if (dma_addr) + if (!dma_mapping_error(chan->device->dev, dma_addr)) desc = dmaengine_prep_slave_single(chan, dma_addr, len, tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -- cgit v1.2.3-59-g8ed1b From 2192a8ddc11ad7f243bed44eef4add8e37a658fe Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 11:29:21 -0500 Subject: mtd: nand: sh_flctl: fix error return code in flctl_probe() platform_get_irq() returns an error code, but the sh_flctl driver ignores it and always returns -ENXIO. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sh_flctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 2404d6634bda..d2afd57bc1f2 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -1141,8 +1141,8 @@ static int flctl_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get flste irq data\n"); - return -ENXIO; + dev_err(&pdev->dev, "failed to get flste irq data: %d\n", irq); + return irq; } ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED, -- cgit v1.2.3-59-g8ed1b From 238709b22097a16839078530e0a10812dde86f16 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 9 Aug 2017 11:35:21 -0500 Subject: mtd: nand: mtk: fix error return code in mtk_ecc_probe() platform_get_irq() returns an error code, but the mtk_ecc driver ignores it and always returns -EINVAL. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mtk_ecc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c index 6c3a4aab0b48..7f3b065b6b8f 100644 --- a/drivers/mtd/nand/mtk_ecc.c +++ b/drivers/mtd/nand/mtk_ecc.c @@ -464,8 +464,8 @@ static int mtk_ecc_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "failed to get irq\n"); - return -EINVAL; + dev_err(dev, "failed to get irq: %d\n", irq); + return irq; } ret = dma_set_mask(dev, DMA_BIT_MASK(32)); -- cgit v1.2.3-59-g8ed1b From d8a9b320a26c1ea28e51e4f3ecfb593d5aac2910 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:16 +0530 Subject: mtd: nand: qcom: fix read failure without complete bootchain The NAND page read fails without complete boot chain since NAND_DEV_CMD_VLD value is not proper. The default power on reset value for this register is 0xe - ERASE_START_VALID | WRITE_START_VALID | READ_STOP_VALID The READ_START_VALID should be enabled for sending PAGE_READ command. READ_STOP_VALID should be cleared since normal NAND page read does not require READ_STOP command. Fixes: c76b78d8ec05a ("mtd: nand: Qualcomm NAND controller driver") Cc: stable@vger.kernel.org Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 0e727d79f2ce..e5cb8f12d5bb 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -109,7 +109,11 @@ #define READ_ADDR 0 /* NAND_DEV_CMD_VLD bits */ -#define READ_START_VLD 0 +#define READ_START_VLD BIT(0) +#define READ_STOP_VLD BIT(1) +#define WRITE_START_VLD BIT(2) +#define ERASE_START_VLD BIT(3) +#define SEQ_READ_START_VLD BIT(4) /* NAND_EBI2_ECC_BUF_CFG bits */ #define NUM_STEPS 0 @@ -148,6 +152,10 @@ #define FETCH_ID 0xb #define RESET_DEVICE 0xd +/* Default Value for NAND_DEV_CMD_VLD */ +#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ + ERASE_START_VLD | SEQ_READ_START_VLD) + /* * the NAND controller performs reads/writes with ECC in 516 byte chunks. * the driver calls the chunks 'step' or 'codeword' interchangeably @@ -695,8 +703,7 @@ static int nandc_param(struct qcom_nand_host *host) /* configure CMD1 and VLD for ONFI param probing */ nandc_set_reg(nandc, NAND_DEV_CMD_VLD, - (nandc->vld & ~(1 << READ_START_VLD)) - | 0 << READ_START_VLD); + (nandc->vld & ~READ_START_VLD)); nandc_set_reg(nandc, NAND_DEV_CMD1, (nandc->cmd1 & ~(0xFF << READ_ADDR)) | NAND_CMD_PARAM << READ_ADDR); @@ -1995,13 +2002,14 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) { /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); + nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); /* enable ADM DMA */ nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); /* save the original values of these registers */ nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); - nandc->vld = nandc_read(nandc, NAND_DEV_CMD_VLD); + nandc->vld = NAND_DEV_CMD_VLD_VAL; return 0; } -- cgit v1.2.3-59-g8ed1b From 58f1f22ac34c39958344cd1ae8a89e1030dcdbbd Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:17 +0530 Subject: mtd: nand: qcom: support for NAND controller properties Currently driver data is being assigned directly with ECC modes. Now, the plan is to add more NAND controller versions which will have different properties. This patch reorganizes the current driver data assignment by creating NAND controller properties structure which will contain all properties specific to NAND controller. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index e5cb8f12d5bb..79f7de82a708 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -240,7 +240,7 @@ struct nandc_regs { * writes. contains the register values to be * written to controller * @cmd1/vld: some fixed controller register values - * @ecc_modes: supported ECC modes by the current controller, + * @props: properties of current NAND controller, * initialized via DT match data */ struct qcom_nand_controller { @@ -271,7 +271,7 @@ struct qcom_nand_controller { struct nandc_regs *regs; u32 cmd1, vld; - u32 ecc_modes; + const struct qcom_nandc_props *props; }; /* @@ -324,6 +324,15 @@ struct qcom_nand_host { u32 clrreadstatus; }; +/* + * This data type corresponds to the NAND controller properties which varies + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND + */ +struct qcom_nandc_props { + u32 ecc_modes; +}; + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -1824,7 +1833,7 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) * uses lesser bytes for ECC. If RS is used, the ECC bytes is * always 10 bytes */ - if (nandc->ecc_modes & ECC_BCH_4BIT) { + if (nandc->props->ecc_modes & ECC_BCH_4BIT) { /* BCH */ host->bch_enabled = true; ecc_mode = 0; @@ -2171,7 +2180,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) return -ENODEV; } - nandc->ecc_modes = (unsigned long)dev_data; + nandc->props = dev_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nandc->base = devm_ioremap_resource(dev, res); @@ -2240,15 +2249,18 @@ static int qcom_nandc_remove(struct platform_device *pdev) return 0; } -#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT) +static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), +}; /* * data will hold a struct pointer containing more differences once we support * more controller variants */ static const struct of_device_id qcom_nandc_of_match[] = { - { .compatible = "qcom,ipq806x-nand", - .data = (void *)EBI2_NANDC_ECC_MODES, + { + .compatible = "qcom,ipq806x-nand", + .data = &ipq806x_nandc_props, }, {} }; -- cgit v1.2.3-59-g8ed1b From 8c5d5d6a0bc62bebed37f306b80ab125fa3fbb8d Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:18 +0530 Subject: mtd: nand: qcom: add bam property for QPIC NAND controller The current driver only supports EBI2 NAND controller which uses ADM DMA. The latest QCOM SoC uses QPIC NAND controller with BAM DMA. NAND registers and programming sequence are same for EBI2 and QPIC NAND so the same driver can support QPIC NAND also by adding the BAM DMA support. This patch adds the is_bam in NAND property which will be checked for determining the DMA engine type. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 79f7de82a708..2d44eeba553c 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -328,9 +328,11 @@ struct qcom_nand_host { * This data type corresponds to the NAND controller properties which varies * among different NAND controllers. * @ecc_modes - ecc mode for NAND + * @is_bam - whether NAND controller is using BAM */ struct qcom_nandc_props { u32 ecc_modes; + bool is_bam; }; static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) @@ -2251,6 +2253,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), + .is_bam = false, }; /* -- cgit v1.2.3-59-g8ed1b From 497d7d852a48a28b5f98f1a994195d3c16f591fc Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Fri, 11 Aug 2017 17:09:19 +0530 Subject: mtd: nand: qcom: add and initialize QPIC DMA resources 1. QPIC NAND controller uses 3 BAM channels: command, data tx and data rx while EBI2 NAND controller uses only single ADM channel. 2. CRCI is only required for ADM DMA and it's not required for BAM DMA. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 86 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 2d44eeba553c..59b764a347d3 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -255,9 +255,22 @@ struct qcom_nand_controller { struct clk *core_clk; struct clk *aon_clk; - struct dma_chan *chan; - unsigned int cmd_crci; - unsigned int data_crci; + union { + /* will be used only by QPIC for BAM DMA */ + struct { + struct dma_chan *tx_chan; + struct dma_chan *rx_chan; + struct dma_chan *cmd_chan; + }; + + /* will be used only by EBI2 for ADM DMA */ + struct { + struct dma_chan *chan; + unsigned int cmd_crci; + unsigned int data_crci; + }; + }; + struct list_head desc_list; u8 *data_buffer; @@ -1989,10 +2002,31 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) if (!nandc->reg_read_buf) return -ENOMEM; - nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); - if (!nandc->chan) { - dev_err(nandc->dev, "failed to request slave channel\n"); - return -ENODEV; + if (nandc->props->is_bam) { + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx"); + if (!nandc->tx_chan) { + dev_err(nandc->dev, "failed to request tx channel\n"); + return -ENODEV; + } + + nandc->rx_chan = dma_request_slave_channel(nandc->dev, "rx"); + if (!nandc->rx_chan) { + dev_err(nandc->dev, "failed to request rx channel\n"); + return -ENODEV; + } + + nandc->cmd_chan = dma_request_slave_channel(nandc->dev, "cmd"); + if (!nandc->cmd_chan) { + dev_err(nandc->dev, "failed to request cmd channel\n"); + return -ENODEV; + } + } else { + nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); + if (!nandc->chan) { + dev_err(nandc->dev, + "failed to request slave channel\n"); + return -ENODEV; + } } INIT_LIST_HEAD(&nandc->desc_list); @@ -2005,7 +2039,19 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) { - dma_release_channel(nandc->chan); + if (nandc->props->is_bam) { + if (nandc->tx_chan) + dma_release_channel(nandc->tx_chan); + + if (nandc->rx_chan) + dma_release_channel(nandc->rx_chan); + + if (nandc->cmd_chan) + dma_release_channel(nandc->cmd_chan); + } else { + if (nandc->chan) + dma_release_channel(nandc->chan); + } } /* one time setup of a few nand controller registers */ @@ -2146,16 +2192,20 @@ static int qcom_nandc_parse_dt(struct platform_device *pdev) struct device_node *np = nandc->dev->of_node; int ret; - ret = of_property_read_u32(np, "qcom,cmd-crci", &nandc->cmd_crci); - if (ret) { - dev_err(nandc->dev, "command CRCI unspecified\n"); - return ret; - } + if (!nandc->props->is_bam) { + ret = of_property_read_u32(np, "qcom,cmd-crci", + &nandc->cmd_crci); + if (ret) { + dev_err(nandc->dev, "command CRCI unspecified\n"); + return ret; + } - ret = of_property_read_u32(np, "qcom,data-crci", &nandc->data_crci); - if (ret) { - dev_err(nandc->dev, "data CRCI unspecified\n"); - return ret; + ret = of_property_read_u32(np, "qcom,data-crci", + &nandc->data_crci); + if (ret) { + dev_err(nandc->dev, "data CRCI unspecified\n"); + return ret; + } } return 0; @@ -2205,7 +2255,7 @@ static int qcom_nandc_probe(struct platform_device *pdev) ret = qcom_nandc_alloc(nandc); if (ret) - return ret; + goto err_core_clk; ret = clk_prepare_enable(nandc->core_clk); if (ret) -- cgit v1.2.3-59-g8ed1b From 6192ff7a44c1806f4db110f09168fb4e84d2770b Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:39 +0530 Subject: mtd: nand: qcom: DMA mapping support for register read buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EBI2 NAND controller directly remaps register read buffer with dma_map_sg and DMA address of this buffer will be passed to DMA API’s. While, on QPIC NAND controller, which uses BAM DMA, we read the controller registers by preparing a BAM command descriptor. This command descriptor requires the - controller register address - the DMA address in which we want to store the value read back from the controller register. This command descriptor will be remapped with dma_map_sg and its DMA address will be passed to DMA API’s. Therefore, it's required that we also map our register read buffer for DMA (using dma_map_single). We use the returned DMA address for preparing entries in our command descriptor. This patch adds the DMA mapping support for register read buffer. This buffer will be DMA mapped during allocation time. Before starting of any operation, this buffer will be synced for device operation and after operation completion, it will be synced again for CPU. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 59b764a347d3..590fc1dd556e 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -234,6 +234,7 @@ struct nandc_regs { * by upper layers directly * @buf_size/count/start: markers for chip->read_buf/write_buf functions * @reg_read_buf: local buffer for reading back registers via DMA + * @reg_read_dma: contains dma address for register read buffer * @reg_read_pos: marker for data read in reg_read_buf * * @regs: a contiguous chunk of memory for DMA register @@ -279,6 +280,7 @@ struct qcom_nand_controller { int buf_start; __le32 *reg_read_buf; + dma_addr_t reg_read_dma; int reg_read_pos; struct nandc_regs *regs; @@ -371,6 +373,24 @@ static inline void nandc_write(struct qcom_nand_controller *nandc, int offset, iowrite32(val, nandc->base + offset); } +static inline void nandc_read_buffer_sync(struct qcom_nand_controller *nandc, + bool is_cpu) +{ + if (!nandc->props->is_bam) + return; + + if (is_cpu) + dma_sync_single_for_cpu(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + else + dma_sync_single_for_device(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); +} + static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) { switch (offset) { @@ -854,6 +874,7 @@ static void free_descs(struct qcom_nand_controller *nandc) static void clear_read_regs(struct qcom_nand_controller *nandc) { nandc->reg_read_pos = 0; + nandc_read_buffer_sync(nandc, false); } static void pre_command(struct qcom_nand_host *host, int command) @@ -883,6 +904,7 @@ static void parse_erase_write_errors(struct qcom_nand_host *host, int command) int i; num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1; + nandc_read_buffer_sync(nandc, true); for (i = 0; i < num_cw; i++) { u32 flash_status = le32_to_cpu(nandc->reg_read_buf[i]); @@ -904,6 +926,7 @@ static void post_command(struct qcom_nand_host *host, int command) switch (command) { case NAND_CMD_READID: + nandc_read_buffer_sync(nandc, true); memcpy(nandc->data_buffer, nandc->reg_read_buf, nandc->buf_count); break; @@ -1067,6 +1090,7 @@ static int parse_read_errors(struct qcom_nand_host *host, u8 *data_buf, int i; buf = (struct read_stats *)nandc->reg_read_buf; + nandc_read_buffer_sync(nandc, true); for (i = 0; i < ecc->steps; i++, buf++) { u32 flash, buffer, erased_cw; @@ -2003,6 +2027,16 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) return -ENOMEM; if (nandc->props->is_bam) { + nandc->reg_read_dma = + dma_map_single(nandc->dev, nandc->reg_read_buf, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + if (dma_mapping_error(nandc->dev, nandc->reg_read_dma)) { + dev_err(nandc->dev, "failed to DMA MAP reg buffer\n"); + return -EIO; + } + nandc->tx_chan = dma_request_slave_channel(nandc->dev, "tx"); if (!nandc->tx_chan) { dev_err(nandc->dev, "failed to request tx channel\n"); @@ -2040,6 +2074,12 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) { if (nandc->props->is_bam) { + if (!dma_mapping_error(nandc->dev, nandc->reg_read_dma)) + dma_unmap_single(nandc->dev, nandc->reg_read_dma, + MAX_REG_RD * + sizeof(*nandc->reg_read_buf), + DMA_FROM_DEVICE); + if (nandc->tx_chan) dma_release_channel(nandc->tx_chan); -- cgit v1.2.3-59-g8ed1b From cb80f1140db6ad2cb6841ad656cc6b779b4b58be Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:40 +0530 Subject: mtd: nand: qcom: allocate BAM transaction - The BAM transaction is the core data structure which will be used for all the data transfers in QPIC NAND. Since the core framework in nand_base.c is serializing all the NAND requests so allocating BAM transaction before every transfer will be overhead. The memory for it be allocated during probe time and before every transfer, it will be cleared. - The BAM transaction contains the array of command and data scatter gather list and indexes. For every transfer, all the resource will be taken from BAM transaction. - The size of the buffer used for BAM transactions is calculated based on the NAND device with the maximum page size, among all the devices connected to the controller. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 590fc1dd556e..4f8306e84537 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -177,6 +177,32 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) +#define QPIC_PER_CW_CMD_SGL 32 +#define QPIC_PER_CW_DATA_SGL 8 + +/* + * This data type corresponds to the BAM transaction which will be used for all + * NAND transfers. + * @cmd_sgl - sgl for NAND BAM command pipe + * @data_sgl - sgl for NAND BAM consumer/producer pipe + * @cmd_sgl_pos - current index in command sgl. + * @cmd_sgl_start - start index in command sgl. + * @tx_sgl_pos - current index in data sgl for tx. + * @tx_sgl_start - start index in data sgl for tx. + * @rx_sgl_pos - current index in data sgl for rx. + * @rx_sgl_start - start index in data sgl for rx. + */ +struct bam_transaction { + struct scatterlist *cmd_sgl; + struct scatterlist *data_sgl; + u32 cmd_sgl_pos; + u32 cmd_sgl_start; + u32 tx_sgl_pos; + u32 tx_sgl_start; + u32 rx_sgl_pos; + u32 rx_sgl_start; +}; + struct desc_info { struct list_head node; @@ -243,6 +269,8 @@ struct nandc_regs { * @cmd1/vld: some fixed controller register values * @props: properties of current NAND controller, * initialized via DT match data + * @max_cwperpage: maximum QPIC codewords required. calculated + * from all connected NAND devices pagesize */ struct qcom_nand_controller { struct nand_hw_control controller; @@ -273,11 +301,13 @@ struct qcom_nand_controller { }; struct list_head desc_list; + struct bam_transaction *bam_txn; u8 *data_buffer; int buf_size; int buf_count; int buf_start; + unsigned int max_cwperpage; __le32 *reg_read_buf; dma_addr_t reg_read_dma; @@ -350,6 +380,44 @@ struct qcom_nandc_props { bool is_bam; }; +/* Frees the BAM transaction memory */ +static void free_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + devm_kfree(nandc->dev, bam_txn); +} + +/* Allocates and Initializes the BAM transaction */ +static struct bam_transaction * +alloc_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn; + size_t bam_txn_size; + unsigned int num_cw = nandc->max_cwperpage; + void *bam_txn_buf; + + bam_txn_size = + sizeof(*bam_txn) + num_cw * + ((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + + (sizeof(*bam_txn->data_sgl) * QPIC_PER_CW_DATA_SGL)); + + bam_txn_buf = devm_kzalloc(nandc->dev, bam_txn_size, GFP_KERNEL); + if (!bam_txn_buf) + return NULL; + + bam_txn = bam_txn_buf; + bam_txn_buf += sizeof(*bam_txn); + + bam_txn->cmd_sgl = bam_txn_buf; + bam_txn_buf += + sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; + + bam_txn->data_sgl = bam_txn_buf; + + return bam_txn; +} + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -1920,6 +1988,8 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) mtd_set_ooblayout(mtd, &qcom_nand_ooblayout_ops); cwperpage = mtd->writesize / ecc->size; + nandc->max_cwperpage = max_t(unsigned int, nandc->max_cwperpage, + cwperpage); /* * DATA_UD_BYTES varies based on whether the read/write command protects @@ -2054,6 +2124,20 @@ static int qcom_nandc_alloc(struct qcom_nand_controller *nandc) dev_err(nandc->dev, "failed to request cmd channel\n"); return -ENODEV; } + + /* + * Initially allocate BAM transaction to read ONFI param page. + * After detecting all the devices, this BAM transaction will + * be freed and the next BAM tranasction will be allocated with + * maximum codeword size + */ + nandc->max_cwperpage = 1; + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + return -ENOMEM; + } } else { nandc->chan = dma_request_slave_channel(nandc->dev, "rxtx"); if (!nandc->chan) { @@ -2211,6 +2295,16 @@ static int qcom_probe_nand_devices(struct qcom_nand_controller *nandc) if (list_empty(&nandc->host_list)) return -ENODEV; + if (nandc->props->is_bam) { + free_bam_transaction(nandc); + nandc->bam_txn = alloc_bam_transaction(nandc); + if (!nandc->bam_txn) { + dev_err(nandc->dev, + "failed to allocate bam transaction\n"); + return -ENOMEM; + } + } + list_for_each_entry_safe(host, tmp, &nandc->host_list, node) { ret = qcom_nand_mtd_register(nandc, host, child); if (ret) { -- cgit v1.2.3-59-g8ed1b From 381dd24539a85a4bdec155369e3216e6f267df7d Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:41 +0530 Subject: mtd: nand: qcom: add BAM DMA descriptor handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. prepare_bam_async_desc is the function which will call all the DMA API’s. It will fetch the outstanding scatter gather list for passed channel and will do the DMA descriptor formation. The DMA flag is dependent upon the type of channel. 2. For ADM DMA, the descriptor is being formed for every DMA request so its sgl count will be always 1 while in BAM DMA, the clubbing of descriptor is being done to increase throughput. 3. ADM DMA uses only one channel while in BAM DMA, data descriptors will be submitted to tx channel (for write) or rx channel (for read) and all the registers read/write descriptors in command channel. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 148 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 4f8306e84537..f52a69252358 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -203,11 +203,27 @@ struct bam_transaction { u32 rx_sgl_start; }; +/* + * This data type corresponds to the nand dma descriptor + * @list - list for desc_info + * @dir - DMA transfer direction + * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by + * ADM + * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM + * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM + * @dma_desc - low level DMA engine descriptor + */ struct desc_info { struct list_head node; enum dma_data_direction dir; - struct scatterlist sgl; + union { + struct scatterlist adm_sgl; + struct { + struct scatterlist *bam_sgl; + int sgl_cnt; + }; + }; struct dma_async_tx_descriptor *dma_desc; }; @@ -568,9 +584,78 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) nandc_set_reg(nandc, NAND_EXEC_CMD, 1); } -static int prep_dma_desc(struct qcom_nand_controller *nandc, bool read, - int reg_off, const void *vaddr, int size, - bool flow_control) +/* + * Maps the scatter gather list for DMA transfer and forms the DMA descriptor + * for BAM. This descriptor will be added in the NAND DMA descriptor queue + * which will be submitted to DMA engine. + */ +static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, + struct dma_chan *chan, + unsigned long flags) +{ + struct desc_info *desc; + struct scatterlist *sgl; + unsigned int sgl_cnt; + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + enum dma_transfer_direction dir_eng; + struct dma_async_tx_descriptor *dma_desc; + + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + + if (chan == nandc->cmd_chan) { + sgl = &bam_txn->cmd_sgl[bam_txn->cmd_sgl_start]; + sgl_cnt = bam_txn->cmd_sgl_pos - bam_txn->cmd_sgl_start; + bam_txn->cmd_sgl_start = bam_txn->cmd_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else if (chan == nandc->tx_chan) { + sgl = &bam_txn->data_sgl[bam_txn->tx_sgl_start]; + sgl_cnt = bam_txn->tx_sgl_pos - bam_txn->tx_sgl_start; + bam_txn->tx_sgl_start = bam_txn->tx_sgl_pos; + dir_eng = DMA_MEM_TO_DEV; + desc->dir = DMA_TO_DEVICE; + } else { + sgl = &bam_txn->data_sgl[bam_txn->rx_sgl_start]; + sgl_cnt = bam_txn->rx_sgl_pos - bam_txn->rx_sgl_start; + bam_txn->rx_sgl_start = bam_txn->rx_sgl_pos; + dir_eng = DMA_DEV_TO_MEM; + desc->dir = DMA_FROM_DEVICE; + } + + sg_mark_end(sgl + sgl_cnt - 1); + ret = dma_map_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + if (ret == 0) { + dev_err(nandc->dev, "failure in mapping desc\n"); + kfree(desc); + return -ENOMEM; + } + + desc->sgl_cnt = sgl_cnt; + desc->bam_sgl = sgl; + + dma_desc = dmaengine_prep_slave_sg(chan, sgl, sgl_cnt, dir_eng, + flags); + + if (!dma_desc) { + dev_err(nandc->dev, "failure in prep desc\n"); + dma_unmap_sg(nandc->dev, sgl, sgl_cnt, desc->dir); + kfree(desc); + return -EINVAL; + } + + desc->dma_desc = dma_desc; + + list_add_tail(&desc->node, &nandc->desc_list); + + return 0; +} + +static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, + int reg_off, const void *vaddr, int size, + bool flow_control) { struct desc_info *desc; struct dma_async_tx_descriptor *dma_desc; @@ -583,7 +668,7 @@ static int prep_dma_desc(struct qcom_nand_controller *nandc, bool read, if (!desc) return -ENOMEM; - sgl = &desc->sgl; + sgl = &desc->adm_sgl; sg_init_one(sgl, vaddr, size); @@ -659,7 +744,7 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, vaddr = nandc->reg_read_buf + nandc->reg_read_pos; nandc->reg_read_pos += num_regs; - return prep_dma_desc(nandc, true, first, vaddr, size, flow_control); + return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control); } /* @@ -690,7 +775,8 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, size = num_regs * sizeof(u32); - return prep_dma_desc(nandc, false, first, vaddr, size, flow_control); + return prep_adm_dma_desc(nandc, false, first, vaddr, size, + flow_control); } /* @@ -704,7 +790,7 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size) { - return prep_dma_desc(nandc, true, reg_off, vaddr, size, false); + return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } /* @@ -718,7 +804,7 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size) { - return prep_dma_desc(nandc, false, reg_off, vaddr, size, false); + return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } /* @@ -917,12 +1003,43 @@ static int submit_descs(struct qcom_nand_controller *nandc) { struct desc_info *desc; dma_cookie_t cookie = 0; + struct bam_transaction *bam_txn = nandc->bam_txn; + int r; + + if (nandc->props->is_bam) { + if (bam_txn->rx_sgl_pos > bam_txn->rx_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->rx_chan, 0); + if (r) + return r; + } + + if (bam_txn->tx_sgl_pos > bam_txn->tx_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (r) + return r; + } + + if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) { + r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0); + if (r) + return r; + } + } list_for_each_entry(desc, &nandc->desc_list, node) cookie = dmaengine_submit(desc->dma_desc); - if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) - return -ETIMEDOUT; + if (nandc->props->is_bam) { + dma_async_issue_pending(nandc->tx_chan); + dma_async_issue_pending(nandc->rx_chan); + + if (dma_sync_wait(nandc->cmd_chan, cookie) != DMA_COMPLETE) + return -ETIMEDOUT; + } else { + if (dma_sync_wait(nandc->chan, cookie) != DMA_COMPLETE) + return -ETIMEDOUT; + } return 0; } @@ -933,7 +1050,14 @@ static void free_descs(struct qcom_nand_controller *nandc) list_for_each_entry_safe(desc, n, &nandc->desc_list, node) { list_del(&desc->node); - dma_unmap_sg(nandc->dev, &desc->sgl, 1, desc->dir); + + if (nandc->props->is_bam) + dma_unmap_sg(nandc->dev, desc->bam_sgl, + desc->sgl_cnt, desc->dir); + else + dma_unmap_sg(nandc->dev, &desc->adm_sgl, 1, + desc->dir); + kfree(desc); } } -- cgit v1.2.3-59-g8ed1b From 67e830aef3f81affe23e50708f16d35550153836 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:42 +0530 Subject: mtd: nand: qcom: support for passing flags in DMA helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QPIC NAND BAM has multiple flags to control the transfer. This patch adds flags parameter in register and data transfer DMA helper functions and modifies all these functions call with appropriate flags using following rule 1. Read and write can’t go in single command descriptor so separate SGL should be used. 2. For some of the requests, NWD flag should be set in BAM DMA descriptor. 3. For Data write, the BAM has internal buffer for each codeword. All write request will modify the data in internal buffer and this buffer will be flushed to NAND device once EOT flag is set. So for all the write requests in single codeword, the EOT should be cleared for all tx data descriptors except the last one. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 129 +++++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index f52a69252358..c9226172c3a3 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -180,6 +180,17 @@ #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 +/* + * Flags used in DMA descriptor preparation helper functions + * (i.e. read_reg_dma/write_reg_dma/read_data_dma/write_data_dma) + */ +/* Don't set the EOT in current tx BAM sgl */ +#define NAND_BAM_NO_EOT BIT(0) +/* Set the NWD flag in current BAM sgl */ +#define NAND_BAM_NWD BIT(1) +/* Finish writing in the current BAM sgl and start writing in another BAM sgl */ +#define NAND_BAM_NEXT_SGL BIT(2) + /* * This data type corresponds to the BAM transaction which will be used for all * NAND transfers. @@ -729,9 +740,10 @@ err: * * @first: offset of the first register in the contiguous block * @num_regs: number of registers to read + * @flags: flags to control DMA descriptor preparation */ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs) + int num_regs, unsigned int flags) { bool flow_control = false; void *vaddr; @@ -753,9 +765,10 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, * * @first: offset of the first register in the contiguous block * @num_regs: number of registers to write + * @flags: flags to control DMA descriptor preparation */ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, - int num_regs) + int num_regs, unsigned int flags) { bool flow_control = false; struct nandc_regs *regs = nandc->regs; @@ -767,6 +780,9 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_FLASH_CMD) flow_control = true; + if (first == NAND_EXEC_CMD) + flags |= NAND_BAM_NWD; + if (first == NAND_DEV_CMD1_RESTORE) first = NAND_DEV_CMD1; @@ -786,9 +802,10 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, * @reg_off: offset within the controller's data buffer * @vaddr: virtual address of the buffer we want to write to * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation */ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size) + const u8 *vaddr, int size, unsigned int flags) { return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } @@ -800,9 +817,10 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, * @reg_off: offset within the controller's data buffer * @vaddr: virtual address of the buffer we want to read from * @size: DMA transaction size in bytes + * @flags: flags to control DMA descriptor preparation */ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, - const u8 *vaddr, int size) + const u8 *vaddr, int size, unsigned int flags) { return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } @@ -813,9 +831,9 @@ static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, */ static void config_nand_page_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_ADDR0, 2); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3); - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); + write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); } /* @@ -824,11 +842,12 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_cw_read(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 2); - read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 2, 0); + read_reg_dma(nandc, NAND_ERASED_CW_DETECT_STATUS, 1, + NAND_BAM_NEXT_SGL); } /* @@ -847,9 +866,10 @@ static void config_nand_single_cw_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_page_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_ADDR0, 2); - write_reg_dma(nandc, NAND_DEV0_CFG0, 3); - write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1); + write_reg_dma(nandc, NAND_ADDR0, 2, 0); + write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); + write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, + NAND_BAM_NEXT_SGL); } /* @@ -858,13 +878,13 @@ static void config_nand_page_write(struct qcom_nand_controller *nandc) */ static void config_nand_cw_write(struct qcom_nand_controller *nandc) { - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_STATUS, 1); - write_reg_dma(nandc, NAND_READ_STATUS, 1); + write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); + write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); } /* @@ -911,8 +931,8 @@ static int nandc_param(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); - write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1); - write_reg_dma(nandc, NAND_DEV_CMD1, 1); + write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); nandc->buf_count = 512; memset(nandc->data_buffer, 0xff, nandc->buf_count); @@ -920,11 +940,11 @@ static int nandc_param(struct qcom_nand_host *host) config_nand_single_cw_page_read(nandc); read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - nandc->buf_count); + nandc->buf_count, 0); /* restore CMD1 and VLD regs */ - write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1); - write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1); + write_reg_dma(nandc, NAND_DEV_CMD1_RESTORE, 1, 0); + write_reg_dma(nandc, NAND_DEV_CMD_VLD_RESTORE, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -946,14 +966,14 @@ static int erase_block(struct qcom_nand_host *host, int page_addr) nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); - write_reg_dma(nandc, NAND_FLASH_CMD, 3); - write_reg_dma(nandc, NAND_DEV0_CFG0, 2); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); - write_reg_dma(nandc, NAND_FLASH_STATUS, 1); - write_reg_dma(nandc, NAND_READ_STATUS, 1); + write_reg_dma(nandc, NAND_FLASH_STATUS, 1, 0); + write_reg_dma(nandc, NAND_READ_STATUS, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -973,10 +993,10 @@ static int read_id(struct qcom_nand_host *host, int column) nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); - write_reg_dma(nandc, NAND_FLASH_CMD, 4); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_READ_ID, 1); + read_reg_dma(nandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -990,10 +1010,10 @@ static int reset(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_FLASH_CMD, RESET_DEVICE); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); - write_reg_dma(nandc, NAND_FLASH_CMD, 1); - write_reg_dma(nandc, NAND_EXEC_CMD, 1); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); - read_reg_dma(nandc, NAND_FLASH_STATUS, 1); + read_reg_dma(nandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL); return 0; } @@ -1389,7 +1409,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, if (data_buf) read_data_dma(nandc, FLASH_BUF_ACC, data_buf, - data_size); + data_size, 0); /* * when ecc is enabled, the controller doesn't read the real @@ -1405,7 +1425,7 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, *oob_buf++ = 0xff; read_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size); + oob_buf, oob_size, 0); } if (data_buf) @@ -1447,7 +1467,7 @@ static int copy_last_cw(struct qcom_nand_host *host, int page) config_nand_single_cw_page_read(nandc); - read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size); + read_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, size, 0); ret = submit_descs(nandc); if (ret) @@ -1516,19 +1536,19 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, config_nand_cw_read(nandc); - read_data_dma(nandc, reg_off, data_buf, data_size1); + read_data_dma(nandc, reg_off, data_buf, data_size1, 0); reg_off += data_size1; data_buf += data_size1; - read_data_dma(nandc, reg_off, oob_buf, oob_size1); + read_data_dma(nandc, reg_off, oob_buf, oob_size1, 0); reg_off += oob_size1; oob_buf += oob_size1; - read_data_dma(nandc, reg_off, data_buf, data_size2); + read_data_dma(nandc, reg_off, data_buf, data_size2, 0); reg_off += data_size2; data_buf += data_size2; - read_data_dma(nandc, reg_off, oob_buf, oob_size2); + read_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; } @@ -1595,7 +1615,8 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, } - write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size); + write_data_dma(nandc, FLASH_BUF_ACC, data_buf, data_size, + i == (ecc->steps - 1) ? NAND_BAM_NO_EOT : 0); /* * when ECC is enabled, we don't really need to write anything @@ -1608,7 +1629,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, oob_buf += host->bbm_size; write_data_dma(nandc, FLASH_BUF_ACC + data_size, - oob_buf, oob_size); + oob_buf, oob_size, 0); } config_nand_cw_write(nandc); @@ -1663,19 +1684,22 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } - write_data_dma(nandc, reg_off, data_buf, data_size1); + write_data_dma(nandc, reg_off, data_buf, data_size1, + NAND_BAM_NO_EOT); reg_off += data_size1; data_buf += data_size1; - write_data_dma(nandc, reg_off, oob_buf, oob_size1); + write_data_dma(nandc, reg_off, oob_buf, oob_size1, + NAND_BAM_NO_EOT); reg_off += oob_size1; oob_buf += oob_size1; - write_data_dma(nandc, reg_off, data_buf, data_size2); + write_data_dma(nandc, reg_off, data_buf, data_size2, + NAND_BAM_NO_EOT); reg_off += data_size2; data_buf += data_size2; - write_data_dma(nandc, reg_off, oob_buf, oob_size2); + write_data_dma(nandc, reg_off, oob_buf, oob_size2, 0); oob_buf += oob_size2; config_nand_cw_write(nandc); @@ -1729,8 +1753,8 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, update_rw_regs(host, 1, false); config_nand_page_write(nandc); - write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, - data_size + oob_size); + write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, data_size + oob_size, 0); config_nand_cw_write(nandc); ret = submit_descs(nandc); @@ -1814,7 +1838,8 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) update_rw_regs(host, 1, false); config_nand_page_write(nandc); - write_data_dma(nandc, FLASH_BUF_ACC, nandc->data_buffer, host->cw_size); + write_data_dma(nandc, FLASH_BUF_ACC, + nandc->data_buffer, host->cw_size, 0); config_nand_cw_write(nandc); ret = submit_descs(nandc); -- cgit v1.2.3-59-g8ed1b From 91af95c143088d4c17d1fad238c4b0e999f4a5e8 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:43 +0530 Subject: mtd: nand: qcom: support for read location registers In EBI2, all codeword data will be read in FLASH_BUF_ACC buffer and ADM will copy the data from source (FLASH_BUF_ACC) to destination (memory for data read). In QPIC, there is no FLASH_BUF_ACC and all the codeword data will held in QPIC BAM FIFO buffers. It provides multiple READ_LOCATION registers which will be used for copying the data from FIFO to memory. The READ_LOCATION register will be used to read a specific amount of data from a specific offset within the flash buffer. It supports sequential offset requests. Each request is composed of the following fields: a. Offset within the flash buffer from which data should be read b. Amount of data to be read c. Flag bit specifying the last read request from the flash buffer. Following the last read request the NANDc refers to the buffer as empty. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index c9226172c3a3..9d55e8e30ea6 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -53,6 +53,8 @@ #define NAND_VERSION 0xf08 #define NAND_READ_LOCATION_0 0xf20 #define NAND_READ_LOCATION_1 0xf24 +#define NAND_READ_LOCATION_2 0xf28 +#define NAND_READ_LOCATION_3 0xf2c /* dummy register offsets, used by write_reg_dma */ #define NAND_DEV_CMD1_RESTORE 0xdead @@ -135,6 +137,11 @@ #define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED) #define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED) +/* NAND_READ_LOCATION_n bits */ +#define READ_LOCATION_OFFSET 0 +#define READ_LOCATION_SIZE 16 +#define READ_LOCATION_LAST 31 + /* Version Mask */ #define NAND_VERSION_MAJOR_MASK 0xf0000000 #define NAND_VERSION_MAJOR_SHIFT 28 @@ -177,6 +184,12 @@ #define ECC_BCH_4BIT BIT(2) #define ECC_BCH_8BIT BIT(3) +#define nandc_set_read_loc(nandc, reg, offset, size, is_last) \ +nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ + ((offset) << READ_LOCATION_OFFSET) | \ + ((size) << READ_LOCATION_SIZE) | \ + ((is_last) << READ_LOCATION_LAST)) + #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 @@ -263,6 +276,11 @@ struct nandc_regs { __le32 orig_vld; __le32 ecc_buf_cfg; + __le32 read_location0; + __le32 read_location1; + __le32 read_location2; + __le32 read_location3; + }; /* @@ -519,6 +537,14 @@ static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset) return ®s->orig_vld; case NAND_EBI2_ECC_BUF_CFG: return ®s->ecc_buf_cfg; + case NAND_READ_LOCATION_0: + return ®s->read_location0; + case NAND_READ_LOCATION_1: + return ®s->read_location1; + case NAND_READ_LOCATION_2: + return ®s->read_location2; + case NAND_READ_LOCATION_3: + return ®s->read_location3; default: return NULL; } @@ -593,6 +619,10 @@ static void update_rw_regs(struct qcom_nand_host *host, int num_cw, bool read) nandc_set_reg(nandc, NAND_FLASH_STATUS, host->clrflashstatus); nandc_set_reg(nandc, NAND_READ_STATUS, host->clrreadstatus); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); + + if (read) + nandc_set_read_loc(nandc, 0, 0, host->use_ecc ? + host->cw_data : host->cw_size, 1); } /* @@ -842,6 +872,10 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) */ static void config_nand_cw_read(struct qcom_nand_controller *nandc) { + if (nandc->props->is_bam) + write_reg_dma(nandc, NAND_READ_LOCATION_0, 4, + NAND_BAM_NEXT_SGL); + write_reg_dma(nandc, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL); write_reg_dma(nandc, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL); @@ -930,6 +964,7 @@ static int nandc_param(struct qcom_nand_host *host) nandc_set_reg(nandc, NAND_DEV_CMD1_RESTORE, nandc->cmd1); nandc_set_reg(nandc, NAND_DEV_CMD_VLD_RESTORE, nandc->vld); + nandc_set_read_loc(nandc, 0, 0, 512, 1); write_reg_dma(nandc, NAND_DEV_CMD_VLD, 1, 0); write_reg_dma(nandc, NAND_DEV_CMD1, 1, NAND_BAM_NEXT_SGL); @@ -1405,6 +1440,19 @@ static int read_page_ecc(struct qcom_nand_host *host, u8 *data_buf, oob_size = host->ecc_bytes_hw + host->spare_bytes; } + if (nandc->props->is_bam) { + if (data_buf && oob_buf) { + nandc_set_read_loc(nandc, 0, 0, data_size, 0); + nandc_set_read_loc(nandc, 1, data_size, + oob_size, 1); + } else if (data_buf) { + nandc_set_read_loc(nandc, 0, 0, data_size, 1); + } else { + nandc_set_read_loc(nandc, 0, data_size, + oob_size, 1); + } + } + config_nand_cw_read(nandc); if (data_buf) @@ -1509,6 +1557,7 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, u8 *data_buf, *oob_buf; struct nand_ecc_ctrl *ecc = &chip->ecc; int i, ret; + int read_loc; data_buf = buf; oob_buf = chip->oob_poi; @@ -1534,6 +1583,20 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_size2 = host->ecc_bytes_hw + host->spare_bytes; } + if (nandc->props->is_bam) { + read_loc = 0; + nandc_set_read_loc(nandc, 0, read_loc, data_size1, 0); + read_loc += data_size1; + + nandc_set_read_loc(nandc, 1, read_loc, oob_size1, 0); + read_loc += oob_size1; + + nandc_set_read_loc(nandc, 2, read_loc, data_size2, 0); + read_loc += data_size2; + + nandc_set_read_loc(nandc, 3, read_loc, oob_size2, 1); + } + config_nand_cw_read(nandc); read_data_dma(nandc, reg_off, data_buf, data_size1, 0); -- cgit v1.2.3-59-g8ed1b From a86b9c4f57108a1368b7363bda12de704a7a64ec Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:44 +0530 Subject: mtd: nand: qcom: erased codeword detection configuration The NAND controller returns ECC failure during read of completely erased codeword. The NAND controller has hardware functionality to detect erased codeword in case of BCH ECC algorithm. The NAND_ERASED_CW_DETECT_CFG register controls the erased codeword/page detection controller. This register should be reset before every page read by setting and clearing bit 0 of NAND_ERASED_CW_DETECT_CFG. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 9d55e8e30ea6..81cfce794ca7 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -203,6 +203,11 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ #define NAND_BAM_NWD BIT(1) /* Finish writing in the current BAM sgl and start writing in another BAM sgl */ #define NAND_BAM_NEXT_SGL BIT(2) +/* + * Erased codeword status is being used two times in single transfer so this + * flag will determine the current value of erased codeword status register + */ +#define NAND_ERASED_CW_SET BIT(4) /* * This data type corresponds to the BAM transaction which will be used for all @@ -281,6 +286,8 @@ struct nandc_regs { __le32 read_location2; __le32 read_location3; + __le32 erased_cw_detect_cfg_clr; + __le32 erased_cw_detect_cfg_set; }; /* @@ -810,6 +817,13 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_FLASH_CMD) flow_control = true; + if (first == NAND_ERASED_CW_DETECT_CFG) { + if (flags & NAND_ERASED_CW_SET) + vaddr = ®s->erased_cw_detect_cfg_set; + else + vaddr = ®s->erased_cw_detect_cfg_clr; + } + if (first == NAND_EXEC_CMD) flags |= NAND_BAM_NWD; @@ -864,6 +878,9 @@ static void config_nand_page_read(struct qcom_nand_controller *nandc) write_reg_dma(nandc, NAND_ADDR0, 2, 0); write_reg_dma(nandc, NAND_DEV0_CFG0, 3, 0); write_reg_dma(nandc, NAND_EBI2_ECC_BUF_CFG, 1, 0); + write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, 0); + write_reg_dma(nandc, NAND_ERASED_CW_DETECT_CFG, 1, + NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL); } /* @@ -2264,6 +2281,10 @@ static int qcom_nand_host_setup(struct qcom_nand_host *host) host->clrflashstatus = FS_READY_BSY_N; host->clrreadstatus = 0xc0; + nandc->regs->erased_cw_detect_cfg_clr = + cpu_to_le32(CLR_ERASED_PAGE_DET); + nandc->regs->erased_cw_detect_cfg_set = + cpu_to_le32(SET_ERASED_PAGE_DET); dev_dbg(nandc->dev, "cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n", -- cgit v1.2.3-59-g8ed1b From 9d43f91569526b60775174115c98768cb48fc828 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:45 +0530 Subject: mtd: nand: qcom: enable BAM or ADM mode 1. DM_EN is only required for EBI2 NAND controller which uses ADM 2. BAM mode will be disabled after power on reset which needs to be enabled before starting any BAM transfers. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 81cfce794ca7..fd77d592c4ee 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -163,6 +163,9 @@ #define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \ ERASE_START_VLD | SEQ_READ_START_VLD) +/* NAND_CTRL bits */ +#define BAM_MODE_EN BIT(0) + /* * the NAND controller performs reads/writes with ECC in 516 byte chunks. * the driver calls the chunks 'step' or 'codeword' interchangeably @@ -1042,7 +1045,8 @@ static int read_id(struct qcom_nand_host *host, int column) nandc_set_reg(nandc, NAND_FLASH_CMD, FETCH_ID); nandc_set_reg(nandc, NAND_ADDR0, column); nandc_set_reg(nandc, NAND_ADDR1, 0); - nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + nandc_set_reg(nandc, NAND_FLASH_CHIP_SELECT, + nandc->props->is_bam ? 0 : DM_EN); nandc_set_reg(nandc, NAND_EXEC_CMD, 1); write_reg_dma(nandc, NAND_FLASH_CMD, 4, NAND_BAM_NEXT_SGL); @@ -2414,12 +2418,19 @@ static void qcom_nandc_unalloc(struct qcom_nand_controller *nandc) /* one time setup of a few nand controller registers */ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) { + u32 nand_ctrl; + /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); - /* enable ADM DMA */ - nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + /* enable ADM or BAM DMA */ + if (nandc->props->is_bam) { + nand_ctrl = nandc_read(nandc, NAND_CTRL); + nandc_write(nandc, NAND_CTRL, nand_ctrl | BAM_MODE_EN); + } else { + nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN); + } /* save the original values of these registers */ nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); -- cgit v1.2.3-59-g8ed1b From 4e2f6c52f4840b0d2ad1a62b71bf139cb0ec0915 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:46 +0530 Subject: mtd: nand: qcom: QPIC data descriptors handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add the data descriptor preparation function which will be used only by BAM DMA for forming the data SGL’s 2. Add clear BAM transaction and call it before every new request 3. Check DMA mode for ADM or BAM and call the appropriate descriptor formation function. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 76 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index fd77d592c4ee..1ff5daf9d619 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -473,6 +473,27 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) return bam_txn; } +/* Clears the BAM transaction indexes */ +static void clear_bam_transaction(struct qcom_nand_controller *nandc) +{ + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (!nandc->props->is_bam) + return; + + bam_txn->cmd_sgl_pos = 0; + bam_txn->cmd_sgl_start = 0; + bam_txn->tx_sgl_pos = 0; + bam_txn->tx_sgl_start = 0; + bam_txn->rx_sgl_pos = 0; + bam_txn->rx_sgl_start = 0; + + sg_init_table(bam_txn->cmd_sgl, nandc->max_cwperpage * + QPIC_PER_CW_CMD_SGL); + sg_init_table(bam_txn->data_sgl, nandc->max_cwperpage * + QPIC_PER_CW_DATA_SGL); +} + static inline struct qcom_nand_host *to_qcom_nand_host(struct nand_chip *chip) { return container_of(chip, struct qcom_nand_host, chip); @@ -704,6 +725,41 @@ static int prepare_bam_async_desc(struct qcom_nand_controller *nandc, return 0; } +/* + * Prepares the data descriptor for BAM DMA which will be used for NAND + * data reads and writes. + */ +static int prep_bam_dma_desc_data(struct qcom_nand_controller *nandc, bool read, + const void *vaddr, + int size, unsigned int flags) +{ + int ret; + struct bam_transaction *bam_txn = nandc->bam_txn; + + if (read) { + sg_set_buf(&bam_txn->data_sgl[bam_txn->rx_sgl_pos], + vaddr, size); + bam_txn->rx_sgl_pos++; + } else { + sg_set_buf(&bam_txn->data_sgl[bam_txn->tx_sgl_pos], + vaddr, size); + bam_txn->tx_sgl_pos++; + + /* + * BAM will only set EOT for DMA_PREP_INTERRUPT so if this flag + * is not set, form the DMA descriptor + */ + if (!(flags & NAND_BAM_NO_EOT)) { + ret = prepare_bam_async_desc(nandc, nandc->tx_chan, + DMA_PREP_INTERRUPT); + if (ret) + return ret; + } + } + + return 0; +} + static int prep_adm_dma_desc(struct qcom_nand_controller *nandc, bool read, int reg_off, const void *vaddr, int size, bool flow_control) @@ -854,6 +910,9 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { + if (nandc->props->is_bam) + return prep_bam_dma_desc_data(nandc, true, vaddr, size, flags); + return prep_adm_dma_desc(nandc, true, reg_off, vaddr, size, false); } @@ -869,6 +928,9 @@ static int read_data_dma(struct qcom_nand_controller *nandc, int reg_off, static int write_data_dma(struct qcom_nand_controller *nandc, int reg_off, const u8 *vaddr, int size, unsigned int flags) { + if (nandc->props->is_bam) + return prep_bam_dma_desc_data(nandc, false, vaddr, size, flags); + return prep_adm_dma_desc(nandc, false, reg_off, vaddr, size, false); } @@ -1156,6 +1218,10 @@ static void pre_command(struct qcom_nand_host *host, int command) host->last_command = command; clear_read_regs(nandc); + + if (command == NAND_CMD_RESET || command == NAND_CMD_READID || + command == NAND_CMD_PARAM || command == NAND_CMD_ERASE1) + clear_bam_transaction(nandc); } /* @@ -1559,6 +1625,7 @@ static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip, data_buf = buf; oob_buf = oob_required ? chip->oob_poi : NULL; + clear_bam_transaction(nandc); ret = read_page_ecc(host, data_buf, oob_buf); if (ret) { dev_err(nandc->dev, "failure to read page\n"); @@ -1584,6 +1651,8 @@ static int qcom_nandc_read_page_raw(struct mtd_info *mtd, oob_buf = chip->oob_poi; host->use_ecc = false; + + clear_bam_transaction(nandc); update_rw_regs(host, ecc->steps, true); config_nand_page_read(nandc); @@ -1655,6 +1724,7 @@ static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); host->use_ecc = true; set_address(host, 0, page); @@ -1678,6 +1748,7 @@ static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip, int i, ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -1743,6 +1814,7 @@ static int qcom_nandc_write_page_raw(struct mtd_info *mtd, int i, ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); data_buf = (u8 *)buf; oob_buf = chip->oob_poi; @@ -1819,11 +1891,13 @@ static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, host->use_ecc = true; + clear_bam_transaction(nandc); ret = copy_last_cw(host, page); if (ret) return ret; clear_read_regs(nandc); + clear_bam_transaction(nandc); /* calculate the data and oob size for the last codeword/step */ data_size = ecc->size - ((ecc->steps - 1) << 2); @@ -1876,6 +1950,7 @@ static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs) */ host->use_ecc = false; + clear_bam_transaction(nandc); ret = copy_last_cw(host, page); if (ret) goto err; @@ -1906,6 +1981,7 @@ static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs) int page, ret, status = 0; clear_read_regs(nandc); + clear_bam_transaction(nandc); /* * to mark the BBM as bad, we flash the entire last codeword with 0s. -- cgit v1.2.3-59-g8ed1b From cc409b9a8ec5e88d6f712c535d88b14765f234c4 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:47 +0530 Subject: mtd: nand: qcom: support for different DEV_CMD register offsets The FLASH_DEV_CMD registers starting offset is not same in different QPIC NAND controller versions. This patch adds the starting offset in NAND controller properties and uses the same for calculating the actual offset of these registers. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 1ff5daf9d619..7977a70a0499 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -193,6 +193,12 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ ((size) << READ_LOCATION_SIZE) | \ ((is_last) << READ_LOCATION_LAST)) +/* + * Returns the actual register address for all NAND_DEV_ registers + * (i.e. NAND_DEV_CMD0, NAND_DEV_CMD1, NAND_DEV_CMD2 and NAND_DEV_CMD_VLD) + */ +#define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) + #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 @@ -429,10 +435,12 @@ struct qcom_nand_host { * among different NAND controllers. * @ecc_modes - ecc mode for NAND * @is_bam - whether NAND controller is using BAM + * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset */ struct qcom_nandc_props { u32 ecc_modes; bool is_bam; + u32 dev_cmd_reg_start; }; /* Frees the BAM transaction memory */ @@ -848,6 +856,9 @@ static int read_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_READ_ID || first == NAND_FLASH_STATUS) flow_control = true; + if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, first); + size = num_regs * sizeof(u32); vaddr = nandc->reg_read_buf + nandc->reg_read_pos; nandc->reg_read_pos += num_regs; @@ -886,11 +897,11 @@ static int write_reg_dma(struct qcom_nand_controller *nandc, int first, if (first == NAND_EXEC_CMD) flags |= NAND_BAM_NWD; - if (first == NAND_DEV_CMD1_RESTORE) - first = NAND_DEV_CMD1; + if (first == NAND_DEV_CMD1_RESTORE || first == NAND_DEV_CMD1) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD1); - if (first == NAND_DEV_CMD_VLD_RESTORE) - first = NAND_DEV_CMD_VLD; + if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD) + first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD); size = num_regs * sizeof(u32); @@ -2498,7 +2509,8 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) /* kill onenand */ nandc_write(nandc, SFLASHC_BURST_CFG, 0); - nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL); + nandc_write(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD), + NAND_DEV_CMD_VLD_VAL); /* enable ADM or BAM DMA */ if (nandc->props->is_bam) { @@ -2509,7 +2521,7 @@ static int qcom_nandc_setup(struct qcom_nand_controller *nandc) } /* save the original values of these registers */ - nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1); + nandc->cmd1 = nandc_read(nandc, dev_cmd_reg_addr(nandc, NAND_DEV_CMD1)); nandc->vld = NAND_DEV_CMD_VLD_VAL; return 0; @@ -2758,6 +2770,7 @@ static int qcom_nandc_remove(struct platform_device *pdev) static const struct qcom_nandc_props ipq806x_nandc_props = { .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), .is_bam = false, + .dev_cmd_reg_start = 0x0, }; /* -- cgit v1.2.3-59-g8ed1b From a06378341eeb809f9df4e80ddb507418b3e36d97 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:53 +0530 Subject: mtd: nand: qcom: support for IPQ4019 QPIC NAND controller Add the compatible string for IPQ4019 QPIC NAND controller version 1.4.0 which uses BAM DMA. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 7977a70a0499..158076c6ea3e 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2773,6 +2773,12 @@ static const struct qcom_nandc_props ipq806x_nandc_props = { .dev_cmd_reg_start = 0x0, }; +static const struct qcom_nandc_props ipq4019_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), + .is_bam = true, + .dev_cmd_reg_start = 0x0, +}; + /* * data will hold a struct pointer containing more differences once we support * more controller variants @@ -2782,6 +2788,10 @@ static const struct of_device_id qcom_nandc_of_match[] = { .compatible = "qcom,ipq806x-nand", .data = &ipq806x_nandc_props, }, + { + .compatible = "qcom,ipq4019-nand", + .data = &ipq4019_nandc_props, + }, {} }; MODULE_DEVICE_TABLE(of, qcom_nandc_of_match); -- cgit v1.2.3-59-g8ed1b From dce84760b09f8c3d6c9e001fe5f37be93d2daa46 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Thu, 17 Aug 2017 17:37:54 +0530 Subject: mtd: nand: qcom: Support for IPQ8074 QPIC NAND controller Add the compatible string for IPQ8074 QPIC NAND controller version 1.5.0 which uses BAM DMA and its FLASH_DEV_CMD registers starting offset is 0x7000. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 158076c6ea3e..131738a6e86a 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2779,6 +2779,12 @@ static const struct qcom_nandc_props ipq4019_nandc_props = { .dev_cmd_reg_start = 0x0, }; +static const struct qcom_nandc_props ipq8074_nandc_props = { + .ecc_modes = (ECC_BCH_4BIT | ECC_BCH_8BIT), + .is_bam = true, + .dev_cmd_reg_start = 0x7000, +}; + /* * data will hold a struct pointer containing more differences once we support * more controller variants @@ -2792,6 +2798,10 @@ static const struct of_device_id qcom_nandc_of_match[] = { .compatible = "qcom,ipq4019-nand", .data = &ipq4019_nandc_props, }, + { + .compatible = "qcom,ipq8074-nand", + .data = &ipq8074_nandc_props, + }, {} }; MODULE_DEVICE_TABLE(of, qcom_nandc_of_match); -- cgit v1.2.3-59-g8ed1b From 482ead931e05b4d5556a5ffd51c2f40cd586f20c Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:35 +0200 Subject: mtd: nand: sharpsl: Register partitions using the parsers With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Use now these parsers. Signed-off-by: Andrea Adami Signed-off-by: Boris Brezillon --- drivers/mtd/nand/sharpsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 064ca1757589..9859546a9207 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -183,7 +183,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ mtd->name = "sharpsl-nand"; - err = mtd_device_parse_register(mtd, NULL, NULL, + err = mtd_device_parse_register(mtd, data->part_parsers, NULL, data->partitions, data->nr_partitions); if (err) goto err_add; -- cgit v1.2.3-59-g8ed1b From 311bba10cb0e232f2f9b0bace8bec873d7dc32a7 Mon Sep 17 00:00:00 2001 From: Andrea Adami Date: Mon, 14 Aug 2017 22:48:36 +0200 Subject: mtd: nand: tmio: Register partitions using the parsers With the introduction of sharpslpart partition parser we can now read the offsets from NAND: we specify the list of the parsers as platform data, with cmdlinepart and ofpart parsers first allowing to override the part. table written in NAND. This is done in the board files using this driver. Use now these parsers. Signed-off-by: Andrea Adami Acked-by: Wolfram Sang Signed-off-by: Boris Brezillon --- drivers/mtd/nand/tmio_nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index fc5e773f8b60..47f439fb6ae3 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -440,7 +440,9 @@ static int tmio_probe(struct platform_device *dev) goto err_irq; /* Register the partitions */ - retval = mtd_device_parse_register(mtd, NULL, NULL, + retval = mtd_device_parse_register(mtd, + data ? data->part_parsers : NULL, + NULL, data ? data->partition : NULL, data ? data->num_partitions : 0); if (!retval) -- cgit v1.2.3-59-g8ed1b From 69fc01296c92814b62dbfba1600fe7ed2ed304f5 Mon Sep 17 00:00:00 2001 From: Lothar Waßmann Date: Tue, 29 Aug 2017 12:17:12 +0200 Subject: mtd: nand: make Samsung SLC NAND usable again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c51d0ac59f24 ("mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c") introduced a regression for Samsung SLC NAND chips. Prior to this commit chip->bits_per_cell was initialized by calling nand_get_bits_per_cell() before using nand_is_slc(). With the offending commit this call is skipped, leaving chip->bits_per_cell cleared to zero when the manufacturer specific '.detect' function calls nand_is_slc() which in turn interprets bits_per_cell != 1 as indication for an MLC chip. The effect is that e.g. a K9F1G08U0F NAND chip is falsely detected as MLC NAND with 4KiB page size rather than SLC with 2KiB page size. Add a call to nand_get_bits_per_cell() before calling the .detect hook function in nand_manufacturer_detect(), so that the nand_is_slc() calls in the manufacturer specific code will return correct results. Fixes: c51d0ac59f24 ("mtd: nand: Move Samsung specific init/detection logic in nand_samsung.c") Cc: Signed-off-by: Lothar Waßmann Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8f4a681fd10e..6ed5392f3798 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3813,10 +3813,13 @@ static void nand_manufacturer_detect(struct nand_chip *chip) * nand_decode_ext_id() otherwise. */ if (chip->manufacturer.desc && chip->manufacturer.desc->ops && - chip->manufacturer.desc->ops->detect) + chip->manufacturer.desc->ops->detect) { + /* The 3rd id byte holds MLC / multichip data */ + chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]); chip->manufacturer.desc->ops->detect(chip); - else + } else { nand_decode_ext_id(chip); + } } /* -- cgit v1.2.3-59-g8ed1b