This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335X NADN 写入速度优化

Other Parts Discussed in Thread: AM3354

各位大侠:

大家好,我在自制的AM335X板子上运行linux3.2,该板子用AM3354 cpu,基于SDK6.0,uboot为2013版,linux kernel版本为3.2.0
   有个问题,nand的写入速度太慢了.uboot下,写入60MB的文件系统,花了80秒钟.写入速度才几百KB.在linux系统下,最快的写入速度也才1.4MB/s,慢的时候 只有1.1MB/S,  (用1个76M的文件,多次通过FTP上传到开发板,并 sync到flash的测试结果).     nand型号:micron:MT29F2G08ABAGA

之前读取速度也很慢,后台通过打入预取和DMA补丁(我将添加预取补丁贴上来)后,算正常(波动也有点大). 但是这个写入速度感觉有点不正常!

Index: u-boot/arch/arm/include/asm/arch-am33xx/mem.h
===================================================================
--- u-boot/arch/arm/include/asm/arch-am33xx/mem.h	(revision 3348)
+++ u-boot/arch/arm/include/asm/arch-am33xx/mem.h	(revision 3349)
@@ -29,7 +29,7 @@
 
 #ifndef _MEM_H_
 #define _MEM_H_
-
+#include "asm/arch-omap3/omap3-regs.h"
 /*
  * GPMC settings -
  * Definitions is as per the following format
@@ -53,6 +53,58 @@
 #define GPMC_SIZE_32M		0xE
 #define GPMC_SIZE_16M		0xF
 
+
+/* Note: GPMC Clock = Core Clock M4 / 2 == 100 MHz, d.h. alles in n*10ns */
+/* Note: RDcycle und WrCycle >= 4 bei Verwendung der BCH ECC (Kap. 7.1.3.3.12.3.2.1)
+ *                 U-Boot          Linux */                    
+#define _CSROFF     4         /* 44ns */    
+#define _CSWOFF     4         /* 44ns */
+#define _ADON       0         /* 6ns */
+#define _ADROFF     4         /* 34ns */
+#define _ADWOFF     4         /* 44ns */
+#define _OEON       1         /* 0ns */
+#define _OEOFF      3         /* 54ns */
+#define _WEON       1         /* 0ns */
+#define _WEOFF      3         /* 40ns */
+#define _RDCY       4         /* 82ns */
+#define _WRCY       4         /* 82ns */
+#define _RDACC      4         /* 64ns */
+#define _CSHIGH     6         /* 0ns */     /* 100ns tADL! 60ns tWHR! */
+#define _WBURST     0         /* 0ns */
+#define _WRACC      4         /* 40ns */
+#define _BTURN      9         /* ??? */     /* 100ns tRHW */
+
+/* Info zur Prefetch-Engine:
+ * =========================
+ *  GPMC_PREFETCH_CONFIG1[27] ENABLEOPTIMIZEDACCESS = 1 (to remove _CSHIGH)
+ *  GPMC_PREFETCH_CONFIG1[30-28] CYCLEOPTIMIZATION  = 0 (Zugriff kann nicht weiter verkuerzt werden)
+ */
+
+/* CONFIG1: Type of Device, Type of Access */
+
+#ifdef CONFIG_POLARIS_PREFETCH
+#define M_NAND_GPMC_CONFIG1 ( GPMCFCLKDIVIDER(0) | 0 /* TIMEPARAGRANULARITY */ | 0 /* MUXADDDATA */ | \
+    DEVICETYPE_NAND | DEVICESIZE_16BIT | WAITPINSELECT(0) | WAITMONITORINGTIME(0) | \
+	0 /* WAITWRITEMONITORING */ | 0 /* WAITREADMONITORING */ | ATTACHEDDEVICEPAGELENGTH(0) | \
+	CLKACTIVATIONTIME(0) | 0 /* WRITETYPE */ | 0 /* WRITEMULTIPLE */ | 0 /* READTYPE */ | \
+	0 /* READMULTIPLE */ | 0 /* WRAPBURST */ )
+/* CONFIG2: Chip Select */        
+#define M_NAND_GPMC_CONFIG2 (CSWROFFTIME(_CSWOFF) | CSRDOFFTIME(_CSROFF) | CSONTIME(0) | 0 /* CSEXTRADELAY */ )
+/* CONFIG3: ADV/ALE */
+#define M_NAND_GPMC_CONFIG3 ( ADVWROFFTIME(_ADWOFF) | ADVRDOFFTIME(_ADROFF) | 0 /* ADVEXTRADELAY */ | ADVONTIME(_ADON) )
+/* CONFIG4: WE/OE */
+#define M_NAND_GPMC_CONFIG4 ( WEOFFTIME(_WEOFF) | 0 /* WEEXTRADELAY */ | WEONTIME(_WEON) | \
+	OEOFFTIME(_OEOFF) | 0 /* OEEXTRADELAY */ | OEONTIME(_OEON) )
+/* CONFIG5: Cycle Timing */
+#define M_NAND_GPMC_CONFIG5 ( PAGEBURSTACCESSTIME(0) | RDACCESSTIME(_RDACC) | WRCYCLETIME(_WRCY) | RDCYCLETIME(_RDCY) )
+/* CONFIG6: Rest of the Pack */
+#define M_NAND_GPMC_CONFIG6 ( WRACCESSTIME(_WRACC) | WRDATAONADMUXBUS(_WBURST) | CYCLE2CYCLEDELAY(_CSHIGH) | \
+	CYCLE2CYCLESAMECSEN | 0 /* CYCLE2CYCLEDIFFCSEN */ | BUSTURNAROUND(_BTURN) )
+/* CONFIG7: Address Mapping */
+#define M_NAND_GPMC_CONFIG7	MASKADDRESS(0x00) | CSVALID | BASEADDRESS(0x0)
+
+#else
+
 #ifdef CONFIG_POLARIS_NAND_16
 /* jfm 16-bit and half-speed for 16-bit S2 and 16-bit EVM */
 /* #define M_NAND_GPMC_CONFIG1	0x00001810 */
@@ -70,6 +122,8 @@
 #define M_NAND_GPMC_CONFIG6	0x16000f80
 #define M_NAND_GPMC_CONFIG7	0x00000008
 
+#endif
+
 /* NOR chip on NOR module for Beaglebone */
 #define STNOR_GPMC_CONFIG1	0x00001200
 #define STNOR_GPMC_CONFIG2	0x00101000
Index: u-boot/arch/arm/include/asm/arch-am33xx/cpu.h
===================================================================
--- u-boot/arch/arm/include/asm/arch-am33xx/cpu.h	(revision 3348)
+++ u-boot/arch/arm/include/asm/arch-am33xx/cpu.h	(revision 3349)
@@ -96,7 +96,11 @@
 	u32 status;		/* 0x54 */
 	u8 res5[0x8];		/* 0x58 */
 	struct gpmc_cs cs[8];	/* 0x60, 0x90, .. */
-	u8 res6[0x14];		/* 0x1E0 */
+    u32 pref_config1;       /* 0x1E0 */
+    u32 pref_config2;       /* 0x1E4 */
+    u8 res6[0x4];           /* 0x1E8 */
+    u32 pref_control;       /* 0x1EC */
+    u32 pref_status;        /* 0x1F0 */
 	u32 ecc_config;		/* 0x1F4 */
 	u32 ecc_control;	/* 0x1F8 */
 	u32 ecc_size_config;	/* 0x1FC */
Index: u-boot/arch/arm/cpu/armv7/am33xx/mem.c
===================================================================
--- u-boot/arch/arm/cpu/armv7/am33xx/mem.c	(revision 3348)
+++ u-boot/arch/arm/cpu/armv7/am33xx/mem.c	(revision 3349)
@@ -42,7 +42,8 @@
 	M_NAND_GPMC_CONFIG3,
 	M_NAND_GPMC_CONFIG4,
 	M_NAND_GPMC_CONFIG5,
-	M_NAND_GPMC_CONFIG6, 0
+	M_NAND_GPMC_CONFIG6, 
+	M_NAND_GPMC_CONFIG7, 
 };
 #endif
 
@@ -72,9 +73,7 @@
 	writel(gpmc_config[3], &cs->config4);
 	writel(gpmc_config[4], &cs->config5);
 	writel(gpmc_config[5], &cs->config6);
-	/* Enable the config */
-	writel((((size & 0xF) << 8) | ((base >> 24) & 0x3F) |
-		(1 << 6)), &cs->config7);
+        writel(gpmc_config[6] | CSVALID, &cs->config7);
 	sdelay(2000);
 }
 
@@ -113,8 +112,8 @@
 #ifdef CONFIG_CMD_NAND
 	gpmc_config = gpmc_m_nand;
 
-	base = PISMO1_NAND_BASE;
-	size = PISMO1_NAND_SIZE;
+    base = 0; // PISMO1_NAND_BASE;
+    size = 0; //PISMO1_NAND_SIZE;
 	enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[0], base, size);
 #endif
 
