Here's the resubmitted patches for PPC4XX DMA improvements/fixes. If these are still mangled by my mailer then I'll resend them as attachments.
Colin. =============================================================== --- linux-2.6.10/arch/ppc/syslib/ppc4xx_dma.c 2004-12-24 21:35:40.000000000 +0000 +++ linux-current/arch/ppc/syslib/ppc4xx_dma.c 2005-01-19 15:34:30.000000000 +0000 @@ -512,6 +512,8 @@ ppc4xx_get_channel_config(unsigned int d return DMA_STATUS_BAD_CHANNEL; } + memcpy(p_dma_ch, &dma_channels[dmanr], sizeof (ppc_dma_ch_t)); + #if DCRN_POL > 0 polarity = mfdcr(DCRN_POL); #else @@ -604,6 +606,84 @@ ppc4xx_get_peripheral_width(unsigned int return (GET_DMA_PW(control)); } +/* + * Clears the channel status bits + */ +int +ppc4xx_clr_dma_status(unsigned int dmanr) +{ + if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) { + printk(KERN_ERR "ppc4xx_clr_dma_status: bad channel: %d\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } + mtdcr(DCRN_DMASR, ((u32)DMA_CH0_ERR | (u32)DMA_CS0 | (u32)DMA_TS0) >> dmanr); + return DMA_STATUS_GOOD; +} + +/* + * Enables the burst on the channel (BTEN bit in the control/count register) + * Note: + * For scatter/gather dma, this function MUST be called before the + * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the + * sgl list and used as each sgl element is added. + */ +int +ppc4xx_enable_burst(unsigned int dmanr) +{ + unsigned int ctc; + if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) { + printk(KERN_ERR "ppc4xx_enable_burst: bad channel: %d\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } + ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) | DMA_CTC_BTEN; + mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc); + return DMA_STATUS_GOOD; +} +/* + * Disables the burst on the channel (BTEN bit in the control/count register) + * Note: + * For scatter/gather dma, this function MUST be called before the + * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the + * sgl list and used as each sgl element is added. + */ +int +ppc4xx_disable_burst(unsigned int dmanr) +{ + unsigned int ctc; + if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) { + printk(KERN_ERR "ppc4xx_disable_burst: bad channel: %d\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } + ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BTEN; + mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc); + return DMA_STATUS_GOOD; +} +/* + * Sets the burst size (number of peripheral widths) for the channel + * (BSIZ bits in the control/count register)) + * must be one of: + * DMA_CTC_BSIZ_2 + * DMA_CTC_BSIZ_4 + * DMA_CTC_BSIZ_8 + * DMA_CTC_BSIZ_16 + * Note: + * For scatter/gather dma, this function MUST be called before the + * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the + * sgl list and used as each sgl element is added. + */ +int +ppc4xx_set_burst_size(unsigned int dmanr, unsigned int bsize) +{ + unsigned int ctc; + if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) { + printk(KERN_ERR "ppc4xx_set_burst_size: bad channel: %d\n", dmanr); + return DMA_STATUS_BAD_CHANNEL; + } + ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BSIZ_MSK; + ctc |= (bsize & DMA_CTC_BSIZ_MSK); + mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc); + return DMA_STATUS_GOOD; +} EXPORT_SYMBOL(ppc4xx_init_dma_channel); EXPORT_SYMBOL(ppc4xx_get_channel_config); @@ -622,3 +702,7 @@ EXPORT_SYMBOL(ppc4xx_get_dma_residue); EXPORT_SYMBOL(ppc4xx_enable_dma_interrupt); EXPORT_SYMBOL(ppc4xx_disable_dma_interrupt); EXPORT_SYMBOL(ppc4xx_get_dma_status); +EXPORT_SYMBOL(ppc4xx_clr_dma_status); +EXPORT_SYMBOL(ppc4xx_enable_burst); +EXPORT_SYMBOL(ppc4xx_disable_burst); +EXPORT_SYMBOL(ppc4xx_set_burst_size); =============================================================== --- linux-2.6.10/include/asm-ppc/ppc4xx_dma.h 2004-12-24 21:35:01.000000000 +0000 +++ linux-current/include/asm-ppc/ppc4xx_dma.h 2005-01-19 10:59:55.000000000 +0000 @@ -137,9 +137,10 @@ extern unsigned long DMA_MODE_WRITE, DMA #define DMA_TCE_ENABLE (1<<(8-DMA_CR_OFFSET)) #define SET_DMA_TCE(x) (((x)&0x1)<<(8-DMA_CR_OFFSET)) -#define DMA_DEC (1<<(2) /* Address Decrement */ +#define DMA_DEC (1<<(2)) /* Address Decrement */ #define SET_DMA_DEC(x) (((x)&0x1)<<2) #define GET_DMA_DEC(x) (((x)&DMA_DEC)>>2) + /* * Transfer Modes @@ -244,6 +245,14 @@ typedef uint32_t sgl_handle_t; #define DMA_SG2 (1<<5) #define DMA_SG3 (1<<4) +/* DMA Channel Count Register */ +#define DMA_CTC_BTEN (1<<23) /* Burst Enable/Disable bit */ +#define DMA_CTC_BSIZ_MSK (3<<21) /* Mask of the Burst size bits */ +#define DMA_CTC_BSIZ_2 (0) +#define DMA_CTC_BSIZ_4 (1<<21) +#define DMA_CTC_BSIZ_8 (2<<21) +#define DMA_CTC_BSIZ_16 (3<<21) + /* * DMA SG Command Register */ @@ -482,6 +491,7 @@ typedef struct { char td; /* transfer direction */ #endif + char int_on_final_sg;/* for scatter/gather - only interrupt on last sg */ } ppc_dma_ch_t; /* @@ -545,6 +555,9 @@ extern int ppc4xx_delete_dma_sgl_element extern int ppc4xx_alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int); extern void ppc4xx_free_dma_handle(sgl_handle_t); extern int ppc4xx_get_dma_status(void); +extern int ppc4xx_enable_burst(unsigned int); +extern int ppc4xx_disable_burst(unsigned int); +extern int ppc4xx_set_burst_size(unsigned int, unsigned int); extern void ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr); extern void ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr); extern void ppc4xx_enable_dma(unsigned int dmanr); =============================================================== --- linux-2.6.10/arch/ppc/syslib/ppc4xx_sgdma.c 2004-12-24 21:35:18.000000000 +0000 +++ linux-current/arch/ppc/syslib/ppc4xx_sgdma.c 2005-01-19 15:07:47.000000000 +0000 @@ -120,6 +120,12 @@ ppc4xx_add_dma_sgl(sgl_handle_t handle, psgl->ptail = psgl->phead; psgl->ptail_dma = psgl->phead_dma; } else { + if(p_dma_ch->int_on_final_sg) { + /* mask out all dma interrupts, except error, on tail + before adding new tail. */ + psgl->ptail->control_count &= + ~(SG_TCI_ENABLE | SG_ETI_ENABLE); + } psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t); psgl->ptail++; psgl->ptail_dma += sizeof(ppc_sgl_t); @@ -160,7 +166,7 @@ ppc4xx_enable_dma_sgl(sgl_handle_t handl p_dma_ch = &dma_channels[psgl->dmanr]; psgl->ptail->control_count &= ~SG_LINK; /* make this the last dscrptr */ sg_command = mfdcr(DCRN_ASGC); - + ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma); sg_command |= SSG_ENABLE(psgl->dmanr); @@ -217,7 +223,7 @@ ppc4xx_get_dma_sgl_residue(sgl_handle_t } sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8))); - count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)); + count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)) & SG_COUNT_MASK; if (!sgl_addr) { printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n"); @@ -351,10 +357,11 @@ ppc4xx_delete_dma_sgl_element(sgl_handle int ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr) { - sgl_list_info_t *psgl; + sgl_list_info_t *psgl=NULL; dma_addr_t dma_addr; ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr]; uint32_t sg_command; + uint32_t ctc_settings; void *ret; if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) { @@ -412,6 +419,11 @@ ppc4xx_alloc_dma_handle(sgl_handle_t * p mtdcr(DCRN_ASGC, sg_command); psgl->sgl_control = SG_ERI_ENABLE | SG_LINK; + /* keep control count register settings */ + ctc_settings = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) + & (DMA_CTC_BSIZ_MSK | DMA_CTC_BTEN); /*burst mode settings*/ + psgl->sgl_control |= ctc_settings; + if (p_dma_ch->int_enable) { if (p_dma_ch->tce_enable) psgl->sgl_control |= SG_TCI_ENABLE; =============================================================== [End]