aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
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 /drivers/mtd/nand
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>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/Kconfig8
-rw-r--r--drivers/mtd/nand/omap2.c161
2 files changed, 160 insertions, 9 deletions
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}