各位大侠:
大家好,我在自制的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;
}