dma/imx-sdma: move clk_enable out of sdma_request_channel
[deliverable/linux.git] / drivers / dma / imx-sdma.c
index f993955a640c376342498d3336668348ecd78884..1e0e516b481f31710d74462afc3e271002cf5fa3 100644 (file)
@@ -247,7 +247,7 @@ struct sdma_engine;
 struct sdma_channel {
        struct sdma_engine              *sdma;
        unsigned int                    channel;
-       enum dma_data_direction         direction;
+       enum dma_transfer_direction             direction;
        enum sdma_peripheral_type       peripheral_type;
        unsigned int                    event_id0;
        unsigned int                    event_id1;
@@ -268,6 +268,8 @@ struct sdma_channel {
        struct dma_async_tx_descriptor  desc;
        dma_cookie_t                    last_completed;
        enum dma_status                 status;
+       unsigned int                    chn_count;
+       unsigned int                    chn_real_count;
 };
 
 #define IMX_DMA_SG_LOOP                (1 << 0)
@@ -366,9 +368,9 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
        if (event_override && mcu_override && dsp_override)
                return -EINVAL;
 
-       evt = __raw_readl(sdma->regs + SDMA_H_EVTOVR);
-       mcu = __raw_readl(sdma->regs + SDMA_H_HOSTOVR);
-       dsp = __raw_readl(sdma->regs + SDMA_H_DSPOVR);
+       evt = readl_relaxed(sdma->regs + SDMA_H_EVTOVR);
+       mcu = readl_relaxed(sdma->regs + SDMA_H_HOSTOVR);
+       dsp = readl_relaxed(sdma->regs + SDMA_H_DSPOVR);
 
        if (dsp_override)
                dsp &= ~(1 << channel);
@@ -385,13 +387,18 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
        else
                mcu |= (1 << channel);
 
-       __raw_writel(evt, sdma->regs + SDMA_H_EVTOVR);
-       __raw_writel(mcu, sdma->regs + SDMA_H_HOSTOVR);
-       __raw_writel(dsp, sdma->regs + SDMA_H_DSPOVR);
+       writel_relaxed(evt, sdma->regs + SDMA_H_EVTOVR);
+       writel_relaxed(mcu, sdma->regs + SDMA_H_HOSTOVR);
+       writel_relaxed(dsp, sdma->regs + SDMA_H_DSPOVR);
 
        return 0;
 }
 
+static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
+{
+       writel(1 << channel, sdma->regs + SDMA_H_START);
+}
+
 /*
  * sdma_run_channel - run a channel and wait till it's done
  */
@@ -403,7 +410,7 @@ static int sdma_run_channel(struct sdma_channel *sdmac)
 
        init_completion(&sdmac->done);
 
-       __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
+       sdma_enable_channel(sdma, channel);
 
        ret = wait_for_completion_timeout(&sdmac->done, HZ);
 
@@ -453,9 +460,9 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
        u32 val;
        u32 chnenbl = chnenbl_ofs(sdma, event);
 
-       val = __raw_readl(sdma->regs + chnenbl);
+       val = readl_relaxed(sdma->regs + chnenbl);
        val |= (1 << channel);
-       __raw_writel(val, sdma->regs + chnenbl);
+       writel_relaxed(val, sdma->regs + chnenbl);
 }
 
 static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -465,9 +472,9 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
        u32 chnenbl = chnenbl_ofs(sdma, event);
        u32 val;
 
-       val = __raw_readl(sdma->regs + chnenbl);
+       val = readl_relaxed(sdma->regs + chnenbl);
        val &= ~(1 << channel);
-       __raw_writel(val, sdma->regs + chnenbl);
+       writel_relaxed(val, sdma->regs + chnenbl);
 }
 
 static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
@@ -503,6 +510,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
        struct sdma_buffer_descriptor *bd;
        int i, error = 0;
 
