From 882fd1577cbe7812ae3a48988180c5f0fda475ca Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Sat, 26 Aug 2017 17:19:15 +0200 Subject: mtd: nand: Use standard large page OOB layout when using NAND_ECC_NONE Use the core's large page OOB layout functions when not reserving any space for ECC bytes in the OOB layout. Fix ->nand_ooblayout_ecc_lp() to return -ERANGE instead of a zero length in this case. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bcc8cef1c615..fae28ec56277 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -115,7 +115,7 @@ static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, struct nand_chip *chip = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; - if (section) + if (section || !ecc->total) return -ERANGE; oobregion->length = ecc->total; @@ -4701,6 +4701,19 @@ int nand_scan_tail(struct mtd_info *mtd) mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops); break; default: + /* + * Expose the whole OOB area to users if ECC_NONE + * is passed. We could do that for all kind of + * ->oobsize, but we must keep the old large/small + * page with ECC layout when ->oobsize <= 128 for + * compatibility reasons. + */ + if (ecc->mode == NAND_ECC_NONE) { + mtd_set_ooblayout(mtd, + &nand_ooblayout_lp_ops); + break; + } + WARN(1, "No oob scheme defined for oobsize %d\n", mtd->oobsize); ret = -EINVAL; -- cgit v1.2.3 From 14157f861437ebe2d624b0a845b91bbdf8ca9a2d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 Sep 2017 11:05:50 +0900 Subject: mtd: nand: introduce NAND_ROW_ADDR_3 flag Several drivers check ->chipsize to see if the third row address cycle is needed. Instead of embedding magic sizes such as 32MB, 128MB in drivers, introduce a new flag NAND_ROW_ADDR_3 for clean-up. Since nand_scan_ident() knows well about the device, it can handle this properly. The flag is set if the row address bit width is greater than 16. Delete comments such as "One more address cycle for ..." because intention is now clear enough from the code. Signed-off-by: Masahiro Yamada Acked-by: Wenyou Yang Signed-off-by: Boris Brezillon --- drivers/mtd/nand/atmel/nand-controller.c | 3 +-- drivers/mtd/nand/au1550nd.c | 3 +-- drivers/mtd/nand/diskonchip.c | 3 +-- drivers/mtd/nand/hisi504_nand.c | 3 +-- drivers/mtd/nand/mxc_nand.c | 3 +-- drivers/mtd/nand/nand_base.c | 9 +++++---- drivers/mtd/nand/nuc900_nand.c | 2 +- 7 files changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index f25eca79f4e5..7bc8d20ed885 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -718,8 +718,7 @@ static void atmel_nfc_set_op_addr(struct nand_chip *chip, int page, int column) nc->op.addrs[nc->op.naddrs++] = page; nc->op.addrs[nc->op.naddrs++] = page >> 8; - if ((mtd->writesize > 512 && chip->chipsize > SZ_128M) || - (mtd->writesize <= 512 && chip->chipsize > SZ_32M)) + if (chip->options & NAND_ROW_ADDR_3) nc->op.addrs[nc->op.naddrs++] = page >> 16; } } diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 9d4a28fa6b73..8ab827edf94e 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -331,8 +331,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ctx->write_byte(mtd, (u8)(page_addr >> 8)); - /* One more address cycle for devices > 32MiB */ - if (this->chipsize > (32 << 20)) + if (this->options & NAND_ROW_ADDR_3) ctx->write_byte(mtd, ((page_addr >> 16) & 0x0f)); } diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index c3aa53caab5c..72671dc52e2e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -705,8 +705,7 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu if (page_addr != -1) { WriteDOC((unsigned char)(page_addr & 0xff), docptr, Mplus_FlashAddress); WriteDOC((unsigned char)((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) { + if (this->options & NAND_ROW_ADDR_3) { WriteDOC((unsigned char)((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); printk("high density\n"); } diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index d9ee1a7e6956..0897261c3e17 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -432,8 +432,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr) host->addr_value[0] |= (page_addr & 0xffff) << (host->addr_cycle * 8); host->addr_cycle += 2; - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) { + if (chip->options & NAND_ROW_ADDR_3) { host->addr_cycle += 1; if (host->command == NAND_CMD_ERASE1) host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 53e5e0337c3e..bacdd04e765b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -859,8 +859,7 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) host->devtype_data->send_addr(host, (page_addr >> 8) & 0xff, true); } else { - /* One more address cycle for higher density devices */ - if (mtd->size >= 0x4000000) { + if (nand_chip->options & NAND_ROW_ADDR_3) { /* paddr_8 - paddr_15 */ host->devtype_data->send_addr(host, (page_addr >> 8) & 0xff, diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index fae28ec56277..c63e4a88a653 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -727,8 +727,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, page_addr, ctrl); ctrl &= ~NAND_CTRL_CHANGE; chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - /* One more address cycle for devices > 32MiB */ - if (chip->chipsize > (32 << 20)) + if (chip->options & NAND_ROW_ADDR_3) chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); } chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); @@ -854,8 +853,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, page_addr, ctrl); chip->cmd_ctrl(mtd, page_addr >> 8, NAND_NCE | NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) + if (chip->options & NAND_ROW_ADDR_3) chip->cmd_ctrl(mtd, page_addr >> 16, NAND_NCE | NAND_ALE); } @@ -4000,6 +3998,9 @@ ident_done: chip->chip_shift += 32 - 1; } + if (chip->chip_shift - chip->page_shift > 16) + chip->options |= NAND_ROW_ADDR_3; + chip->badblockbits = 8; chip->erase = single_erase; diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 7bb4d2ea9342..af5b32c9a791 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -154,7 +154,7 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, if (page_addr != -1) { write_addr_reg(nand, page_addr); - if (chip->chipsize > (128 << 20)) { + if (chip->options & NAND_ROW_ADDR_3) { write_addr_reg(nand, page_addr >> 8); write_addr_reg(nand, page_addr >> 16 | ENDADDR); } else { -- cgit v1.2.3 From a3750a6422a7112740fe69a596bcd5eb62577aed Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 13 Sep 2017 11:05:51 +0900 Subject: mtd: nand: denali: support two row address cycle devices The register TWO_ROW_ADDR_CYCLES specifies the number of row address cycles of the device, but it is fixed to 0 in the driver init code (i.e. always 3 row address cycles). Reflect the result of nand_scan_ident() to the register setting in order to support 2 row address cycle devices. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3087b0ba7b7f..aefdc83bdab0 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1137,8 +1137,6 @@ static void denali_hw_init(struct denali_nand_info *denali) iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); - /* Should set value for these registers when init */ - iowrite32(0, denali->reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->reg + ECC_ENABLE); } @@ -1379,6 +1377,8 @@ int denali_init(struct denali_nand_info *denali) denali->reg + PAGES_PER_BLOCK); iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0, denali->reg + DEVICE_WIDTH); + iowrite32(chip->options & NAND_ROW_ADDR_3 ? 0 : TWO_ROW_ADDR_CYCLES__FLAG, + denali->reg + TWO_ROW_ADDR_CYCLES); iowrite32(mtd->writesize, denali->reg + DEVICE_MAIN_AREA_SIZE); iowrite32(mtd->oobsize, denali->reg + DEVICE_SPARE_AREA_SIZE); -- cgit v1.2.3 From ee0ae6a38d7acf0ec68ac8bb043a7e7cdbd002c8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:38 +0900 Subject: mtd: nand: denali: squash setup_ecc_for_xfer() helper into caller The setup_ecc_for_xfer() is only called from denali_data_xfer(). This helper is small enough, so squash it into the caller. This looks cleaner to me. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index aefdc83bdab0..d847ae48267d 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -208,24 +208,6 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali) return irq_status; } -/* - * This helper function setups the registers for ECC and whether or not - * the spare area will be transferred. - */ -static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, - bool transfer_spare) -{ - int ecc_en_flag, transfer_spare_flag; - - /* set ECC, transfer spare bits if needed */ - ecc_en_flag = ecc_en ? ECC_ENABLE__FLAG : 0; - transfer_spare_flag = transfer_spare ? TRANSFER_SPARE_REG__FLAG : 0; - - /* Enable spare area/ECC per user's request. */ - iowrite32(ecc_en_flag, denali->reg + ECC_ENABLE); - iowrite32(transfer_spare_flag, denali->reg + TRANSFER_SPARE_REG); -} - static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct denali_nand_info *denali = mtd_to_denali(mtd); @@ -659,7 +641,9 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, static int denali_data_xfer(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw, int write) { - setup_ecc_for_xfer(denali, !raw, raw); + iowrite32(raw ? 0 : ECC_ENABLE__FLAG, denali->reg + ECC_ENABLE); + iowrite32(raw ? TRANSFER_SPARE_REG__FLAG : 0, + denali->reg + TRANSFER_SPARE_REG); if (denali->dma_avail) return denali_dma_xfer(denali, buf, size, page, raw, write); -- cgit v1.2.3 From 3ac6c7166396060c2b427668470e2e626c358a39 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:39 +0900 Subject: mtd: nand: denali: prefix detect_max_banks() with denali_ All functions in this driver are prefixed with denali_ except detect_max_banks(). Rename it for consistency. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d847ae48267d..48193f946220 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -81,7 +81,7 @@ static void denali_host_write(struct denali_nand_info *denali, * Use the configuration feature register to determine the maximum number of * banks that the hardware supports. */ -static void detect_max_banks(struct denali_nand_info *denali) +static void denali_detect_max_banks(struct denali_nand_info *denali) { uint32_t features = ioread32(denali->reg + FEATURES); @@ -1115,7 +1115,7 @@ static void denali_hw_init(struct denali_nand_info *denali) * if this value is 0, just let it be. */ denali->oob_skip_bytes = ioread32(denali->reg + SPARE_AREA_SKIP_BYTES); - detect_max_banks(denali); + denali_detect_max_banks(denali); iowrite32(0x0F, denali->reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); -- cgit v1.2.3 From da4734be238341b873a94027fe24101b3e7c5c53 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:40 +0900 Subject: mtd: nand: denali: consolidate include directives Include necessary headers explicitly without relying on indirect header inclusion. Also, sort them alphabetically. , , turned out bogus, so removed. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 12 +++++++----- drivers/mtd/nand/denali.h | 3 +++ drivers/mtd/nand/denali_dt.c | 3 ++- drivers/mtd/nand/denali_pci.c | 3 +++ 4 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 48193f946220..4daeb7fa9eec 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -16,14 +16,16 @@ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * */ -#include -#include + +#include #include -#include -#include -#include +#include +#include #include +#include +#include #include +#include #include "denali.h" diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 9239e6793e6e..dc3f970feae5 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -21,7 +21,10 @@ #define __DENALI_H__ #include +#include #include +#include +#include #define DEVICE_RESET 0x0 #define DEVICE_RESET__BANK(bank) BIT(bank) diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 56e2e177644d..01e0100ed2e7 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -12,15 +12,16 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ + #include #include #include #include #include #include -#include #include #include +#include #include "denali.h" diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 81370c79aa48..7d5600b6d07c 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -11,6 +11,9 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ + +#include +#include #include #include #include -- cgit v1.2.3 From 586a2c52909df453ed1b6239283744b0851ccf81 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:41 +0900 Subject: mtd: nand: denali: squash denali_enable_dma() helper into caller This helper just sets/clears a flag of DMA_ENABLE register (with register read-back, I do not know why it is necessary). Move the register write code to the caller, and remove the helper. It works for me without the register read-back. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4daeb7fa9eec..e7b25de2e579 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -465,13 +465,6 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, return max_bitflips; } -/* programs the controller to either enable/disable DMA transfers */ -static void denali_enable_dma(struct denali_nand_info *denali, bool en) -{ - iowrite32(en ? DMA_ENABLE__FLAG : 0, denali->reg + DMA_ENABLE); - ioread32(denali->reg + DMA_ENABLE); -} - static void denali_setup_dma64(struct denali_nand_info *denali, dma_addr_t dma_addr, int page, int write) { @@ -619,7 +612,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, ecc_err_mask = INTR__ECC_ERR; } - denali_enable_dma(denali, true); + iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); denali_reset_irq(denali); denali_setup_dma(denali, dma_addr, page, write); @@ -631,7 +624,8 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, else if (irq_status & ecc_err_mask) ret = -EBADMSG; - denali_enable_dma(denali, false); + iowrite32(0, denali->reg + DMA_ENABLE); + dma_unmap_single(denali->dev, dma_addr, size, dir); if (irq_status & INTR__ERASED_PAGE) -- cgit v1.2.3 From fdd4d0836bdb0dd6a4e7e588d7dce2de37f8531d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:42 +0900 Subject: mtd: nand: denali: slight clean up of denali_wait_for_irq() This function has a local variable "irq_mask" and its value is the same as denali->irq_mask. Clean up the code a little. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e7b25de2e579..3cc56decbadb 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -191,7 +191,7 @@ static uint32_t denali_wait_for_irq(struct denali_nand_info *denali, msecs_to_jiffies(1000)); if (!time_left) { dev_err(denali->dev, "timeout while waiting for irq 0x%x\n", - denali->irq_mask); + irq_mask); return 0; } -- cgit v1.2.3 From e0d53b3f8ed2b14dab54a04a4589fa72b0827fa5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:43 +0900 Subject: mtd: nand: denali: clean up macros with All the register offsets and bitfield masks are defined in denali.h, but the driver code ended up with additional crappy macros such as MAKE_ECC_CORRECTION(), ECC_SECTOR(), etc. The reason is apparent - accessing a register field requires mask and shift pair. The denali.h only provides mask. However, defining both is tedious. provides a convenient way to get register fields only with a single shifted mask. Now use it. While I am here, I shortened some macros. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 25 +++++++++++-------------- drivers/mtd/nand/denali.h | 13 +++++-------- 2 files changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 3cc56decbadb..1525c4e61c80 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -386,13 +387,6 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, return max_bitflips; } -#define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) -#define ECC_BYTE(x) (((x) & ECC_ERROR_ADDRESS__OFFSET)) -#define ECC_CORRECTION_VALUE(x) ((x) & ERR_CORRECTION_INFO__BYTEMASK) -#define ECC_ERROR_UNCORRECTABLE(x) ((x) & ERR_CORRECTION_INFO__ERROR_TYPE) -#define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8) -#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) - static int denali_sw_ecc_fixup(struct mtd_info *mtd, struct denali_nand_info *denali, unsigned long *uncor_ecc_flags, uint8_t *buf) @@ -410,18 +404,20 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, do { err_addr = ioread32(denali->reg + ECC_ERROR_ADDRESS); - err_sector = ECC_SECTOR(err_addr); - err_byte = ECC_BYTE(err_addr); + err_sector = FIELD_GET(ECC_ERROR_ADDRESS__SECTOR, err_addr); + err_byte = FIELD_GET(ECC_ERROR_ADDRESS__OFFSET, err_addr); err_cor_info = ioread32(denali->reg + ERR_CORRECTION_INFO); - err_cor_value = ECC_CORRECTION_VALUE(err_cor_info); - err_device = ECC_ERR_DEVICE(err_cor_info); + err_cor_value = FIELD_GET(ERR_CORRECTION_INFO__BYTE, + err_cor_info); + err_device = FIELD_GET(ERR_CORRECTION_INFO__DEVICE, + err_cor_info); /* reset the bitflip counter when crossing ECC sector */ if (err_sector != prev_sector) bitflips = 0; - if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) { + if (err_cor_info & ERR_CORRECTION_INFO__UNCOR) { /* * Check later if this is a real ECC error, or * an erased sector. @@ -451,7 +447,7 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, } prev_sector = err_sector; - } while (!ECC_LAST_ERR(err_cor_info)); + } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); /* * Once handle all ecc errors, controller will trigger a @@ -1351,7 +1347,8 @@ int denali_init(struct denali_nand_info *denali) "chosen ECC settings: step=%d, strength=%d, bytes=%d\n", chip->ecc.size, chip->ecc.strength, chip->ecc.bytes); - iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1), + iowrite32(FIELD_PREP(ECC_CORRECTION__ERASE_THRESHOLD, 1) | + FIELD_PREP(ECC_CORRECTION__VALUE, chip->ecc.strength), denali->reg + ECC_CORRECTION); iowrite32(mtd->erasesize / mtd->writesize, denali->reg + PAGES_PER_BLOCK); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index dc3f970feae5..73aad3ac4577 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -114,9 +114,6 @@ #define ECC_CORRECTION 0x1b0 #define ECC_CORRECTION__VALUE GENMASK(4, 0) #define ECC_CORRECTION__ERASE_THRESHOLD GENMASK(31, 16) -#define MAKE_ECC_CORRECTION(val, thresh) \ - (((val) & (ECC_CORRECTION__VALUE)) | \ - (((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD))) #define READ_MODE 0x1c0 #define READ_MODE__VALUE GENMASK(3, 0) @@ -258,13 +255,13 @@ #define ECC_ERROR_ADDRESS 0x630 #define ECC_ERROR_ADDRESS__OFFSET GENMASK(11, 0) -#define ECC_ERROR_ADDRESS__SECTOR_NR GENMASK(15, 12) +#define ECC_ERROR_ADDRESS__SECTOR GENMASK(15, 12) #define ERR_CORRECTION_INFO 0x640 -#define ERR_CORRECTION_INFO__BYTEMASK GENMASK(7, 0) -#define ERR_CORRECTION_INFO__DEVICE_NR GENMASK(11, 8) -#define ERR_CORRECTION_INFO__ERROR_TYPE BIT(14) -#define ERR_CORRECTION_INFO__LAST_ERR_INFO BIT(15) +#define ERR_CORRECTION_INFO__BYTE GENMASK(7, 0) +#define ERR_CORRECTION_INFO__DEVICE GENMASK(11, 8) +#define ERR_CORRECTION_INFO__UNCOR BIT(14) +#define ERR_CORRECTION_INFO__LAST_ERR BIT(15) #define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) #define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) -- cgit v1.2.3 From 8e4cbf7f0a55a235fdd8c088da1259b9fe8e9393 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:44 +0900 Subject: mtd: nand: denali: use more FIELD_PREP / FIELD_GET where appropriate In several places in this driver, the register fields are retrieved as follows: val = reg & FOO_MASK; Then, modified as follows: reg &= ~FOO_MASK; reg |= val; This code relies on its shift is 0, which we will never know until we check the definition of FOO_MASK. Use FIELD_PREP / FIELD_GET where appropriate. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 1525c4e61c80..ca98015b9e6d 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -88,7 +88,7 @@ static void denali_detect_max_banks(struct denali_nand_info *denali) { uint32_t features = ioread32(denali->reg + FEATURES); - denali->max_banks = 1 << (features & FEATURES__N_BANKS); + denali->max_banks = 1 << FIELD_GET(FEATURES__N_BANKS, features); /* the encoding changed from rev 5.0 to 5.1 */ if (denali->revision < 0x0501) @@ -374,7 +374,7 @@ static int denali_hw_ecc_fixup(struct mtd_info *mtd, return 0; } - max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS; + max_bitflips = FIELD_GET(ECC_COR_INFO__MAX_ERRORS, ecc_cor); /* * The register holds the maximum of per-sector corrected bitflips. @@ -985,7 +985,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + ACC_CLKS); tmp &= ~ACC_CLKS__VALUE; - tmp |= acc_clks; + tmp |= FIELD_PREP(ACC_CLKS__VALUE, acc_clks); iowrite32(tmp, denali->reg + ACC_CLKS); /* tRWH -> RE_2_WE */ @@ -994,7 +994,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + RE_2_WE); tmp &= ~RE_2_WE__VALUE; - tmp |= re_2_we; + tmp |= FIELD_PREP(RE_2_WE__VALUE, re_2_we); iowrite32(tmp, denali->reg + RE_2_WE); /* tRHZ -> RE_2_RE */ @@ -1003,7 +1003,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + RE_2_RE); tmp &= ~RE_2_RE__VALUE; - tmp |= re_2_re; + tmp |= FIELD_PREP(RE_2_RE__VALUE, re_2_re); iowrite32(tmp, denali->reg + RE_2_RE); /* tWHR -> WE_2_RE */ @@ -1012,7 +1012,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE); tmp &= ~TWHR2_AND_WE_2_RE__WE_2_RE; - tmp |= we_2_re; + tmp |= FIELD_PREP(TWHR2_AND_WE_2_RE__WE_2_RE, we_2_re); iowrite32(tmp, denali->reg + TWHR2_AND_WE_2_RE); /* tADL -> ADDR_2_DATA */ @@ -1026,8 +1026,8 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, addr_2_data = min_t(int, addr_2_data, addr_2_data_mask); tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA); - tmp &= ~addr_2_data_mask; - tmp |= addr_2_data; + tmp &= ~TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA; + tmp |= FIELD_PREP(TCWAW_AND_ADDR_2_DATA__ADDR_2_DATA, addr_2_data); iowrite32(tmp, denali->reg + TCWAW_AND_ADDR_2_DATA); /* tREH, tWH -> RDWR_EN_HI_CNT */ @@ -1037,7 +1037,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + RDWR_EN_HI_CNT); tmp &= ~RDWR_EN_HI_CNT__VALUE; - tmp |= rdwr_en_hi; + tmp |= FIELD_PREP(RDWR_EN_HI_CNT__VALUE, rdwr_en_hi); iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT); /* tRP, tWP -> RDWR_EN_LO_CNT */ @@ -1051,7 +1051,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + RDWR_EN_LO_CNT); tmp &= ~RDWR_EN_LO_CNT__VALUE; - tmp |= rdwr_en_lo; + tmp |= FIELD_PREP(RDWR_EN_LO_CNT__VALUE, rdwr_en_lo); iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT); /* tCS, tCEA -> CS_SETUP_CNT */ @@ -1062,7 +1062,7 @@ static int denali_setup_data_interface(struct mtd_info *mtd, int chipnr, tmp = ioread32(denali->reg + CS_SETUP_CNT); tmp &= ~CS_SETUP_CNT__VALUE; - tmp |= cs_setup; + tmp |= FIELD_PREP(CS_SETUP_CNT__VALUE, cs_setup); iowrite32(tmp, denali->reg + CS_SETUP_CNT); return 0; -- cgit v1.2.3 From 8582a03e028f666d15acc651e0491c02941d13e7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:45 +0900 Subject: mtd: nand: denali: clean up comments This driver explains too much about what is apparent from the code. Comments around basic APIs such as init_completion(), spin_lock_init(), etc. seem unneeded lessons to kernel developers. (With those comments dropped, denali_drv_init() is small enough, so it has been merged into the probe function.) Also, NAND driver developers should know the NAND init procedure, so there is no need to explain nand_scan_ident/tail. I removed FSF's address from the license blocks, and added simple comments to struct members. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 52 +++++-------------------------------------- drivers/mtd/nand/denali.h | 24 +++++++------------- drivers/mtd/nand/denali_dt.c | 1 - drivers/mtd/nand/denali_pci.c | 2 -- 4 files changed, 13 insertions(+), 66 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ca98015b9e6d..02ce310f44e4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -10,11 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include @@ -64,10 +59,6 @@ MODULE_LICENSE("GPL"); */ #define DENALI_CLK_X_MULT 6 -/* - * this macro allows us to convert from an MTD structure to our own - * device context (denali) structure. - */ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) { return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); @@ -450,9 +441,8 @@ static int denali_sw_ecc_fixup(struct mtd_info *mtd, } while (!(err_cor_info & ERR_CORRECTION_INFO__LAST_ERR)); /* - * Once handle all ecc errors, controller will trigger a - * ECC_TRANSACTION_DONE interrupt, so here just wait for - * a while for this interrupt + * Once handle all ECC errors, controller will trigger an + * ECC_TRANSACTION_DONE interrupt. */ irq_status = denali_wait_for_irq(denali, INTR__ECC_TRANSACTION_DONE); if (!(irq_status & INTR__ECC_TRANSACTION_DONE)) @@ -613,7 +603,6 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, denali_reset_irq(denali); denali_setup_dma(denali, dma_addr, page, write); - /* wait for operation to complete */ irq_status = denali_wait_for_irq(denali, irq_mask); if (!(irq_status & INTR__DMA_CMD_COMP)) ret = -EIO; @@ -1185,22 +1174,6 @@ static const struct mtd_ooblayout_ops denali_ooblayout_ops = { .free = denali_ooblayout_free, }; -/* initialize driver data structures */ -static void denali_drv_init(struct denali_nand_info *denali) -{ - /* - * the completion object will be used to notify - * the callee that the interrupt is done - */ - init_completion(&denali->complete); - - /* - * the spinlock will be used to synchronize the ISR with any - * element that might be access shared data (interrupt status) - */ - spin_lock_init(&denali->irq_lock); -} - static int denali_multidev_fixup(struct denali_nand_info *denali) { struct nand_chip *chip = &denali->nand; @@ -1260,11 +1233,12 @@ int denali_init(struct denali_nand_info *denali) mtd->dev.parent = denali->dev; denali_hw_init(denali); - denali_drv_init(denali); + + init_completion(&denali->complete); + spin_lock_init(&denali->irq_lock); denali_clear_irq_all(denali); - /* Request IRQ after all the hardware initialization is finished */ ret = devm_request_irq(denali->dev, denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali); if (ret) { @@ -1282,7 +1256,6 @@ int denali_init(struct denali_nand_info *denali) if (!mtd->name) mtd->name = "denali-nand"; - /* register the driver with the NAND core subsystem */ chip->select_chip = denali_select_chip; chip->read_byte = denali_read_byte; chip->write_byte = denali_write_byte; @@ -1295,11 +1268,6 @@ int denali_init(struct denali_nand_info *denali) if (denali->clk_x_rate) chip->setup_data_interface = denali_setup_data_interface; - /* - * scan for NAND devices attached to the controller - * this is the first stage in a two step process to register - * with the nand subsystem - */ ret = nand_scan_ident(mtd, denali->max_banks, NULL); if (ret) goto disable_irq; @@ -1323,18 +1291,9 @@ int denali_init(struct denali_nand_info *denali) chip->buf_align = 16; } - /* - * second stage of the NAND scan - * this stage requires information regarding ECC and - * bad block management. - */ - chip->bbt_options |= NAND_BBT_USE_FLASH; chip->bbt_options |= NAND_BBT_NO_OOB; - chip->ecc.mode = NAND_ECC_HW_SYNDROME; - - /* no subpage writes on denali */ chip->options |= NAND_NO_SUBPAGE_WRITE; ret = denali_ecc_setup(mtd, chip, denali); @@ -1418,7 +1377,6 @@ disable_irq: } EXPORT_SYMBOL(denali_init); -/* driver exit point */ void denali_remove(struct denali_nand_info *denali) { struct mtd_info *mtd = nand_to_mtd(&denali->nand); diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 73aad3ac4577..f55ee10724c2 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -10,11 +10,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #ifndef __DENALI_H__ @@ -310,22 +305,19 @@ struct denali_nand_info { struct device *dev; void __iomem *reg; /* Register Interface */ void __iomem *host; /* Host Data/Command Interface */ - - /* elements used by ISR */ struct completion complete; - spinlock_t irq_lock; - uint32_t irq_mask; - uint32_t irq_status; + spinlock_t irq_lock; /* protect irq_mask and irq_status */ + u32 irq_mask; /* interrupts we are waiting for */ + u32 irq_status; /* interrupts that have happened */ int irq; - - void *buf; + void *buf; /* for syndrome layout conversion */ dma_addr_t dma_addr; - int dma_avail; + int dma_avail; /* can support DMA? */ int devs_per_cs; /* devices connected in parallel */ - int oob_skip_bytes; + int oob_skip_bytes; /* number of bytes reserved for BBM */ int max_banks; - unsigned int revision; - unsigned int caps; + unsigned int revision; /* IP revision */ + unsigned int caps; /* IP capability (or quirk) */ const struct nand_ecc_caps *ecc_caps; }; diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 01e0100ed2e7..cfd33e6ca77f 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -156,7 +156,6 @@ static struct platform_driver denali_dt_driver = { .of_match_table = denali_nand_dt_ids, }, }; - module_platform_driver(denali_dt_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index 7d5600b6d07c..57fb7ae31412 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -109,7 +109,6 @@ failed_remap_reg: return ret; } -/* driver exit point */ static void denali_pci_remove(struct pci_dev *dev) { struct denali_nand_info *denali = pci_get_drvdata(dev); @@ -125,5 +124,4 @@ static struct pci_driver denali_pci_driver = { .probe = denali_pci_probe, .remove = denali_pci_remove, }; - module_pci_driver(denali_pci_driver); -- cgit v1.2.3 From 5f2baae00542b2203e6d0fa77890f64ff741aaf3 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:46 +0900 Subject: mtd: nand: denali: use upper/lower_32_bits() macro for clean-up I used (uint64_t) cast to avoid "right shift count >= width of type" warning. provides nice helpers to cater to it. The code will be cleaner, and easier to understand. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 02ce310f44e4..e567ad9a4ef3 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -469,10 +469,10 @@ static void denali_setup_dma64(struct denali_nand_info *denali, 0x01002000 | (64 << 16) | (write << 8) | page_count); /* 2. set memory low address */ - denali_host_write(denali, mode, dma_addr); + denali_host_write(denali, mode, lower_32_bits(dma_addr)); /* 3. set memory high address */ - denali_host_write(denali, mode, (uint64_t)dma_addr >> 32); + denali_host_write(denali, mode, upper_32_bits(dma_addr)); } static void denali_setup_dma32(struct denali_nand_info *denali, -- cgit v1.2.3 From c70b5eb20a5dd9b3e4f68e041ad7526c94a2945e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:47 +0900 Subject: mtd: nand: denali: remove unneeded init of ECC_ENABLE register The ECC correction is properly enabled/disabled before the page read/write. There is no need to set up this at the beginning of the probe. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index e567ad9a4ef3..ee688e0042a8 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1101,8 +1101,6 @@ static void denali_hw_init(struct denali_nand_info *denali) iowrite32(CHIP_EN_DONT_CARE__FLAG, denali->reg + CHIP_ENABLE_DONT_CARE); iowrite32(0xffff, denali->reg + SPARE_AREA_MARKER); - - iowrite32(1, denali->reg + ECC_ENABLE); } int denali_calc_ecc_bytes(int step_size, int strength) -- cgit v1.2.3 From 29c4dd928735d5668b3108d350c30be7d0dc68fb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:48 +0900 Subject: mtd: nand: denali: support direct addressing mode The Denali NAND IP core decodes the lower 28 bits of the slave address to get the control information; bit[27:26]=mode, bit[25:24]=bank, etc. This means 256MB address range must be allocated for this IP. (Direct Addressing) For systems with address space limitation, the Denali IP provides an optional module that translates the addressing - address and data are latched by the registers in the translation module. (Indexed Addressing) The addressing mode can be selected when the delivered RTL is configured, and it can be read out from the FEATURES register. Most of SoC vendors would choose Indexed Addressing to save the address space, but Direct Addressing is possible as well, and it can be easily supported by adding ->host_{read,write} hooks. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 109 +++++++++++++++++++++++++++++----------------- drivers/mtd/nand/denali.h | 2 + 2 files changed, 70 insertions(+), 41 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index ee688e0042a8..7c24983012a1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -29,9 +29,9 @@ MODULE_LICENSE("GPL"); #define DENALI_NAND_NAME "denali-nand" -/* Host Data/Command Interface */ -#define DENALI_HOST_ADDR 0x00 -#define DENALI_HOST_DATA 0x10 +/* for Indexed Addressing */ +#define DENALI_INDEXED_CTRL 0x00 +#define DENALI_INDEXED_DATA 0x10 #define DENALI_MAP00 (0 << 26) /* direct access to buffer */ #define DENALI_MAP01 (1 << 26) /* read/write pages in PIO */ @@ -64,11 +64,39 @@ static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd) return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand); } -static void denali_host_write(struct denali_nand_info *denali, - uint32_t addr, uint32_t data) +/* + * Direct Addressing - the slave address forms the control information (command + * type, bank, block, and page address). The slave data is the actual data to + * be transferred. This mode requires 28 bits of address region allocated. + */ +static u32 denali_direct_read(struct denali_nand_info *denali, u32 addr) +{ + return ioread32(denali->host + addr); +} + +static void denali_direct_write(struct denali_nand_info *denali, u32 addr, + u32 data) +{ + iowrite32(data, denali->host + addr); +} + +/* + * Indexed Addressing - address translation module intervenes in passing the + * control information. This mode reduces the required address range. The + * control information and transferred data are latched by the registers in + * the translation module. + */ +static u32 denali_indexed_read(struct denali_nand_info *denali, u32 addr) { - iowrite32(addr, denali->host + DENALI_HOST_ADDR); - iowrite32(data, denali->host + DENALI_HOST_DATA); + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + return ioread32(denali->host + DENALI_INDEXED_DATA); +} + +static void denali_indexed_write(struct denali_nand_info *denali, u32 addr, + u32 data) +{ + iowrite32(addr, denali->host + DENALI_INDEXED_CTRL); + iowrite32(data, denali->host + DENALI_INDEXED_DATA); } /* @@ -205,52 +233,44 @@ static uint32_t denali_check_irq(struct denali_nand_info *denali) static void denali_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); int i; - iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), - denali->host + DENALI_HOST_ADDR); - for (i = 0; i < len; i++) - buf[i] = ioread32(denali->host + DENALI_HOST_DATA); + buf[i] = denali->host_read(denali, addr); } static void denali_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); int i; - iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), - denali->host + DENALI_HOST_ADDR); - for (i = 0; i < len; i++) - iowrite32(buf[i], denali->host + DENALI_HOST_DATA); + denali->host_write(denali, addr, buf[i]); } static void denali_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); uint16_t *buf16 = (uint16_t *)buf; int i; - iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), - denali->host + DENALI_HOST_ADDR); - for (i = 0; i < len / 2; i++) - buf16[i] = ioread32(denali->host + DENALI_HOST_DATA); + buf16[i] = denali->host_read(denali, addr); } static void denali_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { struct denali_nand_info *denali = mtd_to_denali(mtd); + u32 addr = DENALI_MAP11_DATA | DENALI_BANK(denali); const uint16_t *buf16 = (const uint16_t *)buf; int i; - iowrite32(DENALI_MAP11_DATA | DENALI_BANK(denali), - denali->host + DENALI_HOST_ADDR); - for (i = 0; i < len / 2; i++) - iowrite32(buf16[i], denali->host + DENALI_HOST_DATA); + denali->host_write(denali, addr, buf16[i]); } static uint8_t denali_read_byte(struct mtd_info *mtd) @@ -295,7 +315,7 @@ static void denali_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) if (ctrl & NAND_CTRL_CHANGE) denali_reset_irq(denali); - denali_host_write(denali, DENALI_BANK(denali) | type, dat); + denali->host_write(denali, DENALI_BANK(denali) | type, dat); } static int denali_dev_ready(struct mtd_info *mtd) @@ -465,14 +485,14 @@ static void denali_setup_dma64(struct denali_nand_info *denali, * 1. setup transfer type, interrupt when complete, * burst len = 64 bytes, the number of pages */ - denali_host_write(denali, mode, - 0x01002000 | (64 << 16) | (write << 8) | page_count); + denali->host_write(denali, mode, + 0x01002000 | (64 << 16) | (write << 8) | page_count); /* 2. set memory low address */ - denali_host_write(denali, mode, lower_32_bits(dma_addr)); + denali->host_write(denali, mode, lower_32_bits(dma_addr)); /* 3. set memory high address */ - denali_host_write(denali, mode, upper_32_bits(dma_addr)); + denali->host_write(denali, mode, upper_32_bits(dma_addr)); } static void denali_setup_dma32(struct denali_nand_info *denali, @@ -486,17 +506,17 @@ static void denali_setup_dma32(struct denali_nand_info *denali, /* DMA is a four step process */ /* 1. setup transfer type and # of pages */ - denali_host_write(denali, mode | page, - 0x2000 | (write << 8) | page_count); + denali->host_write(denali, mode | page, + 0x2000 | (write << 8) | page_count); /* 2. set memory high address bits 23:8 */ - denali_host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); + denali->host_write(denali, mode | ((dma_addr >> 16) << 8), 0x2200); /* 3. set memory low address bits 23:8 */ - denali_host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); + denali->host_write(denali, mode | ((dma_addr & 0xffff) << 8), 0x2300); /* 4. interrupt when complete, burst len = 64 bytes */ - denali_host_write(denali, mode | 0x14000, 0x2400); + denali->host_write(denali, mode | 0x14000, 0x2400); } static void denali_setup_dma(struct denali_nand_info *denali, @@ -511,7 +531,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, static int denali_pio_read(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw) { - uint32_t addr = DENALI_BANK(denali) | page; + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status, ecc_err_mask; int i; @@ -523,9 +543,8 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, denali_reset_irq(denali); - iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR); for (i = 0; i < size / 4; i++) - *buf32++ = ioread32(denali->host + DENALI_HOST_DATA); + *buf32++ = denali->host_read(denali, addr); irq_status = denali_wait_for_irq(denali, INTR__PAGE_XFER_INC); if (!(irq_status & INTR__PAGE_XFER_INC)) @@ -540,16 +559,15 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, static int denali_pio_write(struct denali_nand_info *denali, const void *buf, size_t size, int page, int raw) { - uint32_t addr = DENALI_BANK(denali) | page; + u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; const uint32_t *buf32 = (uint32_t *)buf; uint32_t irq_status; int i; denali_reset_irq(denali); - iowrite32(DENALI_MAP01 | addr, denali->host + DENALI_HOST_ADDR); for (i = 0; i < size / 4; i++) - iowrite32(*buf32++, denali->host + DENALI_HOST_DATA); + denali->host_write(denali, addr, *buf32++); irq_status = denali_wait_for_irq(denali, INTR__PROGRAM_COMP | INTR__PROGRAM_FAIL); @@ -935,8 +953,8 @@ static int denali_erase(struct mtd_info *mtd, int page) denali_reset_irq(denali); - denali_host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, - DENALI_ERASE); + denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page, + DENALI_ERASE); /* wait for erase to complete or failure to occur */ irq_status = denali_wait_for_irq(denali, @@ -1227,6 +1245,7 @@ int denali_init(struct denali_nand_info *denali) { struct nand_chip *chip = &denali->nand; struct mtd_info *mtd = nand_to_mtd(chip); + u32 features = ioread32(denali->reg + FEATURES); int ret; mtd->dev.parent = denali->dev; @@ -1262,6 +1281,14 @@ int denali_init(struct denali_nand_info *denali) chip->dev_ready = denali_dev_ready; chip->waitfunc = denali_waitfunc; + if (features & FEATURES__INDEX_ADDR) { + denali->host_read = denali_indexed_read; + denali->host_write = denali_indexed_write; + } else { + denali->host_read = denali_direct_read; + denali->host_write = denali_direct_write; + } + /* clk rate info is needed for setup_data_interface */ if (denali->clk_x_rate) chip->setup_data_interface = denali_setup_data_interface; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index f55ee10724c2..3aeb272d7a07 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -319,6 +319,8 @@ struct denali_nand_info { unsigned int revision; /* IP revision */ unsigned int caps; /* IP capability (or quirk) */ const struct nand_ecc_caps *ecc_caps; + u32 (*host_read)(struct denali_nand_info *denali, u32 addr); + void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) -- cgit v1.2.3 From 89dcb27b09fdcc8b585791815be07413d0487102 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 22 Sep 2017 12:46:49 +0900 Subject: mtd: nand: denali: change the setup_dma choice into hook The previous commit added some hooks into struct denali_nand_info, so here is one more for clean-up. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 15 +++++---------- drivers/mtd/nand/denali.h | 2 ++ 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 7c24983012a1..0b268ec88435 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -519,15 +519,6 @@ static void denali_setup_dma32(struct denali_nand_info *denali, denali->host_write(denali, mode | 0x14000, 0x2400); } -static void denali_setup_dma(struct denali_nand_info *denali, - dma_addr_t dma_addr, int page, int write) -{ - if (denali->caps & DENALI_CAP_DMA_64BIT) - denali_setup_dma64(denali, dma_addr, page, write); - else - denali_setup_dma32(denali, dma_addr, page, write); -} - static int denali_pio_read(struct denali_nand_info *denali, void *buf, size_t size, int page, int raw) { @@ -619,7 +610,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE); denali_reset_irq(denali); - denali_setup_dma(denali, dma_addr, page, write); + denali->setup_dma(denali, dma_addr, page, write); irq_status = denali_wait_for_irq(denali, irq_mask); if (!(irq_status & INTR__DMA_CMD_COMP)) @@ -1314,6 +1305,10 @@ int denali_init(struct denali_nand_info *denali) if (denali->dma_avail) { chip->options |= NAND_USE_BOUNCE_BUFFER; chip->buf_align = 16; + if (denali->caps & DENALI_CAP_DMA_64BIT) + denali->setup_dma = denali_setup_dma64; + else + denali->setup_dma = denali_setup_dma32; } chip->bbt_options |= NAND_BBT_USE_FLASH; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 3aeb272d7a07..2911066dacac 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -321,6 +321,8 @@ struct denali_nand_info { const struct nand_ecc_caps *ecc_caps; u32 (*host_read)(struct denali_nand_info *denali, u32 addr); void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); + void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, + int page, int write); }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) -- cgit v1.2.3 From f3d0d8d938b4d71be1f7fb003ca2ac9250b3be4d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 24 Sep 2017 19:39:12 +0200 Subject: mtd: nand: gpio: Convert to use GPIO descriptors There is exactly one board in the kernel that defines platform data for the GPIO NAND driver. Use the feature to provide a lookup table for the GPIOs in the board file so we can convert the driver as a whole to just use GPIO descriptors. After this we can cut the use of and use the GPIO descriptor management from alone to grab and use the GPIOs used in the driver. I also created a local struct device *dev in the probe() function because I was getting annoyed with all the &pdev->dev dereferencing. Cc: arm@kernel.org Cc: Mike Rapoport Cc: Frans Klaver Cc: Gerhard Sittig Cc: Jamie Iles Signed-off-by: Linus Walleij Reviewed-by: Marek Vasut Acked-by: Jamie Iles Acked-by: Olof Johansson Acked-by: Robert Jarzmik Signed-off-by: Boris Brezillon --- drivers/mtd/nand/gpio.c | 112 ++++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 55 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index fd3648952b5a..484f7fbc3f7d 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -31,12 +31,16 @@ #include #include #include -#include struct gpiomtd { void __iomem *io_sync; struct nand_chip nand_chip; struct gpio_nand_platdata plat; + struct gpio_desc *nce; /* Optional chip enable */ + struct gpio_desc *cle; + struct gpio_desc *ale; + struct gpio_desc *rdy; + struct gpio_desc *nwp; /* Optional write protection */ }; static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd) @@ -78,11 +82,10 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) gpio_nand_dosync(gpiomtd); if (ctrl & NAND_CTRL_CHANGE) { - if (gpio_is_valid(gpiomtd->plat.gpio_nce)) - gpio_set_value(gpiomtd->plat.gpio_nce, - !(ctrl & NAND_NCE)); - gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE)); - gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE)); + if (gpiomtd->nce) + gpiod_set_value(gpiomtd->nce, !(ctrl & NAND_NCE)); + gpiod_set_value(gpiomtd->cle, !!(ctrl & NAND_CLE)); + gpiod_set_value(gpiomtd->ale, !!(ctrl & NAND_ALE)); gpio_nand_dosync(gpiomtd); } if (cmd == NAND_CMD_NONE) @@ -96,7 +99,7 @@ static int gpio_nand_devready(struct mtd_info *mtd) { struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); - return gpio_get_value(gpiomtd->plat.gpio_rdy); + return gpiod_get_value(gpiomtd->rdy); } #ifdef CONFIG_OF @@ -123,12 +126,6 @@ static int gpio_nand_get_config_of(const struct device *dev, } } - plat->gpio_rdy = of_get_gpio(dev->of_node, 0); - plat->gpio_nce = of_get_gpio(dev->of_node, 1); - plat->gpio_ale = of_get_gpio(dev->of_node, 2); - plat->gpio_cle = of_get_gpio(dev->of_node, 3); - plat->gpio_nwp = of_get_gpio(dev->of_node, 4); - if (!of_property_read_u32(dev->of_node, "chip-delay", &val)) plat->chip_delay = val; @@ -201,10 +198,11 @@ static int gpio_nand_remove(struct platform_device *pdev) nand_release(nand_to_mtd(&gpiomtd->nand_chip)); - if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) - gpio_set_value(gpiomtd->plat.gpio_nwp, 0); - if (gpio_is_valid(gpiomtd->plat.gpio_nce)) - gpio_set_value(gpiomtd->plat.gpio_nce, 1); + /* Enable write protection and disable the chip */ + if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) + gpiod_set_value(gpiomtd->nwp, 0); + if (gpiomtd->nce && !IS_ERR(gpiomtd->nce)) + gpiod_set_value(gpiomtd->nce, 0); return 0; } @@ -215,66 +213,66 @@ static int gpio_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct resource *res; + struct device *dev = &pdev->dev; int ret = 0; - if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev)) + if (!dev->of_node && !dev_get_platdata(dev)) return -EINVAL; - gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL); + gpiomtd = devm_kzalloc(dev, sizeof(*gpiomtd), GFP_KERNEL); if (!gpiomtd) return -ENOMEM; chip = &gpiomtd->nand_chip; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); + chip->IO_ADDR_R = devm_ioremap_resource(dev, res); if (IS_ERR(chip->IO_ADDR_R)) return PTR_ERR(chip->IO_ADDR_R); res = gpio_nand_get_io_sync(pdev); if (res) { - gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res); + gpiomtd->io_sync = devm_ioremap_resource(dev, res); if (IS_ERR(gpiomtd->io_sync)) return PTR_ERR(gpiomtd->io_sync); } - ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat); + ret = gpio_nand_get_config(dev, &gpiomtd->plat); if (ret) return ret; - if (gpio_is_valid(gpiomtd->plat.gpio_nce)) { - ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, - "NAND NCE"); - if (ret) - return ret; - gpio_direction_output(gpiomtd->plat.gpio_nce, 1); + /* Just enable the chip */ + gpiomtd->nce = devm_gpiod_get_optional(dev, "nce", GPIOD_OUT_HIGH); + if (IS_ERR(gpiomtd->nce)) + return PTR_ERR(gpiomtd->nce); + + /* We disable write protection once we know probe() will succeed */ + gpiomtd->nwp = devm_gpiod_get_optional(dev, "nwp", GPIOD_OUT_LOW); + if (IS_ERR(gpiomtd->nwp)) { + ret = PTR_ERR(gpiomtd->nwp); + goto out_ce; } - if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { - ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp, - "NAND NWP"); - if (ret) - return ret; + gpiomtd->nwp = devm_gpiod_get(dev, "ale", GPIOD_OUT_LOW); + if (IS_ERR(gpiomtd->nwp)) { + ret = PTR_ERR(gpiomtd->nwp); + goto out_ce; } - ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE"); - if (ret) - return ret; - gpio_direction_output(gpiomtd->plat.gpio_ale, 0); + gpiomtd->cle = devm_gpiod_get(dev, "cle", GPIOD_OUT_LOW); + if (IS_ERR(gpiomtd->cle)) { + ret = PTR_ERR(gpiomtd->cle); + goto out_ce; + } - ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE"); - if (ret) - return ret; - gpio_direction_output(gpiomtd->plat.gpio_cle, 0); - - if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { - ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy, - "NAND RDY"); - if (ret) - return ret; - gpio_direction_input(gpiomtd->plat.gpio_rdy); - chip->dev_ready = gpio_nand_devready; + gpiomtd->rdy = devm_gpiod_get_optional(dev, "rdy", GPIOD_IN); + if (IS_ERR(gpiomtd->rdy)) { + ret = PTR_ERR(gpiomtd->rdy); + goto out_ce; } + /* Using RDY pin */ + if (gpiomtd->rdy) + chip->dev_ready = gpio_nand_devready; nand_set_flash_node(chip, pdev->dev.of_node); chip->IO_ADDR_W = chip->IO_ADDR_R; @@ -285,12 +283,13 @@ static int gpio_nand_probe(struct platform_device *pdev) chip->cmd_ctrl = gpio_nand_cmd_ctrl; mtd = nand_to_mtd(chip); - mtd->dev.parent = &pdev->dev; + mtd->dev.parent = dev; platform_set_drvdata(pdev, gpiomtd); - if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) - gpio_direction_output(gpiomtd->plat.gpio_nwp, 1); + /* Disable write protection, if wired up */ + if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) + gpiod_direction_output(gpiomtd->nwp, 1); ret = nand_scan(mtd, 1); if (ret) @@ -305,8 +304,11 @@ static int gpio_nand_probe(struct platform_device *pdev) return 0; err_wp: - if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) - gpio_set_value(gpiomtd->plat.gpio_nwp, 0); + if (gpiomtd->nwp && !IS_ERR(gpiomtd->nwp)) + gpiod_set_value(gpiomtd->nwp, 0); +out_ce: + if (gpiomtd->nce && !IS_ERR(gpiomtd->nce)) + gpiod_set_value(gpiomtd->nce, 0); return ret; } -- cgit v1.2.3 From 8c4cdce8b1ab044a2ee1d86d5a086f67e32b3c10 Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 25 Sep 2017 13:21:25 +0530 Subject: mtd: nand: qcom: add command elements in BAM transaction All the QPIC register read/write through BAM DMA requires command descriptor which contains the array of command elements. Reviewed-by: Archit Taneja Signed-off-by: Abhishek Sahu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/qcom_nandc.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 3baddfc997d1..3d1d506d3d18 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -22,6 +22,7 @@ #include #include #include +#include /* NANDc reg offsets */ #define NAND_FLASH_CMD 0x00 @@ -199,6 +200,7 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ */ #define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg)) +#define QPIC_PER_CW_CMD_ELEMENTS 32 #define QPIC_PER_CW_CMD_SGL 32 #define QPIC_PER_CW_DATA_SGL 8 @@ -221,8 +223,13 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ /* * This data type corresponds to the BAM transaction which will be used for all * NAND transfers. + * @bam_ce - the array of BAM command elements * @cmd_sgl - sgl for NAND BAM command pipe * @data_sgl - sgl for NAND BAM consumer/producer pipe + * @bam_ce_pos - the index in bam_ce which is available for next sgl + * @bam_ce_start - the index in bam_ce which marks the start position ce + * for current sgl. It will be used for size calculation + * for current sgl * @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. @@ -231,8 +238,11 @@ nandc_set_reg(nandc, NAND_READ_LOCATION_##reg, \ * @rx_sgl_start - start index in data sgl for rx. */ struct bam_transaction { + struct bam_cmd_element *bam_ce; struct scatterlist *cmd_sgl; struct scatterlist *data_sgl; + u32 bam_ce_pos; + u32 bam_ce_start; u32 cmd_sgl_pos; u32 cmd_sgl_start; u32 tx_sgl_pos; @@ -462,7 +472,8 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) bam_txn_size = sizeof(*bam_txn) + num_cw * - ((sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL) + + ((sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS) + + (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); @@ -472,6 +483,10 @@ alloc_bam_transaction(struct qcom_nand_controller *nandc) bam_txn = bam_txn_buf; bam_txn_buf += sizeof(*bam_txn); + bam_txn->bam_ce = bam_txn_buf; + bam_txn_buf += + sizeof(*bam_txn->bam_ce) * QPIC_PER_CW_CMD_ELEMENTS * num_cw; + bam_txn->cmd_sgl = bam_txn_buf; bam_txn_buf += sizeof(*bam_txn->cmd_sgl) * QPIC_PER_CW_CMD_SGL * num_cw; @@ -489,6 +504,8 @@ static void clear_bam_transaction(struct qcom_nand_controller *nandc) if (!nandc->props->is_bam) return; + bam_txn->bam_ce_pos = 0; + bam_txn->bam_ce_start = 0; bam_txn->cmd_sgl_pos = 0; bam_txn->cmd_sgl_start = 0; bam_txn->tx_sgl_pos = 0; -- cgit v1.2.3 From 8d6b6d7e135e9bbfc923d34a45cb0e72695e63ed Mon Sep 17 00:00:00 2001 From: Abhishek Sahu Date: Mon, 25 Sep 2017 13:21:26 +0530 Subject: mtd: nand: qcom: support for command descriptor formation 1. Add the function for command descriptor preparation which will be used only by BAM DMA and it will form the DMA descriptors containing command elements 2. DMA_PREP_CMD flag should be used for forming command DMA descript