aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvimal singh <vimalsingh@ti.com>2009-07-13 06:56:24 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-09-19 16:20:51 -0400
commit59e9c5ae17179fe561103fbe0808fac5976ca1bd (patch)
treecc1f155a2569d09ae5d1d232046bb188c6b38d4c
parent8bff82cbc30884fc52969608d090d874641e7196 (diff)
mtd: omap: add support for nand prefetch-read and post-write
This patch adds prefetch support to access nand flash in mpu mode. This patch also adds 8-bit nand support (omap_read/write_buf8). Prefetch can be used for both 8- and 16-bit devices. Signed-off-by: Vimal Singh <vimalsingh@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r--arch/arm/mach-omap2/gpmc.c63
-rw-r--r--arch/arm/plat-omap/include/mach/gpmc.h4
-rw-r--r--drivers/mtd/nand/Kconfig8
-rw-r--r--drivers/mtd/nand/omap2.c161
4 files changed, 226 insertions, 10 deletions
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index f91934b2b092..15876828db23 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -57,6 +57,11 @@
57#define GPMC_CHUNK_SHIFT 24 /* 16 MB */ 57#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
58#define GPMC_SECTION_SHIFT 28 /* 128 MB */ 58#define GPMC_SECTION_SHIFT 28 /* 128 MB */
59 59
60#define PREFETCH_FIFOTHRESHOLD (0x40 << 8)
61#define CS_NUM_SHIFT 24
62#define ENABLE_PREFETCH (0x1 << 7)
63#define DMA_MPU_MODE 2
64
60static struct resource gpmc_mem_root; 65static struct resource gpmc_mem_root;
61static struct resource gpmc_cs_mem[GPMC_CS_NUM]; 66static struct resource gpmc_cs_mem[GPMC_CS_NUM];
62static DEFINE_SPINLOCK(gpmc_mem_lock); 67static DEFINE_SPINLOCK(gpmc_mem_lock);
@@ -386,6 +391,63 @@ void gpmc_cs_free(int cs)
386} 391}
387EXPORT_SYMBOL(gpmc_cs_free); 392EXPORT_SYMBOL(gpmc_cs_free);
388 393
394/**
395 * gpmc_prefetch_enable - configures and starts prefetch transfer
396 * @cs: nand cs (chip select) number
397 * @dma_mode: dma mode enable (1) or disable (0)
398 * @u32_count: number of bytes to be transferred
399 * @is_write: prefetch read(0) or write post(1) mode
400 */
401int gpmc_prefetch_enable(int cs, int dma_mode,
402 unsigned int u32_count, int is_write)
403{
404 uint32_t prefetch_config1;
405
406 if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
407 /* Set the amount of bytes to be prefetched */
408 gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
409
410 /* Set dma/mpu mode, the prefetch read / post write and
411 * enable the engine. Set which cs is has requested for.
412 */
413 prefetch_config1 = ((cs << CS_NUM_SHIFT) |
414 PREFETCH_FIFOTHRESHOLD |
415 ENABLE_PREFETCH |
416 (dma_mode << DMA_MPU_MODE) |
417 (0x1 & is_write));
418 gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
419 } else {
420 return -EBUSY;
421 }
422 /* Start the prefetch engine */
423 gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
424
425 return 0;
426}
427EXPORT_SYMBOL(gpmc_prefetch_enable);
428
429/**
430 * gpmc_prefetch_reset - disables and stops the prefetch engine
431 */
432void gpmc_prefetch_reset(void)
433{
434 /* Stop the PFPW engine */
435 gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
436
437 /* Reset/disable the PFPW engine */
438 gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
439}
440EXPORT_SYMBOL(gpmc_prefetch_reset);
441
442/**
443 * gpmc_prefetch_status - reads prefetch status of engine
444 */
445int gpmc_prefetch_status(void)
446{
447 return gpmc_read_reg(GPMC_PREFETCH_STATUS);
448}
449EXPORT_SYMBOL(gpmc_prefetch_status);
450
389static void __init gpmc_mem_init(void) 451static void __init gpmc_mem_init(void)
390{ 452{
391 int cs; 453 int cs;
@@ -452,6 +514,5 @@ void __init gpmc_init(void)
452 l &= 0x03 << 3; 514 l &= 0x03 << 3;
453 l |= (0x02 << 3) | (1 << 0); 515 l |= (0x02 << 3) | (1 << 0);
454 gpmc_write_reg(GPMC_SYSCONFIG, l); 516 gpmc_write_reg(GPMC_SYSCONFIG, l);
455
456 gpmc_mem_init(); 517 gpmc_mem_init();
457} 518}
diff --git a/arch/arm/plat-omap/include/mach/gpmc.h b/arch/arm/plat-omap/include/mach/gpmc.h
index 921b16532ff5..9c99cda77ba6 100644
--- a/arch/arm/plat-omap/include/mach/gpmc.h
+++ b/arch/arm/plat-omap/include/mach/gpmc.h
@@ -103,6 +103,10 @@ extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
103extern void gpmc_cs_free(int cs); 103extern void gpmc_cs_free(int cs);
104extern int gpmc_cs_set_reserved(int cs, int reserved); 104extern int gpmc_cs_set_reserved(int cs, int reserved);
105extern int gpmc_cs_reserved(int cs); 105extern int gpmc_cs_reserved(int cs);
106extern int gpmc_prefetch_enable(int cs, int dma_mode,
107 unsigned int u32_count, int is_write);
108extern void gpmc_prefetch_reset(void);
109extern int gpmc_prefetch_status(void);
106extern void __init gpmc_init(void); 110extern void __init gpmc_init(void);
107 111
108#endif 112#endif
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 707d7ee495df..7dab79caed44 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -80,6 +80,14 @@ config MTD_NAND_OMAP2
80 help 80 help
81 Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. 81 Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
82 82
83config MTD_NAND_OMAP_PREFETCH
84 bool "GPMC prefetch support for NAND Flash device"
85 depends on MTD_NAND && MTD_NAND_OMAP2
86 default y
87 help
88 The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
89 to improve the performance.
90
83config MTD_NAND_TS7250 91config MTD_NAND_TS7250
84 tristate "NAND Flash device on TS-7250 board" 92 tristate "NAND Flash device on TS-7250 board"
85 depends on MACH_TS72XX 93 depends on MACH_TS72XX
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index ebd07e95b814..6736822c4751 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -112,6 +112,16 @@
112static const char *part_probes[] = { "cmdlinepart", NULL }; 112static const char *part_probes[] = { "cmdlinepart", NULL };
113#endif 113#endif
114 114
115#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH
116static int use_prefetch = 1;
117
118/* "modprobe ... use_prefetch=0" etc */
119module_param(use_prefetch, bool, 0);
120MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
121#else
122const int use_prefetch;
123#endif
124
115struct omap_nand_info { 125struct omap_nand_info {
116 struct nand_hw_control controller; 126 struct nand_hw_control controller;
117 struct omap_nand_platform_data *pdata; 127 struct omap_nand_platform_data *pdata;
@@ -124,6 +134,7 @@ struct omap_nand_info {
124 unsigned long phys_base; 134 unsigned long phys_base;
125 void __iomem *gpmc_cs_baseaddr; 135 void __iomem *gpmc_cs_baseaddr;
126 void __iomem *gpmc_baseaddr; 136 void __iomem *gpmc_baseaddr;
137 void __iomem *nand_pref_fifo_add;
127}; 138};
128 139
129/** 140/**
@@ -189,6 +200,38 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
189} 200}
190 201
191/** 202/**
203 * omap_read_buf8 - read data from NAND controller into buffer
204 * @mtd: MTD device structure
205 * @buf: buffer to store date
206 * @len: number of bytes to read
207 */
208static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
209{
210 struct nand_chip *nand = mtd->priv;
211
212 ioread8_rep(nand->IO_ADDR_R, buf, len);
213}
214
215/**
216 * omap_write_buf8 - write buffer to NAND controller
217 * @mtd: MTD device structure
218 * @buf: data buffer
219 * @len: number of bytes to write
220 */
221static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
222{
223 struct omap_nand_info *info = container_of(mtd,
224 struct omap_nand_info, mtd);
225 u_char *p = (u_char *)buf;
226
227 while (len--) {
228 iowrite8(*p++, info->nand.IO_ADDR_W);
229 while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
230 GPMC_STATUS) & GPMC_BUF_FULL));
231 }
232}
233
234/**
192 * omap_read_buf16 - read data from NAND controller into buffer 235 * omap_read_buf16 - read data from NAND controller into buffer
193 * @mtd: MTD device structure 236 * @mtd: MTD device structure
194 * @buf: buffer to store date 237 * @buf: buffer to store date
@@ -198,7 +241,7 @@ static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
198{ 241{
199 struct nand_chip *nand = mtd->priv; 242 struct nand_chip *nand = mtd->priv;
200 243
201 __raw_readsw(nand->IO_ADDR_R, buf, len / 2); 244 ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
202} 245}
203 246
204/** 247/**
@@ -217,13 +260,101 @@ static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
217 len >>= 1; 260 len >>= 1;
218 261
219 while (len--) { 262 while (len--) {
220 writew(*p++, info->nand.IO_ADDR_W); 263 iowrite16(*p++, info->nand.IO_ADDR_W);
221 264
222 while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr + 265 while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
223 GPMC_STATUS) & GPMC_BUF_FULL)) 266 GPMC_STATUS) & GPMC_BUF_FULL))
224 ; 267 ;
225 } 268 }
226} 269}
270
271/**
272 * omap_read_buf_pref - read data from NAND controller into buffer
273 * @mtd: MTD device structure
274 * @buf: buffer to store date
275 * @len: number of bytes to read
276 */
277static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
278{
279 struct omap_nand_info *info = container_of(mtd,
280 struct omap_nand_info, mtd);
281 uint32_t pfpw_status = 0, r_count = 0;
282 int ret = 0;
283 u32 *p = (u32 *)buf;
284
285 /* take care of subpage reads */
286 for (; len % 4 != 0; ) {
287 *buf++ = __raw_readb(info->nand.IO_ADDR_R);
288 len--;
289 }
290 p = (u32 *) buf;
291
292 /* configure and start prefetch transfer */
293 ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
294 if (ret) {
295 /* PFPW engine is busy, use cpu copy method */
296 if (info->nand.options & NAND_BUSWIDTH_16)
297 omap_read_buf16(mtd, buf, len);
298 else
299 omap_read_buf8(mtd, buf, len);
300 } else {
301 do {
302 pfpw_status = gpmc_prefetch_status();
303 r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
304 ioread32_rep(info->nand_pref_fifo_add, p, r_count);
305 p += r_count;
306 len -= r_count << 2;
307 } while (len);
308
309 /* disable and stop the PFPW engine */
310 gpmc_prefetch_reset();
311 }
312}
313
314/**
315 * omap_write_buf_pref - write buffer to NAND controller
316 * @mtd: MTD device structure
317 * @buf: data buffer
318 * @len: number of bytes to write
319 */
320static void omap_write_buf_pref(struct mtd_info *mtd,
321 const u_char *buf, int len)
322{
323 struct omap_nand_info *info = container_of(mtd,
324 struct omap_nand_info, mtd);
325 uint32_t pfpw_status = 0, w_count = 0;
326 int i = 0, ret = 0;
327 u16 *p = (u16 *) buf;
328
329 /* take care of subpage writes */
330 if (len % 2 != 0) {
331 writeb(*buf, info->nand.IO_ADDR_R);
332 p = (u16 *)(buf + 1);
333 len--;
334 }
335
336 /* configure and start prefetch transfer */
337 ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
338 if (ret) {
339 /* PFPW engine is busy, use cpu copy method */
340 if (info->nand.options & NAND_BUSWIDTH_16)
341 omap_write_buf16(mtd, buf, len);
342 else
343 omap_write_buf8(mtd, buf, len);
344 } else {
345 pfpw_status = gpmc_prefetch_status();
346 while (pfpw_status & 0x3FFF) {
347 w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
348 for (i = 0; (i < w_count) && len; i++, len -= 2)
349 iowrite16(*p++, info->nand_pref_fifo_add);
350 pfpw_status = gpmc_prefetch_status();
351 }
352
353 /* disable and stop the PFPW engine */
354 gpmc_prefetch_reset();
355 }
356}
357
227/** 358/**
228 * omap_verify_buf - Verify chip data against buffer 359 * omap_verify_buf - Verify chip data against buffer
229 * @mtd: MTD device structure 360 * @mtd: MTD device structure
@@ -658,17 +789,12 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
658 err = -ENOMEM; 789 err = -ENOMEM;
659 goto out_release_mem_region; 790 goto out_release_mem_region;
660 } 791 }
792
661 info->nand.controller = &info->controller; 793 info->nand.controller = &info->controller;
662 794
663 info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; 795 info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
664 info->nand.cmd_ctrl = omap_hwcontrol; 796 info->nand.cmd_ctrl = omap_hwcontrol;
665 797
666 /* REVISIT: only supports 16-bit NAND flash */
667
668 info->nand.read_buf = omap_read_buf16;
669 info->nand.write_buf = omap_write_buf16;
670 info->nand.verify_buf = omap_verify_buf;
671
672 /* 798 /*
673 * If RDY/BSY line is connected to OMAP then use the omap ready 799 * If RDY/BSY line is connected to OMAP then use the omap ready
674 * funcrtion and the generic nand_wait function which reads the status 800 * funcrtion and the generic nand_wait function which reads the status
@@ -689,6 +815,23 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
689 == 0x1000) 815 == 0x1000)
690 info->nand.options |= NAND_BUSWIDTH_16; 816 info->nand.options |= NAND_BUSWIDTH_16;
691 817
818 if (use_prefetch) {
819 /* copy the virtual address of nand base for fifo access */
820 info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
821
822 info->nand.read_buf = omap_read_buf_pref;
823 info->nand.write_buf = omap_write_buf_pref;
824 } else {
825 if (info->nand.options & NAND_BUSWIDTH_16) {
826 info->nand.read_buf = omap_read_buf16;
827 info->nand.write_buf = omap_write_buf16;
828 } else {
829 info->nand.read_buf = omap_read_buf8;
830 info->nand.write_buf = omap_write_buf8;
831 }
832 }
833 info->nand.verify_buf = omap_verify_buf;
834
692#ifdef CONFIG_MTD_NAND_OMAP_HWECC 835#ifdef CONFIG_MTD_NAND_OMAP_HWECC
693 info->nand.ecc.bytes = 3; 836 info->nand.ecc.bytes = 3;
694 info->nand.ecc.size = 512; 837 info->nand.ecc.size = 512;
@@ -746,7 +889,7 @@ static int omap_nand_remove(struct platform_device *pdev)
746 platform_set_drvdata(pdev, NULL); 889 platform_set_drvdata(pdev, NULL);
747 /* Release NAND device, its internal structures and partitions */ 890 /* Release NAND device, its internal structures and partitions */
748 nand_release(&info->mtd); 891 nand_release(&info->mtd);
749 iounmap(info->nand.IO_ADDR_R); 892 iounmap(info->nand_pref_fifo_add);
750 kfree(&info->mtd); 893 kfree(&info->mtd);
751 return 0; 894 return 0;
752} 895}