+       sdmac->chn_real_count = 0;
        /*
         * non loop mode. Iterate over all descriptors, collect
         * errors and call callback function
@@ -512,6 +520,7 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
 
                 if (bd->mode.status & (BD_DONE | BD_RROR))
                        error = -EIO;
+                sdmac->chn_real_count += bd->mode.count;
        }
 
        if (error)
@@ -519,9 +528,9 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
        else
                sdmac->status = DMA_SUCCESS;
 
+       sdmac->last_completed = sdmac->desc.cookie;
        if (sdmac->desc.callback)
                sdmac->desc.callback(sdmac->desc.callback_param);
-       sdmac->last_completed = sdmac->desc.cookie;
 }
 
 static void mxc_sdma_handle_channel(struct sdma_channel *sdmac)
@@ -543,8 +552,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
        struct sdma_engine *sdma = dev_id;
        u32 stat;
 
-       stat = __raw_readl(sdma->regs + SDMA_H_INTR);
-       __raw_writel(stat, sdma->regs + SDMA_H_INTR);
+       stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
+       writel_relaxed(stat, sdma->regs + SDMA_H_INTR);
 
        while (stat) {
                int channel = fls(stat) - 1;
@@ -650,7 +659,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
        struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
        int ret;
 
-       if (sdmac->direction == DMA_FROM_DEVICE) {
+       if (sdmac->direction == DMA_DEV_TO_MEM) {
                load_address = sdmac->pc_from_device;
        } else {
                load_address = sdmac->pc_to_device;
@@ -698,7 +707,7 @@ static void sdma_disable_channel(struct sdma_channel *sdmac)
        struct sdma_engine *sdma = sdmac->sdma;
        int channel = sdmac->channel;
 
-       __raw_writel(1 << channel, sdma->regs + SDMA_H_STATSTOP);
+       writel_relaxed(1 << channel, sdma->regs + SDMA_H_STATSTOP);
        sdmac->status = DMA_ERROR;
 }
 
@@ -771,7 +780,7 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
                return -EINVAL;
        }
 
-       __raw_writel(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
+       writel_relaxed(priority, sdma->regs + SDMA_CHNPRI_0 + 4 * channel);
 
        return 0;
 }
@@ -793,8 +802,6 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
        sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
        sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
 
-       clk_enable(sdma->clk);
-
        sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
 
        init_completion(&sdmac->done);
@@ -807,11 +814,6 @@ out:
        return ret;
 }
 
-static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
-{
-       __raw_writel(1 << channel, sdma->regs + SDMA_H_START);
-}
-
 static dma_cookie_t sdma_assign_cookie(struct sdma_channel *sdmac)
 {
        dma_cookie_t cookie = sdmac->chan.cookie;
@@ -832,17 +834,15 @@ static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
 
 static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
 {
+       unsigned long flags;
        struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
-       struct sdma_engine *sdma = sdmac->sdma;
        dma_cookie_t cookie;
 
-       spin_lock_irq(&sdmac->lock);
+       spin_lock_irqsave(&sdmac->lock, flags);
 
        cookie = sdma_assign_cookie(sdmac);
 
-       sdma_enable_channel(sdma, sdmac->channel);
-
-       spin_unlock_irq(&sdmac->lock);
+       spin_unlock_irqrestore(&sdmac->lock, flags);
 
        return cookie;
 }
@@ -871,11 +871,14 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
 
        sdmac->peripheral_type = data->peripheral_type;
        sdmac->event_id0 = data->dma_request;
-       ret = sdma_set_channel_priority(sdmac, prio);
+
+       clk_enable(sdmac->sdma->clk);
+
+       ret = sdma_request_channel(sdmac);
        if (ret)
                return ret;
 
-       ret = sdma_request_channel(sdmac);
+       ret = sdma_set_channel_priority(sdmac, prio);
        if (ret)
                return ret;
 
@@ -911,7 +914,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
 static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flags)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
@@ -941,6 +944,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                goto err_out;
        }
 
+       sdmac->chn_count = 0;
        for_each_sg(sgl, sg, sg_len, i) {
                struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
                int param;
@@ -957,6 +961,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
                }
 
                bd->mode.count = count;
+               sdmac->chn_count += count;
 
                if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
                        ret =  -EINVAL;
@@ -1008,7 +1013,7 @@ err_out:
 
 static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
        struct sdma_engine *sdma = sdmac->sdma;
@@ -1093,7 +1098,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                sdma_disable_channel(sdmac);
                return 0;
        case DMA_SLAVE_CONFIG:
-               if (dmaengine_cfg->direction == DMA_FROM_DEVICE) {
+               if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
                        sdmac->per_address = dmaengine_cfg->src_addr;
                        sdmac->watermark_level = dmaengine_cfg->src_maxburst;
                        sdmac->word_size = dmaengine_cfg->src_addr_width;
@@ -1102,6 +1107,7 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                        sdmac->watermark_level = dmaengine_cfg->dst_maxburst;
                        sdmac->word_size = dmaengine_cfg->dst_addr_width;
                }
+               sdmac->direction = dmaengine_cfg->direction;
                return sdma_config_channel(sdmac);
        default:
                return -ENOSYS;
@@ -1119,16 +1125,19 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 
        last_used = chan->cookie;
 
-       dma_set_tx_state(txstate, sdmac->last_completed, last_used, 0);
+       dma_set_tx_state(txstate, sdmac->last_completed, last_used,
+                       sdmac->chn_count - sdmac->chn_real_count);
 
        return sdmac->status;
 }
 
 static void sdma_issue_pending(struct dma_chan *chan)
 {
-       /*
-        * Nothing to do. We only have a single descriptor
-        */
+       struct sdma_channel *sdmac = to_sdma_chan(chan);
+       struct sdma_engine *sdma = sdmac->sdma;
+
+       if (sdmac->status == DMA_IN_PROGRESS)
+               sdma_enable_channel(sdma, sdmac->channel);
 }
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1        34
@@ -1220,7 +1229,7 @@ static int __init sdma_init(struct sdma_engine *sdma)
        clk_enable(sdma->clk);
 
        /* Be sure SDMA has not started yet */
