From ce3fefc1f27a68c450bfb37b4794a28e90115929 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 27 Nov 2013 07:37:42 -0600 Subject: SAMA5 NAND: Fix some DMA related issues --- nuttx/arch/arm/src/sama5/sam_memories.c | 32 +++++++-- nuttx/arch/arm/src/sama5/sam_nand.c | 122 ++++++++++++++++++++++++++------ nuttx/configs/sama5d3x-ek/README.txt | 30 +++++++- 3 files changed, 156 insertions(+), 28 deletions(-) (limited to 'nuttx') diff --git a/nuttx/arch/arm/src/sama5/sam_memories.c b/nuttx/arch/arm/src/sama5/sam_memories.c index 833ef0991..6e1b38f7a 100644 --- a/nuttx/arch/arm/src/sama5/sam_memories.c +++ b/nuttx/arch/arm/src/sama5/sam_memories.c @@ -211,7 +211,8 @@ static inline uintptr_t sdram_physramaddr(uintptr_t virtramaddr) * * Description: * Given the virtual address of an NFC SRAM memory location, return the - * physical address of that location + * physical address of that location. If NFC SRAM is not being used by + * the NAND logic, then it may be used a general purpose SRAM. * ****************************************************************************/ @@ -465,10 +466,12 @@ static inline uintptr_t sdram_virtramaddr(uintptr_t physramaddr) * * Description: * Given the physical address of an NFC SRAM memory location, return the - * virtual address of that location + * virtual address of that location. If NFC SRAM is not being used by + * the NAND logic, then it may be used a general purpose SRAM. * ****************************************************************************/ +#ifndef CONFIG_SAMA5_HAVE_NAND static inline uintptr_t nfcsram_virtramaddr(uintptr_t physramaddr) { #if SAM_NFCSRAM_PSECTION != SAM_NFCSRAM_VSECTION @@ -489,6 +492,7 @@ static inline uintptr_t nfcsram_virtramaddr(uintptr_t physramaddr) #endif } +#endif /**************************************************************************** * Name: udphsram_virtramaddr @@ -691,6 +695,18 @@ uintptr_t sam_physregaddr(uintptr_t virtregaddr) return sysc_physregaddr(virtregaddr); } + /* Check for NFCS SRAM. If NFC SRAM is being used by the NAND logic, + * then it will be treated as peripheral space. + */ + +#ifdef CONFIG_SAMA5_HAVE_NAND + if (virtregaddr >= SAM_NFCSRAM_VSECTION && + virtregaddr < (SAM_NFCSRAM_VSECTION + SAM_NFCSRAM_SIZE)) + { + return nfcsram_physramaddr(virtregaddr); + } +#endif + /* We will not get here unless we are called with an invalid register * address */ @@ -731,13 +747,17 @@ uintptr_t sam_physramaddr(uintptr_t virtramaddr) } #endif - /* Check for NFCS SRAM. */ + /* Check for NFCS SRAM. If NFC SRAM is not being used by the NAND logic, + * then it may be used a general purpose SRAM. + */ +#ifndef CONFIG_SAMA5_HAVE_NAND if (virtramaddr >= SAM_NFCSRAM_VSECTION && virtramaddr < (SAM_NFCSRAM_VSECTION + SAM_NFCSRAM_SIZE)) { return nfcsram_physramaddr(virtramaddr); } +#endif /* Check for UDPH SRAM. */ @@ -835,13 +855,17 @@ uintptr_t sam_virtramaddr(uintptr_t physramaddr) } #endif - /* Check for NFCS SRAM. */ + /* Check for NFCS SRAM. If NFC SRAM is not being used by the NAND logic, + * then it may be used a general purpose SRAM. + */ +#ifndef CONFIG_SAMA5_HAVE_NAND if (physramaddr >= SAM_NFCSRAM_PSECTION && physramaddr < (SAM_NFCSRAM_PSECTION + SAM_NFCSRAM_SIZE)) { return nfcsram_virtramaddr(physramaddr); } +#endif /* Check for UDPH SRAM. */ diff --git a/nuttx/arch/arm/src/sama5/sam_nand.c b/nuttx/arch/arm/src/sama5/sam_nand.c index f39418026..dc7492712 100644 --- a/nuttx/arch/arm/src/sama5/sam_nand.c +++ b/nuttx/arch/arm/src/sama5/sam_nand.c @@ -107,7 +107,7 @@ /* DMA Configuration */ -#define DMA_FLAGS8 \ +#define NFCSRAM_DMA_FLAGS8 \ DMACH_FLAG_FIFOCFG_LARGEST | \ (((0x3f) << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF0 | \ DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHINCREMENT | \ @@ -116,7 +116,15 @@ DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMINCREMENT | \ DMACH_FLAG_MEMCHUNKSIZE_1) -#define DMA_FLAGS16 \ +#define NAND_DMA_FLAGS8 \ + DMACH_FLAG_FIFOCFG_LARGEST | \ + (((0x3f) << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF0 | \ + DMACH_FLAG_PERIPHWIDTH_8BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \ + ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \ + DMACH_FLAG_MEMWIDTH_8BITS | DMACH_FLAG_MEMINCREMENT | \ + DMACH_FLAG_MEMCHUNKSIZE_1) + +#define NFCSRAM_DMA_FLAGS16 \ DMACH_FLAG_FIFOCFG_LARGEST | \ (((0x3f) << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF0 | \ DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_PERIPHINCREMENT | \ @@ -125,6 +133,14 @@ DMACH_FLAG_MEMWIDTH_16BITS | DMACH_FLAG_MEMINCREMENT | \ DMACH_FLAG_MEMCHUNKSIZE_1) +#define NAND_DMA_FLAGS16 \ + DMACH_FLAG_FIFOCFG_LARGEST | \ + (((0x3f) << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF0 | \ + DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \ + ((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \ + DMACH_FLAG_MEMWIDTH_16BITS | DMACH_FLAG_MEMINCREMENT | \ + DMACH_FLAG_MEMCHUNKSIZE_1) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -170,9 +186,11 @@ static int hsmc_interrupt(int irq, void *context); static int nand_wait_dma(struct sam_nandcs_s *priv); static void nand_dmacallback(DMA_HANDLE handle, void *arg, int result); static int nand_dma_read(struct sam_nandcs_s *priv, - uintptr_t vsrc, uintptr_t vdest, size_t nbytes); + uintptr_t vsrc, uintptr_t vdest, size_t nbytes, + uint32_t dmaflags); static int nand_dma_write(struct sam_nandcs_s *priv, - uintptr_t vsrc, uintptr_t vdest, size_t nbytes) + uintptr_t vsrc, uintptr_t vdest, size_t nbytes, + uint32_t dmaflags) #endif /* Raw Data Transfer Helpers */ @@ -972,10 +990,11 @@ static void nand_dmacallback(DMA_HANDLE handle, void *arg, int result) * Transfer data to NAND from the provided buffer via DMA. * * Input Parameters: - * priv - Lower-half, private NAND FLASH device state - * vsrc - NAND data destination address. - * vdest - Buffer where data read from NAND will be returned. - * nbytes - The number of bytes to transfer + * priv - Lower-half, private NAND FLASH device state + * vsrc - NAND data destination address. + * vdest - Buffer where data read from NAND will be returned. + * nbytes - The number of bytes to transfer + * dmaflags - Describes the DMA configuration * * Returned Value * OK on success; a negated errno value on failure. @@ -984,7 +1003,8 @@ static void nand_dmacallback(DMA_HANDLE handle, void *arg, int result) #ifdef CONFIG_SAMA5_NAND_DMA static int nand_dma_read(struct sam_nandcs_s *priv, - uintptr_t vsrc, uintptr_t vdest, size_t nbytes) + uintptr_t vsrc, uintptr_t vdest, size_t nbytes, + uint32_t dmaflags) { uint32_t psrc; uint32_t pdest; @@ -1007,6 +1027,10 @@ static int nand_dma_read(struct sam_nandcs_s *priv, psrc = sam_physregaddr(vsrc); /* Source is NAND */ pdest = sam_physramaddr(vdest); /* Destination is normal memory */ + /* Configure the DMA: 8- vs 16-bit, NFC SRAM or NAND */ + + sam_dmaconfig(priv->dma, dmaflags); + /* Setup the Memory-to-Memory DMA. The semantics of the DMA module are * awkward here. We will treat the NAND (src) as the peripheral source * and memory as the destination. Internally, the DMA module will realize @@ -1046,10 +1070,11 @@ static int nand_dma_read(struct sam_nandcs_s *priv, * Transfer data to NAND from the provided buffer via DMA. * * Input Parameters: - * priv - Lower-half, private NAND FLASH device state - * vsrc - Buffer that provides the data for the write - * vdest - NAND data destination address - * nbytes - The number of bytes to transfer + * priv - Lower-half, private NAND FLASH device state + * vsrc - Buffer that provides the data for the write + * vdest - NAND data destination address + * nbytes - The number of bytes to transfer + * dmaflags - Describes the DMA configuration * * Returned Value * OK on success; a negated errno value on failure. @@ -1058,7 +1083,8 @@ static int nand_dma_read(struct sam_nandcs_s *priv, #ifdef CONFIG_SAMA5_NAND_DMA static int nand_dma_write(struct sam_nandcs_s *priv, - uintptr_t vsrc, uintptr_t vdest, size_t nbytes) + uintptr_t vsrc, uintptr_t vdest, size_t nbytes, + uint32_t dmaflags) { uint32_t psrc; uint32_t pdest; @@ -1077,6 +1103,10 @@ static int nand_dma_write(struct sam_nandcs_s *priv, psrc = sam_physramaddr(vsrc); /* Source is normal memory */ pdest = sam_physregaddr(vdest); /* Destination is NAND (or NAND host SRAM) */ + /* Configure the DMA: 8- vs 16-bit, NFC SRAM or NAND */ + + sam_dmaconfig(priv->dma, dmaflags); + /* Setup the Memory-to-Memory DMA. The semantics of the DMA module are * awkward here. We will treat the NAND (dest) as the peripheral destination * and memory as the source. Internally, the DMA module will realize taht @@ -1216,17 +1246,40 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram, uint8_t *buffer, size_t buflen) { uintptr_t src; +#ifdef CONFIG_SAMA5_NAND_DMA + uint32_t dmaflags; +#endif int buswidth; - /* Pick the data destination: The NFC SRAM or the NAND data address */ + /* Get the buswidth */ + + buswidth = nandmodel_getbuswidth(&priv->raw.model); + + /* Pick the data source: The NFC SRAM or the NAND data address */ if (nfcsram) { + /* Source is NFC SRAM */ + src = NFCSRAM_BASE; + +#ifdef CONFIG_SAMA5_NAND_DMA + /* Select NFC SRAM DMA */ + + dmaflags = (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8); +#endif } else { + /* Source is NFC NAND */ + src = priv->raw.dataaddr; + +#ifdef CONFIG_SAMA5_NAND_DMA + /* Select NAND DMA */ + + dmaflags = (buswidth == 16 ? NAND_DMA_FLAGS16 : NAND_DMA_FLAGS8); +#endif } #ifdef CONFIG_SAMA5_NAND_DMA @@ -1238,7 +1291,7 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram, { /* Transfer using DMA */ - return nand_dma_read(priv, src, (uintptr_t)buffer, buflen); + return nand_dma_read(priv, src, (uintptr_t)buffer, buflen, dmaflags); } else #endif @@ -1253,7 +1306,6 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram, { /* Check the data bus width of the NAND FLASH */ - buswidth = nandmodel_getbuswidth(&priv->raw.model); if (buswidth == 16) { return nand_smc_read16(src, buffer, buflen); @@ -1493,17 +1545,40 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram, uint8_t *buffer, size_t buflen, off_t offset) { uintptr_t dest; +#ifdef CONFIG_SAMA5_NAND_DMA + uint32_t dmaflags; +#endif int buswidth; - /* Pick the data source: The NFC SRAM or the NAND data address */ + /* Get the buswidth */ + + buswidth = nandmodel_getbuswidth(&priv->raw.model); + + /* Pick the data destination: The NFC SRAM or the NAND data address */ if (nfcsram) { + /* Destination is NFC SRAM */ + dest = NFCSRAM_BASE; + +#ifdef CONFIG_SAMA5_NAND_DMA + /* Select NFC SRAM DMA */ + + dmaflags = (buswidth == 16 ? NFCSRAM_DMA_FLAGS16 : NFCSRAM_DMA_FLAGS8); +#endif } else { + /* Destination is NFC NAND */ + dest = priv->raw.dataaddr; + +#ifdef CONFIG_SAMA5_NAND_DMA + /* Select NAND DMA */ + + dmaflags = (buswidth == 16 ? NAND_DMA_FLAGS16 : NAND_DMA_FLAGS8); +#endif } /* Apply the offset to the source address */ @@ -1519,7 +1594,7 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram, { /* Transfer using DMA */ - return nand_dma_write(priv, (uintptr_t)buffer, dest, buflen); + return nand_dma_write(priv, (uintptr_t)buffer, dest, buflen, dmaflags); } else #endif @@ -1534,7 +1609,6 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram, { /* Check the data bus width of the NAND FLASH */ - buswidth = nandmodel_getbuswidth(&priv->raw.model); if (buswidth == 16) { return nand_smc_write16(buffer, dest, buflen); @@ -2611,16 +2685,18 @@ struct mtd_dev_s *sam_nand_initialize(int cs) return NULL; } - /* Allocate a DMA channel for NAND transfers */ + /* Allocate a DMA channel for NAND transfers. The channels will be + * configured as needed on-the-fly + */ #ifdef CONFIG_SAMA5_NAND_DMA if (nandmodel_getbuswidth(&priv->raw.model) == 16) { - priv->dma = sam_dmachannel(NAND_DMAC, DMA_FLAGS16); + priv->dma = sam_dmachannel(NAND_DMAC, 0); } else { - priv->dma = sam_dmachannel(NAND_DMAC, DMA_FLAGS8); + priv->dma = sam_dmachannel(NAND_DMAC, 0); } if (!priv->dma) diff --git a/nuttx/configs/sama5d3x-ek/README.txt b/nuttx/configs/sama5d3x-ek/README.txt index 8c5516cb1..62d55d067 100644 --- a/nuttx/configs/sama5d3x-ek/README.txt +++ b/nuttx/configs/sama5d3x-ek/README.txt @@ -76,6 +76,8 @@ Contents - Serial FLASH - HSMCI Card Slots - USB Ports + - SDRAM Support + - NAND Support - AT24 Serial EEPROM - CAN Usage - SAMA5 ADC Support @@ -640,6 +642,28 @@ USB Ports ---- ----------- ------------------------------------------------------- PD28 OVCUR_USB Combined overrcurrent indication from port A and B +SDRAM Support +============= + In these configurations, .data and .bss are retained in ISRAM. SDRAM can + be initialized and included in the heap. Relevant configuration settings: + + System Type->ATSAMA5 Peripheral Support + CONFIG_SAMA5_MPDDRC=y : Enable the DDR controller + + System Type->External Memory Configuration + CONFIG_SAMA5_DDRCS=y : Tell the system that DRAM is at the DDR CS + CONFIG_SAMA5_DDRCS_SIZE=268435456 : 2Gb DRAM -> 256GB + CONFIG_SAMA5_DDRCS_LPDDR2=y : Its DDR2 + CONFIG_SAMA5_MT47H128M16RT=y : This is the type of DDR2 + + System Type->Heap Configuration + CONFIG_SAMA5_DDRCS_HEAP=y : Add the SDRAM to the heap + CONFIG_SAMA5_DDRCS_HEAP_OFFSET=0 + CONFIG_SAMA5_DDRCS_HEAP_SIZE=268435456 + + Memory Management + CONFIG_MM_REGIONS=2 : Two heap memory regions: ISRAM and SDRAM + NAND Support ============ NAND Support can be added to the the NSH configuration by modifying the @@ -670,7 +694,11 @@ NAND Support File Systems: CONFIG_FS_NXFFS=y : Enable the NXFFS file system - Defaults for all other NXFFS settings should be okay + Defaults for all other NXFFS settings should be okay. + + NOTE: NXFFS will require some significant buffering because of + the large size of the NAND flash blocks. You will also need + to enable SDRAM as described above. Board Selection CONFIG_SAMA5_NAND_AUTOMOUNT=y : Enable FS support on NAND -- cgit v1.2.3