Index: u-boot/boards.cfg
===================================================================
--- u-boot/boards.cfg	(revision 3348)
+++ u-boot/boards.cfg	(revision 3349)
@@ -230,10 +230,10 @@
 integratorap_cm946es         arm         arm946es    integrator          armltd         -               integratorap:CM946ES
 integratorcp_cm946es         arm         arm946es    integrator          armltd         -               integratorcp:CM946ES
 ca9x4_ct_vxp                 arm         armv7       vexpress            armltd
-am335x_evm                   arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS
-am335x_evm_nand16            arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_NAND_16
-am335x_evm_prodtest          arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_PRODTEST
-am335x_evm_prodtest_nand16   arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_PRODTEST,POLARIS_NAND_16
+am335x_evm                   arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_PREFETCH
+am335x_evm_nand16            arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_NAND_16,POLARIS_PREFETCH
+am335x_evm_prodtest          arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_PRODTEST,POLARIS_PREFETCH
+am335x_evm_prodtest_nand16   arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,POLARIS,POLARIS_PRODTEST,POLARIS_NAND_16,POLARIS_PREFETCH
 am335x_evm_nor               arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,NOR
 am335x_evm_norboot           arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,NOR,NOR_BOOT
 am335x_evm_spiboot           arm         armv7       am335x              ti             am33xx      am335x_evm:SERIAL1,CONS_INDEX=1,SPI_BOOT
Index: u-boot/drivers/mtd/nand/nand_spl_simple.c
===================================================================
--- u-boot/drivers/mtd/nand/nand_spl_simple.c	(revision 3348)
+++ u-boot/drivers/mtd/nand/nand_spl_simple.c	(revision 3349)
@@ -59,14 +59,24 @@
 		       NAND_CTRL_ALE); /* A[28:25] */
 #endif
 	/* Latch in address */
-	this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+    this->cmd_ctrl(&mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
+    if (cmd == NAND_CMD_RNDOUT) {
+        /* no wait necessary */
+        return 0;
+    }
 
 	/*
 	 * Wait a while for the data to be ready
 	 */
-	while (!this->dev_ready(&mtd))
-		;
+    ndelay(100);
+    if (!this->dev_ready) {
+        udelay(this->chip_delay);
+        return;
+    }
 
+    while(!this->dev_ready(&mtd))
+            ;
+
 	return 0;
 }
 #else
Index: u-boot/drivers/mtd/nand/omap_gpmc.c
===================================================================
--- u-boot/drivers/mtd/nand/omap_gpmc.c	(revision 3348)
+++ u-boot/drivers/mtd/nand/omap_gpmc.c	(revision 3349)
@@ -266,6 +266,168 @@
 	.nibbles = ECC_BCH8_NIBBLES
 };
 
+#define PREFETCH_FIFOTHRESHOLD_MAX      0x40
+#define PREFETCH_FIFOTHRESHOLD(val)     ((val) << 8)
+
+#define PREFETCH_ENABLEOPTIMIZEDACCESS	 (0x1 << 27)
+
+#define GPMC_PREFETCH_STATUS_FIFO_CNT(val)      (((val) >> 24) & 0x7F)
+#define GPMC_PREFETCH_STATUS_COUNT(val) ((val) & 0x00003fff)
+
+#define CS_NUM_SHIFT            24
+#define ENABLE_PREFETCH         (0x1 << 7)
+//#define DMA_MPU_MODE            2
+//#define OMAP_NAND_TIMEOUT_MS    5000
+
+//#define PRINT_REG(x)
+#define PRINT_REG(x) printf("+++ %.15s (0x%08x)=0x%08x\n", #x, &gpmc_cfg->x, readl(&gpmc_cfg->x))
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+
+#define FIFO_IOADDR 0x100000  // Prefetch IO addr
+
+
+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: cs (chip select) number
+ * @fifo_th: fifo threshold to be used for read/ write
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+static inline void gpmc_prefetch_enable(int cs, int fifo_th, unsigned int u32_count, int is_write)
+{
+        writel(u32_count, &gpmc_cfg->pref_config2);
+
+        /* Set the prefetch read / post write and enable the engine.
+         * Set which cs is has requested for.
+         */
+        uint32_t val = (cs << CS_NUM_SHIFT) |
+            PREFETCH_ENABLEOPTIMIZEDACCESS |
+            PREFETCH_FIFOTHRESHOLD(fifo_th) |
+            ENABLE_PREFETCH |
+            (0x1 & is_write);
+        writel(val, &gpmc_cfg->pref_config1);
+
+                /*  Start the prefetch engine */
+        writel(0x1, &gpmc_cfg->pref_control);
+}
+
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+static inline void gpmc_prefetch_reset(void)
+{
+        /* Stop the PFPW engine */
+    writel(0x0, &gpmc_cfg->pref_control);
+
+        /* Reset/disable the PFPW engine */
+    writel(0x0, &gpmc_cfg->pref_config1);
+}
+
+
+/**
+ * read_buf_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 read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+    // Note: FIFOTHRESHOLDSTATUS is not working for MAX=40H
+    // Note: FIFO threshold not needed here
+    gpmc_prefetch_enable(cs, PREFETCH_FIFOTHRESHOLD_MAX / 2, len, 0);
+
+    do {
+        // Get number of bytes waiting in the FIFO
+        uint32_t read_bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(readl(&gpmc_cfg->pref_status));
+        // Alignment of Destination Buffer
+        while (read_bytes && ((unsigned int)buf & 3)) {
+			
+            *buf++ = readb(FIFO_IOADDR);
+            read_bytes--;
+            len--;
+        }
+        // Use maximum word size (32bit) inside this loop, because speed is limited by
+        // GPMC bus arbitration with a maximum transfer rate of 3.000.000/sec.
+        len -= read_bytes & ~3;
+        while (read_bytes >= 4) {
+            *((uint32_t*)buf) = readl(FIFO_IOADDR);
+            buf += 4;
+            read_bytes -= 4;
+        }
+        // Transfer the last (non-aligned) bytes only at the last iteration,
+        // to maintain full speed up to the end of the transfer.
+        if (read_bytes == len) {
+            while (read_bytes) {
+                *buf++ = readb(FIFO_IOADDR);
+                read_bytes--;
+            }
+            len = 0;
+        }
+    } while (len > 0);
+    gpmc_prefetch_reset();
+}
+
+#ifndef CONFIG_SPL_BUILD
+
+/**
+ * write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void write_buf_pref(struct mtd_info *mtd, const u_char *buf, int len)
+{
+    /*  configure and start prefetch transfer */
+    gpmc_prefetch_enable(cs, PREFETCH_FIFOTHRESHOLD_MAX / 2, len, 1);
+
+    while (len) {
+        // Get number of free bytes in the FIFO
+        uint32_t write_bytes = GPMC_PREFETCH_STATUS_FIFO_CNT(readl(&gpmc_cfg->pref_status));
+
+        // don't write more bytes than requested
+        if (write_bytes > len)
+            write_bytes = len;
+
+        // Alignment of Source Buffer
+        while (write_bytes && ((unsigned int)buf & 3)) {
+            writeb(*buf++, FIFO_IOADDR);
+            write_bytes--;
+            len--;
+        }
+
+        // Use maximum word size (32bit) inside this loop, because speed is limited by
+        // GPMC bus arbitration with a maximum transfer rate of 3.000.000/sec.
+        len -= write_bytes & ~3;
+        while (write_bytes >= 4) {
+            writel(*((uint32_t*)buf), FIFO_IOADDR);
+            buf += 4;
+            write_bytes -= 4;
+        }
+
+        // Transfer the last (non-aligned) bytes only at the last iteration,
+        // to maintain full speed up to the end of the transfer.
+        if (write_bytes == len) {
+            while (write_bytes) {
+                writeb(*buf++, FIFO_IOADDR);
+                write_bytes--;
+            }
+            len = 0;
+        }
+    }
+
+    /* wait for data to flushed-out before reset the prefetch */
+    while (GPMC_PREFETCH_STATUS_COUNT(readl(&gpmc_cfg->pref_status))) {
+        cpu_relax();
+    }
+
+   /* disable and stop the PFPW engine */
+   gpmc_prefetch_reset();
+}
+#endif
+
+
 /*
  * omap_read_bch8_result - Read BCH result for BCH8 level
  *
@@ -765,13 +927,15 @@
 #endif
 #endif
 
-#ifdef CONFIG_SPL_BUILD
+#ifdef CONFIG_POLARIS_PREFETCH
 	if (nand->options & NAND_BUSWIDTH_16)
-		nand->read_buf = nand_read_buf16;
+        nand->read_buf = read_buf_pref;
 	else
-		nand->read_buf = nand_read_buf;
-	nand->dev_ready = omap_spl_dev_ready;
+        nand->read_buf = read_buf_pref;
 #endif
+#ifdef CONFIG_SPL_BUILD
+    nand->dev_ready = omap_spl_dev_ready;
+#endif
 
 	return 0;
 }