📄 tffsarch.c
字号:
} }}/*-----------------------------------------------------------------------* * * * t f f s _ d m a _ r e l e a s e * * * * Release all previously allocated DMA resources (channel, intermediate * * DMA buffer etc.). For OMAP1610 (H2) board. * * * *-----------------------------------------------------------------------*/static void tffs_dma_release(void){ /* if previously was allocated, release DMA channel */ if (tffsInfo.channel == 0) { omap_free_dma (dma_regs); dma_regs = NULL; tffsInfo.channel = -1; } /* if previously was allocated, release intermediate DMA buffer */ if (tffsInfo.dma_buf_vptr != NULL) {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) consistent_free (tffsInfo.dma_buf_vptr, PAGE_SIZE, tffsInfo.dma_buf_paddr);#else dma_free_coherent (NULL, PAGE_SIZE, tffsInfo.dma_buf_vptr, tffsInfo.dma_buf_paddr);#endif tffsInfo.dma_buf_vptr = NULL; }}/*-----------------------------------------------------------------------* * * * _ _ d m a s w _ b r e a d * * * * Transfer data from DiskOnChip's I/O reguster to RAM buffer. * * Example implementation For Texas Instruments OMAP1610 H2 board. * * * * Parameters: * * off offset of DiskOnChip's I/O register from the base * * of DiskOnChip window * * vbuf virtual address of RAM buffer * * bytes bytes to transfer * * * *-----------------------------------------------------------------------*/staticvoid __dmasw_bread ( int off, void * vbuf, unsigned int bytes ){ register u32 tmp; register int waiting; profiling[2]++; /* Channel Source/Destination Parameters. * Specify 16-bit port width, EMIFS source, allow source packing, * 4-words burst allowed for source, EMIFF destination. allow * destination packing, 4-words burst allowed for destination. */ dma_regs->csdp = (BURST_4 << 14) | /* dest.: use 4-word burst */ DCSDP_DST_PACK | /* pack dest. */ (PORT_EMIFF << 9) | /* dest. is EMIFF (RAM) */ (BURST_4 << 7) | /* source: use 4-word burst */ DCSDP_SRC_PACK | /* pack source */ (PORT_EMIFS << 2) | /* source is EMIFS (DiskOnChip) */ DATA_TYPE_S16; /* 16-bit data path */ /* Channel Control Register. * Specify no synchronization, no OMAP 3.0/3.1 compatibility, no * frame synchronization, high priority, constant source address, * post-increment destination address. */ dma_regs->ccr = (AMODE_POST_INC << 14) | /* dest (RAM): post-increment */ (AMODE_CONST << 12) | /* source (DiskOnChip) : const addr. */ DCCR_N31COMP | /* no OMAP 3.0/3.1 compatibility */ DCCR_PRIO; /* high priority */ /* Channel Frame Number Register. * We assume that frame consists of single element, and element * consists of single 16-bit word. */ dma_regs->cfn = (bytes / sizeof(u16)); /* Channel Source Start Address Registers. This would be DiskOnChip's * I/O register which is located at offset 'off' from the DiskOnChip's * base address as specified by tffs_addr[0]). */ tmp = tffs_addr[0] + off; dma_regs->cssa_u = (tmp >> 16); dma_regs->cssa_l = (tmp & 0xffff); /* Channel Destination Start Address Registers */ if (tffs_dma_mode & 4) /* do DMA transfer directly into 'vbuf' */ { if (virt_addr_valid((unsigned long)vbuf)) /* 'vbuf' is in low memory */ { tmp = __pa (vbuf); } else /* 'vbuf' is in high memory */ { char * k_vbuf = (char *) page_address(vmalloc_to_page(vbuf)) + ((unsigned long)vbuf & (PAGE_SIZE - 1)); tmp = __pa (k_vbuf); } /* write (if dirty) and purge contents of 'vbuf' from CPU cache(s) */#if 1 /* D-cache only. Possible options: * flush_dcache_range((unsigned long)vbuf, (unsigned long)(vbuf + bytes)); ARM/PPC * consistent_sync(vbuf, bytes, PCI_DMA_BIDIRECTIONAL); ARM/PPC * dma_cache_wback_inv((unsigned long)vbuf, (unsigned long)bytes); MIPS/PPC/SH/x86 */ flush_dcache_range ((unsigned long)vbuf, (unsigned long)(vbuf + bytes));#else /* both D- and I-caches */ cpu_cache_clean_invalidate_range ((unsigned long)vbuf, (unsigned long)(vbuf + bytes), 1);#endif } else /* transfer into intermediate DMA buffer */ { tmp = tffsInfo.dma_buf_paddr; } dma_regs->cdsa_u = (tmp >> 16); dma_regs->cdsa_l = (tmp & 0xffff); /* start DMA channel */ dma_regs->ccr |= DCCR_EN; /* wait for DMA transfer to finish */ for (waiting = 100000; waiting > 0; waiting--) /* hope this is long enough ... */ { if (((tmp = dma_regs->ccr) & DCCR_EN) == 0) { /* read Channel Status Register to clear it */ if (((tmp = dma_regs->csr) & DCSR_ERROR) == 0) { /* DMA transfer completed, move data from the intermediate DMA * buffer to the destination buffer (in case it was used). */ if ((tffs_dma_mode & 4) == 0) memcpy (vbuf, tffsInfo.dma_buf_vptr, bytes); } else /* andrayk June 13 2006: DMA transfer failed, find way to let MTD know this */ { PrintkError ("Bus error, DMA transfer failed"); } return; } } PrintkError ("DMA transfer timed out");}/*-----------------------------------------------------------------------* * * * _ _ d m a s w _ b w r i t e * * * * Transfer data from RAM buffer to DiskOnChip's I/O reguster. * * Example implementation For Texas Instruments OMAP1610 H2 board. * * * * Parameters: * * off offset of DiskOnChip's I/O register from the base * * of DiskOnChip window * * vbuf virtual address of RAM buffer * * bytes bytes to transfer * * * *-----------------------------------------------------------------------*/staticvoid __dmasw_bwrite ( int off, void * vbuf, unsigned int bytes ){ register u32 tmp; register int waiting; profiling[3]++; /* Channel Source/Destination Parameters. * Specify 16-bit port width, EMIFF source, allow source packing, * 4-words burst allowed for source, EMIFS destination. allow * destination packing, 4-words burst allowed for destination. */ dma_regs->csdp = (BURST_4 << 14) | /* dest.: use 4-word burst */ DCSDP_DST_PACK | /* pack dest. */ (PORT_EMIFS << 9) | /* dest. is EMIFS (DiskOnChip) */ (BURST_4 << 7) | /* source: use 4-word burt */ DCSDP_SRC_PACK | /* pack source */ (PORT_EMIFF << 2) | /* source is EMIFF (RAM) */ DATA_TYPE_S16; /* 16-bit data path */ /* Channel Control Register. * Specify no synchronization, no OMAP 3.0/3.1 compatibility, no * frame synchronization, high priority, constant dest. address, * post-increment source address. */ dma_regs->ccr = (AMODE_CONST << 14) | /* dest. (DiskOnChip): const addr. */ (AMODE_POST_INC << 12) | /* source (RAM): post-increment */ DCCR_N31COMP | /* no OMAP 3.1/3.0 compatibility */ DCCR_PRIO; /* high priority */ /* Channel Frame Number Register. * We assume that frame consists of single elemnt, and element consists * of single 16-bit word. */ dma_regs->cfn = (bytes / sizeof(u16)); /* Channel Source Start Address Registers */ if (tffs_dma_mode & 4) /* do DMA transfer directly from 'vbuf' */ { /* Write (if dirty) contents of 'vbuf' from CPU D-cache to RAM. * Possible options: * clean_dcache_range((unsigned long)vbuf, (unsigned long)(vbuf + bytes)); ARM/PPC * consistent_sync(vbuf, bytes, PCI_DMA_TODEVICE); ARM/PPC * dma_cache_wback((unsigned long)vbuf, (unsigned long)bytes); MIPS/PPC/SH/x86 */ clean_dcache_range ((unsigned long)vbuf, (unsigned long)(vbuf + bytes)); if (virt_addr_valid((unsigned long)vbuf)) /* 'vbuf' is in low memory */ { tmp = __pa (vbuf); } else /* 'vbuf' is in high memory */ { char * k_vbuf = (char *) page_address(vmalloc_to_page(vbuf)) + ((unsigned long)vbuf & (PAGE_SIZE - 1)); tmp = __pa (k_vbuf); } } else /* use intermediate DMA buffer */ { /* move data from RAM buffer to the intermediate DMA buffer */ memcpy (tffsInfo.dma_buf_vptr, vbuf, bytes); tmp = tffsInfo.dma_buf_paddr; } dma_regs->cssa_u = (tmp >> 16); dma_regs->cssa_l = (tmp & 0xffff); /* Channel Destination Start Address Regist.This would be DiskOnChip's * I/O register which is located at offset 'off' from the DiskOnChip's * base address as specified by tffs_addr[0]). */ tmp = tffs_addr[0] + off; dma_regs->cdsa_u = (tmp >> 16); dma_regs->cdsa_l = (tmp & 0xffff); /* start DMA channel */ dma_regs->ccr |= DCCR_EN; /* poll DMA channel's status register for end of DMA transfer */ for (waiting = 100000; waiting > 0; waiting--) /* hope this is long enough ... */ { if (((tmp = dma_regs->ccr) & DCCR_EN) == 0) { if ((tmp = dma_regs->csr) & DCSR_ERROR) /* andrayk June 14 2006: DMA transfer failed, find way to let MTD know this */ { PrintkError ("Bus error, DMA transfer failed"); } return; } } PrintkError ("DMA transfer timed out");}#elif defined(CONFIG_ARCH_OMAP24XX)/*_____________________________________________________________________________ | | | | | Texas Instruments OMAP-2420 (H4) board | | | |____________________________________________________________________________| */# include <asm/arch/hardware.h># include <asm/arch/dma.h>/* # include <asm/arch/pm_prcm.h> */ /* conflicts with <asm/arch/hardware.h> */# include <asm/arch/gpio.h># include <asm/arch/mux.h>/* Routine blk_dma_inv_range_harvard() (arch/arm/mm/blockops.c) appears * to be buggy: it seems to constantly shoot past the end of the address * range [vbuf..vbuf+bytes] by 32 bytes. It also appears to write some * bogus data into this RAM address range while invalidating it in D-cache. */# define OMAP2420_DCACHE_BUG_WORKAROUND# ifndef OMAP_DMA4_CCR_EN# define OMAP_DMA4_CCR_EN (1 << 7)# endif# define GPMC_CONFIG1_CS2 0xC0 /* phys. addr. 0x6800A0C0 */# define GPMC_CONFIG2_CS2 (GPMC_CONFIG1_CS2 + 0x4) /* phys. addr. 0x6800A0C4 */# define GPMC_CONFIG3_CS2 (GPMC_CONFIG1_CS2 + 0x8) /* phys. addr. 0x6800A0C8 */# define GPMC_CONFIG4_CS2 (GPMC_CONFIG1_CS2 + 0xC) /* phys. addr. 0x6800A0CC */# define GPMC_CONFIG5_CS2 (GPMC_CONFIG1_CS2 + 0x10) /* phys. addr. 0x6800A0D0 */# define GPMC_CONFIG6_CS2 (GPMC_CONFIG1_CS2 + 0x14) /* phys. addr. 0x6800A0D4 */# define GPMC_CONFIG7_CS2 (GPMC_CONFIG1_CS2 + 0x18) /* phys. addr. 0x6800A0D8 *//* layout of DMA channel's registers */typedef struct { volatile u32 ccr; /* Channel Control Register */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -