aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/omap2.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/omap2.c')
-rw-r--r--drivers/mtd/nand/omap2.c161
1 files changed, 152 insertions, 9 deletions
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}