-       __raw_writel(0, sdma->regs + SDMA_H_C0PTR);
+       writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
 
        sdma->channel_control = dma_alloc_coherent(NULL,
                        MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
@@ -1243,11 +1252,11 @@ static int __init sdma_init(struct sdma_engine *sdma)
 
        /* disable all channels */
        for (i = 0; i < sdma->num_events; i++)
-               __raw_writel(0, sdma->regs + chnenbl_ofs(sdma, i));
+               writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
 
        /* All channels have priority 0 */
        for (i = 0; i < MAX_DMA_CHANNELS; i++)
-               __raw_writel(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
+               writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
 
        ret = sdma_request_channel(&sdma->channel[0]);
        if (ret)
@@ -1256,16 +1265,16 @@ static int __init sdma_init(struct sdma_engine *sdma)
        sdma_config_ownership(&sdma->channel[0], false, true, false);
 
        /* Set Command Channel (Channel Zero) */
-       __raw_writel(0x4050, sdma->regs + SDMA_CHN0ADDR);
+       writel_relaxed(0x4050, sdma->regs + SDMA_CHN0ADDR);
 
        /* Set bits of CONFIG register but with static context switching */
        /* FIXME: Check whether to set ACR bit depending on clock ratios */
-       __raw_writel(0, sdma->regs + SDMA_H_CONFIG);
+       writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
 
-       __raw_writel(ccb_phys, sdma->regs + SDMA_H_C0PTR);
+       writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
 
        /* Set bits of CONFIG register with given context switching mode */
-       __raw_writel(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
+       writel_relaxed(SDMA_H_CONFIG_CSM, sdma->regs + SDMA_H_CONFIG);
 
        /* Initializes channel's priorities */
        sdma_set_channel_priority(&sdma->channel[0], 7);
This page took 0.042126 seconds and 5 git commands to generate.