Commit 91b9b683 authored by Matt Porter's avatar Matt Porter Committed by Linus Torvalds

[PATCH] ppc32: PPC4xx DMA fixes, burst, and sg improvements

This fixes several issues with the PPC4xx DMA library as well as adding
support for bursting and some improvements to SG handling.
Signed-off-by: default avatarColin Wernham <cwernham@airspan.com>
Signed-off-by: default avatarMatt Porter <mporter@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 75c146da
......@@ -512,6 +512,8 @@ ppc4xx_get_channel_config(unsigned int dmanr, ppc_dma_ch_t * p_dma_ch)
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 dmanr)
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);
......@@ -120,6 +120,12 @@ ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_ad
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);
......@@ -217,7 +223,7 @@ ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
}
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_t handle, phys_addr_t * src_dma_addr,
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 * phandle, unsigned int mode, unsigned int
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;
......
......@@ -137,10 +137,11 @@ extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
#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
* These modes are defined in a way that makes it possible to
......@@ -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(sgl_handle_t, phys_addr_t *, phys_addr_
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment