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