|
@@ -288,6 +288,30 @@ struct sdma_context_data {
|
|
|
|
|
|
struct sdma_engine;
|
|
|
|
|
|
+/**
|
|
|
+ * struct sdma_desc - descriptor structor for one transfer
|
|
|
+ * @vd descriptor for virt dma
|
|
|
+ * @num_bd max NUM_BD. number of descriptors currently handling
|
|
|
+ * @buf_tail ID of the buffer that was processed
|
|
|
+ * @buf_ptail ID of the previous buffer that was processed
|
|
|
+ * @period_len period length, used in cyclic.
|
|
|
+ * @chn_real_count the real count updated from bd->mode.count
|
|
|
+ * @chn_count the transfer count setuped
|
|
|
+ * @sdmac sdma_channel pointer
|
|
|
+ * @bd pointer of alloced bd
|
|
|
+ */
|
|
|
+struct sdma_desc {
|
|
|
+ unsigned int num_bd;
|
|
|
+ dma_addr_t bd_phys;
|
|
|
+ unsigned int buf_tail;
|
|
|
+ unsigned int buf_ptail;
|
|
|
+ unsigned int period_len;
|
|
|
+ unsigned int chn_real_count;
|
|
|
+ unsigned int chn_count;
|
|
|
+ struct sdma_channel *sdmac;
|
|
|
+ struct sdma_buffer_descriptor *bd;
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* struct sdma_channel - housekeeping for a SDMA channel
|
|
|
*
|
|
@@ -298,11 +322,10 @@ struct sdma_engine;
|
|
|
* @event_id0 aka dma request line
|
|
|
* @event_id1 for channels that use 2 events
|
|
|
* @word_size peripheral access size
|
|
|
- * @buf_tail ID of the buffer that was processed
|
|
|
- * @buf_ptail ID of the previous buffer that was processed
|
|
|
- * @num_bd max NUM_BD. number of descriptors currently handling
|
|
|
*/
|
|
|
struct sdma_channel {
|
|
|
+ struct sdma_desc *desc;
|
|
|
+ struct sdma_desc _desc;
|
|
|
struct sdma_engine *sdma;
|
|
|
unsigned int channel;
|
|
|
enum dma_transfer_direction direction;
|
|
@@ -310,12 +333,6 @@ struct sdma_channel {
|
|
|
unsigned int event_id0;
|
|
|
unsigned int event_id1;
|
|
|
enum dma_slave_buswidth word_size;
|
|
|
- unsigned int buf_tail;
|
|
|
- unsigned int buf_ptail;
|
|
|
- unsigned int num_bd;
|
|
|
- unsigned int period_len;
|
|
|
- struct sdma_buffer_descriptor *bd;
|
|
|
- dma_addr_t bd_phys;
|
|
|
unsigned int pc_from_device, pc_to_device;
|
|
|
unsigned int device_to_device;
|
|
|
unsigned long flags;
|
|
@@ -325,10 +342,8 @@ struct sdma_channel {
|
|
|
u32 shp_addr, per_addr;
|
|
|
struct dma_chan chan;
|
|
|
spinlock_t lock;
|
|
|
- struct dma_async_tx_descriptor desc;
|
|
|
+ struct dma_async_tx_descriptor txdesc;
|
|
|
enum dma_status status;
|
|
|
- unsigned int chn_count;
|
|
|
- unsigned int chn_real_count;
|
|
|
struct tasklet_struct tasklet;
|
|
|
struct imx_dma_data data;
|
|
|
bool enabled;
|
|
@@ -391,6 +406,8 @@ struct sdma_engine {
|
|
|
u32 spba_start_addr;
|
|
|
u32 spba_end_addr;
|
|
|
unsigned int irq;
|
|
|
+ dma_addr_t bd0_phys;
|
|
|
+ struct sdma_buffer_descriptor *bd0;
|
|
|
};
|
|
|
|
|
|
static struct sdma_driver_data sdma_imx31 = {
|
|
@@ -625,7 +642,7 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
|
|
|
static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
|
|
|
u32 address)
|
|
|
{
|
|
|
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
|
|
|
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
|
|
|
void *buf_virt;
|
|
|
dma_addr_t buf_phys;
|
|
|
int ret;
|
|
@@ -700,7 +717,9 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
|
|
|
* call callback function.
|
|
|
*/
|
|
|
while (1) {
|
|
|
- bd = &sdmac->bd[sdmac->buf_tail];
|
|
|
+ struct sdma_desc *desc = sdmac->desc;
|
|
|
+
|
|
|
+ bd = &desc->bd[desc->buf_tail];
|
|
|
|
|
|
if (bd->mode.status & BD_DONE)
|
|
|
break;
|
|
@@ -716,11 +735,11 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
|
|
|
* the number of bytes present in the current buffer descriptor.
|
|
|
*/
|
|
|
|
|
|
- sdmac->chn_real_count = bd->mode.count;
|
|
|
+ desc->chn_real_count = bd->mode.count;
|
|
|
bd->mode.status |= BD_DONE;
|
|
|
- bd->mode.count = sdmac->period_len;
|
|
|
- sdmac->buf_ptail = sdmac->buf_tail;
|
|
|
- sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
|
|
|
+ bd->mode.count = desc->period_len;
|
|
|
+ desc->buf_ptail = desc->buf_tail;
|
|
|
+ desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
|
|
|
|
|
|
/*
|
|
|
* The callback is called from the interrupt context in order
|
|
@@ -729,7 +748,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
|
|
|
* executed.
|
|
|
*/
|
|
|
|
|
|
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
|
|
|
+ dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
|
|
|
|
|
|
if (error)
|
|
|
sdmac->status = old_status;
|
|
@@ -742,17 +761,17 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
|
|
|
struct sdma_buffer_descriptor *bd;
|
|
|
int i, error = 0;
|
|
|
|
|
|
- sdmac->chn_real_count = 0;
|
|
|
+ sdmac->desc->chn_real_count = 0;
|
|
|
/*
|
|
|
* non loop mode. Iterate over all descriptors, collect
|
|
|
* errors and call callback function
|
|
|
*/
|
|
|
- for (i = 0; i < sdmac->num_bd; i++) {
|
|
|
- bd = &sdmac->bd[i];
|
|
|
+ for (i = 0; i < sdmac->desc->num_bd; i++) {
|
|
|
+ bd = &sdmac->desc->bd[i];
|
|
|
|
|
|
if (bd->mode.status & (BD_DONE | BD_RROR))
|
|
|
error = -EIO;
|
|
|
- sdmac->chn_real_count += bd->mode.count;
|
|
|
+ sdmac->desc->chn_real_count += bd->mode.count;
|
|
|
}
|
|
|
|
|
|
if (error)
|
|
@@ -760,9 +779,9 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
|
|
|
else
|
|
|
sdmac->status = DMA_COMPLETE;
|
|
|
|
|
|
- dma_cookie_complete(&sdmac->desc);
|
|
|
+ dma_cookie_complete(&sdmac->txdesc);
|
|
|
|
|
|
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
|
|
|
+ dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
|
|
|
}
|
|
|
|
|
|
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
|
|
@@ -890,7 +909,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
|
|
|
int channel = sdmac->channel;
|
|
|
int load_address;
|
|
|
struct sdma_context_data *context = sdma->context;
|
|
|
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
|
|
|
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
|
|
|
int ret;
|
|
|
unsigned long flags;
|
|
|
|
|
@@ -1093,18 +1112,22 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
|
|
|
static int sdma_request_channel(struct sdma_channel *sdmac)
|
|
|
{
|
|
|
struct sdma_engine *sdma = sdmac->sdma;
|
|
|
+ struct sdma_desc *desc;
|
|
|
int channel = sdmac->channel;
|
|
|
int ret = -EBUSY;
|
|
|
|
|
|
- sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
|
|
|
+ sdmac->desc = &sdmac->_desc;
|
|
|
+ desc = sdmac->desc;
|
|
|
+
|
|
|
+ desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
|
|
|
GFP_KERNEL);
|
|
|
- if (!sdmac->bd) {
|
|
|
+ if (!desc->bd) {
|
|
|
ret = -ENOMEM;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
|
|
|
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
|
|
|
+ sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
|
|
|
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
|
|
|
|
|
|
sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
|
|
|
return 0;
|
|
@@ -1169,10 +1192,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
|
|
|
if (ret)
|
|
|
goto disable_clk_ahb;
|
|
|
|
|
|
- dma_async_tx_descriptor_init(&sdmac->desc, chan);
|
|
|
- sdmac->desc.tx_submit = sdma_tx_submit;
|
|
|
+ dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
|
|
|
+ sdmac->txdesc.tx_submit = sdma_tx_submit;
|
|
|
/* txd.flags will be overwritten in prep funcs */
|
|
|
- sdmac->desc.flags = DMA_CTRL_ACK;
|
|
|
+ sdmac->txdesc.flags = DMA_CTRL_ACK;
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -1187,6 +1210,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
|
|
|
{
|
|
|
struct sdma_channel *sdmac = to_sdma_chan(chan);
|
|
|
struct sdma_engine *sdma = sdmac->sdma;
|
|
|
+ struct sdma_desc *desc = sdmac->desc;
|
|
|
|
|
|
sdma_disable_channel(chan);
|
|
|
|
|
@@ -1200,7 +1224,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
|
|
|
|
|
|
sdma_set_channel_priority(sdmac, 0);
|
|
|
|
|
|
- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
|
|
|
+ dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);
|
|
|
|
|
|
clk_disable(sdma->clk_ipg);
|
|
|
clk_disable(sdma->clk_ahb);
|
|
@@ -1216,6 +1240,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
|
|
|
int ret, i, count;
|
|
|
int channel = sdmac->channel;
|
|
|
struct scatterlist *sg;
|
|
|
+ struct sdma_desc *desc = sdmac->desc;
|
|
|
|
|
|
if (sdmac->status == DMA_IN_PROGRESS)
|
|
|
return NULL;
|
|
@@ -1223,9 +1248,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
|
|
|
|
|
|
sdmac->flags = 0;
|
|
|
|
|
|
- sdmac->buf_tail = 0;
|
|
|
- sdmac->buf_ptail = 0;
|
|
|
- sdmac->chn_real_count = 0;
|
|
|
+ desc->buf_tail = 0;
|
|
|
+ desc->buf_ptail = 0;
|
|
|
+ desc->chn_real_count = 0;
|
|
|
|
|
|
dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
|
|
|
sg_len, channel);
|
|
@@ -1242,9 +1267,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
|
|
|
goto err_out;
|
|
|
}
|
|
|
|
|
|
- sdmac->chn_count = 0;
|
|
|
+ desc->chn_count = 0;
|
|
|
for_each_sg(sgl, sg, sg_len, i) {
|
|
|
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
|
|
|
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
|
|
|
int param;
|
|
|
|
|
|
bd->buffer_addr = sg->dma_address;
|
|
@@ -1259,7 +1284,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
|
|
|
}
|
|
|
|
|
|
bd->mode.count = count;
|
|
|
- sdmac->chn_count += count;
|
|
|
+ desc->chn_count += count;
|
|
|
|
|
|
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
|
|
|
ret = -EINVAL;
|
|
@@ -1300,10 +1325,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
|
|
|
bd->mode.status = param;
|
|
|
}
|
|
|
|
|
|
- sdmac->num_bd = sg_len;
|
|
|
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
|
|
|
+ desc->num_bd = sg_len;
|
|
|
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
|
|
|
|
|
|
- return &sdmac->desc;
|
|
|
+ return &sdmac->txdesc;
|
|
|
err_out:
|
|
|
sdmac->status = DMA_ERROR;
|
|
|
return NULL;
|
|
@@ -1319,6 +1344,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
|
|
|
int num_periods = buf_len / period_len;
|
|
|
int channel = sdmac->channel;
|
|
|
int ret, i = 0, buf = 0;
|
|
|
+ struct sdma_desc *desc = sdmac->desc;
|
|
|
|
|
|
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
|
|
|
|
|
@@ -1327,10 +1353,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
|
|
|
|
|
|
sdmac->status = DMA_IN_PROGRESS;
|
|
|
|
|
|
- sdmac->buf_tail = 0;
|
|
|
- sdmac->buf_ptail = 0;
|
|
|
- sdmac->chn_real_count = 0;
|
|
|
- sdmac->period_len = period_len;
|
|
|
+ desc->buf_tail = 0;
|
|
|
+ desc->buf_ptail = 0;
|
|
|
+ desc->chn_real_count = 0;
|
|
|
+ desc->period_len = period_len;
|
|
|
|
|
|
sdmac->flags |= IMX_DMA_SG_LOOP;
|
|
|
sdmac->direction = direction;
|
|
@@ -1351,7 +1377,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
|
|
|
}
|
|
|
|
|
|
while (buf < buf_len) {
|
|
|
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
|
|
|
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
|
|
|
int param;
|
|
|
|
|
|
bd->buffer_addr = dma_addr;
|
|
@@ -1382,10 +1408,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
- sdmac->num_bd = num_periods;
|
|
|
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
|
|
|
+ desc->num_bd = num_periods;
|
|
|
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
|
|
|
|
|
|
- return &sdmac->desc;
|
|
|
+ return &sdmac->txdesc;
|
|
|
err_out:
|
|
|
sdmac->status = DMA_ERROR;
|
|
|
return NULL;
|
|
@@ -1424,13 +1450,14 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
|
|
|
struct dma_tx_state *txstate)
|
|
|
{
|
|
|
struct sdma_channel *sdmac = to_sdma_chan(chan);
|
|
|
+ struct sdma_desc *desc = sdmac->desc;
|
|
|
u32 residue;
|
|
|
|
|
|
if (sdmac->flags & IMX_DMA_SG_LOOP)
|
|
|
- residue = (sdmac->num_bd - sdmac->buf_ptail) *
|
|
|
- sdmac->period_len - sdmac->chn_real_count;
|
|
|
+ residue = (desc->num_bd - desc->buf_ptail) *
|
|
|
+ desc->period_len - desc->chn_real_count;
|
|
|
else
|
|
|
- residue = sdmac->chn_count - sdmac->chn_real_count;
|
|
|
+ residue = desc->chn_count - desc->chn_real_count;
|
|
|
|
|
|
dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
|
|
|
residue);
|
|
@@ -1654,6 +1681,8 @@ static int sdma_init(struct sdma_engine *sdma)
|
|
|
if (ret)
|
|
|
goto err_dma_alloc;
|
|
|
|
|
|
+ sdma->bd0 = sdma->channel[0].desc->bd;
|
|
|
+
|
|
|
sdma_config_ownership(&sdma->channel[0], false, true, false);
|
|
|
|
|
|
/* Set Command Channel (Channel Zero) */
|