From d5ce2b6592c49935462cba7317fa67fe8ee474ec Mon Sep 17 00:00:00 2001 From: Sukumar Ghorai Date: Fri, 28 Jan 2011 15:42:03 +0530 Subject: omap3630: nand: fix device size to work in polled mode zoom3 and 3630-sdp having the x16 nand device. This patch configure gpmc as x16 and select the currect function in driver for polled mode (without prefetch enable) transfer. Signed-off-by: Sukumar Ghorai Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-omap2/board-flash.c') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index fd38c05bb47..f6b72533c08 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -139,11 +139,13 @@ static struct omap_nand_platform_data board_nand_data = { }; void -__init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs) +__init board_nand_init(struct mtd_partition *nand_parts, + u8 nr_parts, u8 cs, int nand_type) { board_nand_data.cs = cs; board_nand_data.parts = nand_parts; - board_nand_data.nr_parts = nr_parts; + board_nand_data.nr_parts = nr_parts; + board_nand_data.devsize = nand_type; gpmc_nand_init(&board_nand_data); } @@ -194,7 +196,7 @@ unmap: * @return - void. */ void board_flash_init(struct flash_partitions partition_info[], - char chip_sel_board[][GPMC_CS_NUM]) + char chip_sel_board[][GPMC_CS_NUM], int nand_type) { u8 cs = 0; u8 norcs = GPMC_CS_NUM + 1; @@ -250,5 +252,5 @@ void board_flash_init(struct flash_partitions partition_info[], "in GPMC\n"); else board_nand_init(partition_info[2].parts, - partition_info[2].nr_parts, nandcs); + partition_info[2].nr_parts, nandcs, nand_type); } -- cgit v1.2.3-70-g09d2 From 4e070376165a9b7f245fada77645b81352c6ec78 Mon Sep 17 00:00:00 2001 From: Sukumar Ghorai Date: Fri, 28 Jan 2011 15:42:06 +0530 Subject: omap3: nand: prefetch in irq mode support This patch enable prefetch-irq mode for nand transfer(read, write) Signed-off-by: Vimal Singh Signed-off-by: Sukumar Ghorai Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 2 + arch/arm/plat-omap/include/plat/nand.h | 4 +- drivers/mtd/nand/omap2.c | 198 +++++++++++++++++++++++++++++++-- 3 files changed, 194 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-omap2/board-flash.c') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index f6b72533c08..19645095d59 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -147,6 +148,7 @@ __init board_nand_init(struct mtd_partition *nand_parts, board_nand_data.nr_parts = nr_parts; board_nand_data.devsize = nand_type; + board_nand_data.gpmc_irq = OMAP_GPMC_IRQ_BASE + cs; gpmc_nand_init(&board_nand_data); } #else diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index 78c0bdb98c1..ae5e0538303 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -13,7 +13,8 @@ enum nand_io { NAND_OMAP_PREFETCH_POLLED = 0, /* prefetch polled mode, default */ NAND_OMAP_POLLED, /* polled mode, without prefetch */ - NAND_OMAP_PREFETCH_DMA /* prefetch enabled sDMA mode */ + NAND_OMAP_PREFETCH_DMA, /* prefetch enabled sDMA mode */ + NAND_OMAP_PREFETCH_IRQ /* prefetch enabled irq mode */ }; struct omap_nand_platform_data { @@ -26,6 +27,7 @@ struct omap_nand_platform_data { int (*nand_setup)(void); int (*dev_ready)(struct omap_nand_platform_data *); int dma_channel; + int gpmc_irq; enum nand_io xfer_type; unsigned long phys_base; int devsize; diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 60bac8e6e9f..fbe84146717 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #define DRIVER_NAME "omap2-nand" +#define OMAP_NAND_TIMEOUT_MS 5000 #define NAND_Ecc_P1e (1 << 0) #define NAND_Ecc_P2e (1 << 1) @@ -108,6 +110,13 @@ struct omap_nand_info { unsigned long phys_base; struct completion comp; int dma_ch; + int gpmc_irq; + enum { + OMAP_NAND_IO_READ = 0, /* read */ + OMAP_NAND_IO_WRITE, /* write */ + } iomode; + u_char *buf; + int buf_len; }; /** @@ -267,9 +276,10 @@ static void omap_write_buf_pref(struct mtd_info *mtd, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - uint32_t pref_count = 0, w_count = 0; + uint32_t w_count = 0; int i = 0, ret = 0; u16 *p; + unsigned long tim, limit; /* take care of subpage writes */ if (len % 2 != 0) { @@ -295,9 +305,12 @@ static void omap_write_buf_pref(struct mtd_info *mtd, iowrite16(*p++, info->nand.IO_ADDR_W); } /* wait for data to flushed-out before reset the prefetch */ - do { - pref_count = gpmc_read_status(GPMC_PREFETCH_COUNT); - } while (pref_count); + tim = 0; + limit = (loops_per_jiffy * + msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); + while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + cpu_relax(); + /* disable and stop the PFPW engine */ gpmc_prefetch_reset(info->gpmc_cs); } @@ -326,11 +339,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); - uint32_t prefetch_status = 0; enum dma_data_direction dir = is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; dma_addr_t dma_addr; int ret; + unsigned long tim, limit; /* The fifo depth is 64 bytes. We have a sync at each frame and frame * length is 64 bytes. @@ -376,7 +389,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, /* configure and start prefetch transfer */ ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write); if (ret) - /* PFPW engine is busy, use cpu copy methode */ + /* PFPW engine is busy, use cpu copy method */ goto out_copy; init_completion(&info->comp); @@ -385,10 +398,11 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, /* setup and start DMA using dma_addr */ wait_for_completion(&info->comp); + tim = 0; + limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); + while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + cpu_relax(); - do { - prefetch_status = gpmc_read_status(GPMC_PREFETCH_COUNT); - } while (prefetch_status); /* disable and stop the PFPW engine */ gpmc_prefetch_reset(info->gpmc_cs); @@ -436,6 +450,155 @@ static void omap_write_buf_dma_pref(struct mtd_info *mtd, omap_nand_dma_transfer(mtd, (u_char *) buf, len, 0x1); } +/* + * omap_nand_irq - GMPC irq handler + * @this_irq: gpmc irq number + * @dev: omap_nand_info structure pointer is passed here + */ +static irqreturn_t omap_nand_irq(int this_irq, void *dev) +{ + struct omap_nand_info *info = (struct omap_nand_info *) dev; + u32 bytes; + u32 irq_stat; + + irq_stat = gpmc_read_status(GPMC_GET_IRQ_STATUS); + bytes = gpmc_read_status(GPMC_PREFETCH_FIFO_CNT); + bytes = bytes & 0xFFFC; /* io in multiple of 4 bytes */ + if (info->iomode == OMAP_NAND_IO_WRITE) { /* checks for write io */ + if (irq_stat & 0x2) + goto done; + + if (info->buf_len && (info->buf_len < bytes)) + bytes = info->buf_len; + else if (!info->buf_len) + bytes = 0; + iowrite32_rep(info->nand.IO_ADDR_W, + (u32 *)info->buf, bytes >> 2); + info->buf = info->buf + bytes; + info->buf_len -= bytes; + + } else { + ioread32_rep(info->nand.IO_ADDR_R, + (u32 *)info->buf, bytes >> 2); + info->buf = info->buf + bytes; + + if (irq_stat & 0x2) + goto done; + } + gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); + + return IRQ_HANDLED; + +done: + complete(&info->comp); + /* disable irq */ + gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, 0); + + /* clear status */ + gpmc_cs_configure(info->gpmc_cs, GPMC_SET_IRQ_STATUS, irq_stat); + + return IRQ_HANDLED; +} + +/* + * omap_read_buf_irq_pref - read data from NAND controller into buffer + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read + */ +static void omap_read_buf_irq_pref(struct mtd_info *mtd, u_char *buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + int ret = 0; + + if (len <= mtd->oobsize) { + omap_read_buf_pref(mtd, buf, len); + return; + } + + info->iomode = OMAP_NAND_IO_READ; + info->buf = buf; + init_completion(&info->comp); + + /* configure and start prefetch transfer */ + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0); + if (ret) + /* PFPW engine is busy, use cpu copy method */ + goto out_copy; + + info->buf_len = len; + /* enable irq */ + gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, + (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + /* waiting for read to complete */ + wait_for_completion(&info->comp); + + /* disable and stop the PFPW engine */ + gpmc_prefetch_reset(info->gpmc_cs); + return; + +out_copy: + if (info->nand.options & NAND_BUSWIDTH_16) + omap_read_buf16(mtd, buf, len); + else + omap_read_buf8(mtd, buf, len); +} + +/* + * omap_write_buf_irq_pref - write buffer to NAND controller + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write + */ +static void omap_write_buf_irq_pref(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct omap_nand_info *info = container_of(mtd, + struct omap_nand_info, mtd); + int ret = 0; + unsigned long tim, limit; + + if (len <= mtd->oobsize) { + omap_write_buf_pref(mtd, buf, len); + return; + } + + info->iomode = OMAP_NAND_IO_WRITE; + info->buf = (u_char *) buf; + init_completion(&info->comp); + + /* configure and start prefetch transfer */ + ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1); + if (ret) + /* PFPW engine is busy, use cpu copy method */ + goto out_copy; + + info->buf_len = len; + /* enable irq */ + gpmc_cs_configure(info->gpmc_cs, GPMC_ENABLE_IRQ, + (GPMC_IRQ_FIFOEVENTENABLE | GPMC_IRQ_COUNT_EVENT)); + + /* waiting for write to complete */ + wait_for_completion(&info->comp); + /* wait for data to flushed-out before reset the prefetch */ + tim = 0; + limit = (loops_per_jiffy * msecs_to_jiffies(OMAP_NAND_TIMEOUT_MS)); + while (gpmc_read_status(GPMC_PREFETCH_COUNT) && (tim++ < limit)) + cpu_relax(); + + /* disable and stop the PFPW engine */ + gpmc_prefetch_reset(info->gpmc_cs); + return; + +out_copy: + if (info->nand.options & NAND_BUSWIDTH_16) + omap_write_buf16(mtd, buf, len); + else + omap_write_buf8(mtd, buf, len); +} + /** * omap_verify_buf - Verify chip data against buffer * @mtd: MTD device structure @@ -846,6 +1009,20 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) } break; + case NAND_OMAP_PREFETCH_IRQ: + err = request_irq(pdata->gpmc_irq, + omap_nand_irq, IRQF_SHARED, "gpmc-nand", info); + if (err) { + dev_err(&pdev->dev, "requesting irq(%d) error:%d", + pdata->gpmc_irq, err); + goto out_release_mem_region; + } else { + info->gpmc_irq = pdata->gpmc_irq; + info->nand.read_buf = omap_read_buf_irq_pref; + info->nand.write_buf = omap_write_buf_irq_pref; + } + break; + default: dev_err(&pdev->dev, "xfer_type(%d) not supported!\n", pdata->xfer_type); @@ -911,6 +1088,9 @@ static int omap_nand_remove(struct platform_device *pdev) if (info->dma_ch != -1) omap_free_dma(info->dma_ch); + if (info->gpmc_irq) + free_irq(info->gpmc_irq, info); + /* Release NAND device, its internal structures and partitions */ nand_release(&info->mtd); iounmap(info->nand.IO_ADDR_R); -- cgit v1.2.3-70-g09d2 From f3d73f362d689a1d044e77964864f0a8ea0217f3 Mon Sep 17 00:00:00 2001 From: Sukumar Ghorai Date: Fri, 28 Jan 2011 15:42:08 +0530 Subject: omap3: nand: ecc layout select from board file This patch makes it possible to select sw or hw (different layout options) ecc scheme supported by omap nand driver. Signed-off-by: Vimal Singh Signed-off-by: Sukumar Ghorai Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 1 + arch/arm/plat-omap/include/plat/gpmc.h | 6 ++++++ arch/arm/plat-omap/include/plat/nand.h | 2 ++ drivers/mtd/nand/omap2.c | 26 +++++++++++--------------- 4 files changed, 20 insertions(+), 15 deletions(-) (limited to 'arch/arm/mach-omap2/board-flash.c') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index 19645095d59..a7681981201 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -148,6 +148,7 @@ __init board_nand_init(struct mtd_partition *nand_parts, board_nand_data.nr_parts = nr_parts; board_nand_data.devsize = nand_type; + board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_DEFAULT; board_nand_data.gpmc_irq = OMAP_GPMC_IRQ_BASE + cs; gpmc_nand_init(&board_nand_data); } diff --git a/arch/arm/plat-omap/include/plat/gpmc.h b/arch/arm/plat-omap/include/plat/gpmc.h index a2434639063..773351bc25a 100644 --- a/arch/arm/plat-omap/include/plat/gpmc.h +++ b/arch/arm/plat-omap/include/plat/gpmc.h @@ -86,6 +86,12 @@ #define PREFETCH_FIFOTHRESHOLD_MAX 0x40 #define PREFETCH_FIFOTHRESHOLD(val) ((val) << 8) +enum omap_ecc { + /* 1-bit ecc: stored at end of spare area */ + OMAP_ECC_HAMMING_CODE_DEFAULT = 0, /* Default, s/w method */ + OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */ +}; + /* * Note that all values in this struct are in nanoseconds except sync_clk * (which is in picoseconds), while the register values are in gpmc_fck cycles. diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index ae5e0538303..d86d1ecf006 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include #include enum nand_io { @@ -31,6 +32,7 @@ struct omap_nand_platform_data { enum nand_io xfer_type; unsigned long phys_base; int devsize; + enum omap_ecc ecc_opt; }; /* minimum size for IO mapping */ diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index f1648fd5924..6d4a42e3938 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -626,8 +626,6 @@ static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len) return 0; } -#ifdef CONFIG_MTD_NAND_OMAP_HWECC - /** * gen_true_ecc - This function will generate true ECC value * @ecc_buf: buffer to store ecc code @@ -847,8 +845,6 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode) gpmc_enable_hwecc(info->gpmc_cs, mode, dev_width, info->nand.ecc.size); } -#endif - /** * omap_wait - wait until the command is done * @mtd: MTD device structure @@ -1038,17 +1034,17 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) info->nand.verify_buf = omap_verify_buf; -#ifdef CONFIG_MTD_NAND_OMAP_HWECC - info->nand.ecc.bytes = 3; - info->nand.ecc.size = 512; - info->nand.ecc.calculate = omap_calculate_ecc; - info->nand.ecc.hwctl = omap_enable_hwecc; - info->nand.ecc.correct = omap_correct_data; - info->nand.ecc.mode = NAND_ECC_HW; - -#else - info->nand.ecc.mode = NAND_ECC_SOFT; -#endif + /* selsect the ecc type */ + if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT) + info->nand.ecc.mode = NAND_ECC_SOFT; + else if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) { + info->nand.ecc.bytes = 3; + info->nand.ecc.size = 512; + info->nand.ecc.calculate = omap_calculate_ecc; + info->nand.ecc.hwctl = omap_enable_hwecc; + info->nand.ecc.correct = omap_correct_data; + info->nand.ecc.mode = NAND_ECC_HW; + } /* DIP switches on some boards change between 8 and 16 bit * bus widths for flash. Try the other width if the first try fails. -- cgit v1.2.3-70-g09d2 From f69eefd18d5201cd512c862a4bd27b8e8febd20b Mon Sep 17 00:00:00 2001 From: Sanjeev Premi Date: Tue, 15 Feb 2011 10:57:31 +0000 Subject: omap3: fix minor typos This patch fixes typos that were remaining after the file and functions were renamed. Signed-off-by: Sanjeev Premi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-omap2/board-flash.c') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index fd38c05bb47..ce61200ae68 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -1,5 +1,5 @@ /* - * board-sdp-flash.c + * board-flash.c * Modified from mach-omap2/board-3430sdp-flash.c * * Copyright (C) 2009 Nokia Corporation @@ -189,7 +189,7 @@ unmap: } /** - * sdp3430_flash_init - Identify devices connected to GPMC and register. + * board_flash_init - Identify devices connected to GPMC and register. * * @return - void. */ -- cgit v1.2.3-70-g09d2 From adc5430b473db2842a96fcce1ffbd43049757d3b Mon Sep 17 00:00:00 2001 From: Sanjeev Premi Date: Tue, 15 Feb 2011 10:57:32 +0000 Subject: omap3: flash: use pr_err instead of printk Change all occurences of printf() to pr_err(). Includes minor formatting changes as result of this change. Signed-off-by: Sanjeev Premi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/board-flash.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'arch/arm/mach-omap2/board-flash.c') diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c index ce61200ae68..86d1020da15 100644 --- a/arch/arm/mach-omap2/board-flash.c +++ b/arch/arm/mach-omap2/board-flash.c @@ -73,11 +73,11 @@ __init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs) + FLASH_SIZE_SDPV1 - 1; } if (err < 0) { - printk(KERN_ERR "NOR: Can't request GPMC CS\n"); + pr_err("NOR: Can't request GPMC CS\n"); return; } if (platform_device_register(&board_nor_device) < 0) - printk(KERN_ERR "Unable to register NOR device\n"); + pr_err("Unable to register NOR device\n"); } #if defined(CONFIG_MTD_ONENAND_OMAP2) || \ @@ -208,7 +208,7 @@ void board_flash_init(struct flash_partitions partition_info[], */ idx = get_gpmc0_type(); if (idx >= MAX_SUPPORTED_GPMC_CONFIG) { - printk(KERN_ERR "%s: Invalid chip select: %d\n", __func__, cs); + pr_err("%s: Invalid chip select: %d\n", __func__, cs); return; } config_sel = (unsigned char *)(chip_sel_board[idx]); @@ -232,22 +232,19 @@ void board_flash_init(struct flash_partitions partition_info[], } if (norcs > GPMC_CS_NUM) - printk(KERN_INFO "NOR: Unable to find configuration " - "in GPMC\n"); + pr_err("NOR: Unable to find configuration in GPMC\n"); else board_nor_init(partition_info[0].parts, partition_info[0].nr_parts, norcs); if (onenandcs > GPMC_CS_NUM) - printk(KERN_INFO "OneNAND: Unable to find configuration " - "in GPMC\n"); + pr_err("OneNAND: Unable to find configuration in GPMC\n"); else board_onenand_init(partition_info[1].parts, partition_info[1].nr_parts, onenandcs); if (nandcs > GPMC_CS_NUM) - printk(KERN_INFO "NAND: Unable to find configuration " - "in GPMC\n"); + pr_err("NAND: Unable to find configuration in GPMC\n"); else board_nand_init(partition_info[2].parts, partition_info[2].nr_parts, nandcs); -- cgit v1.2.3-70-g09d2