diff options
-rw-r--r-- | drivers/dma/dw/core.c | 34 | ||||
-rw-r--r-- | drivers/dma/hsu/hsu.c | 13 | ||||
-rw-r--r-- | drivers/dma/hsu/hsu.h | 3 | ||||
-rw-r--r-- | drivers/dma/omap-dma.c | 26 |
4 files changed, 47 insertions, 29 deletions
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 5ad0ec1f0e29..97199b3c25a2 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c | |||
@@ -130,26 +130,14 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) | |||
130 | static void dwc_initialize(struct dw_dma_chan *dwc) | 130 | static void dwc_initialize(struct dw_dma_chan *dwc) |
131 | { | 131 | { |
132 | struct dw_dma *dw = to_dw_dma(dwc->chan.device); | 132 | struct dw_dma *dw = to_dw_dma(dwc->chan.device); |
133 | struct dw_dma_slave *dws = dwc->chan.private; | ||
134 | u32 cfghi = DWC_CFGH_FIFO_MODE; | 133 | u32 cfghi = DWC_CFGH_FIFO_MODE; |
135 | u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); | 134 | u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); |
136 | 135 | ||
137 | if (dwc->initialized == true) | 136 | if (dwc->initialized == true) |
138 | return; | 137 | return; |
139 | 138 | ||
140 | if (dws) { | 139 | cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); |
141 | /* | 140 | cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); |
142 | * We need controller-specific data to set up slave | ||
143 | * transfers. | ||
144 | */ | ||
145 | BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); | ||
146 | |||
147 | cfghi |= DWC_CFGH_DST_PER(dws->dst_id); | ||
148 | cfghi |= DWC_CFGH_SRC_PER(dws->src_id); | ||
149 | } else { | ||
150 | cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); | ||
151 | cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); | ||
152 | } | ||
153 | 141 | ||
154 | channel_writel(dwc, CFG_LO, cfglo); | 142 | channel_writel(dwc, CFG_LO, cfglo); |
155 | channel_writel(dwc, CFG_HI, cfghi); | 143 | channel_writel(dwc, CFG_HI, cfghi); |
@@ -941,7 +929,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param) | |||
941 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); | 929 | struct dw_dma_chan *dwc = to_dw_dma_chan(chan); |
942 | struct dw_dma_slave *dws = param; | 930 | struct dw_dma_slave *dws = param; |
943 | 931 | ||
944 | if (!dws || dws->dma_dev != chan->device->dev) | 932 | if (dws->dma_dev != chan->device->dev) |
945 | return false; | 933 | return false; |
946 | 934 | ||
947 | /* We have to copy data since dws can be temporary storage */ | 935 | /* We have to copy data since dws can be temporary storage */ |
@@ -1165,6 +1153,14 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) | |||
1165 | * doesn't mean what you think it means), and status writeback. | 1153 | * doesn't mean what you think it means), and status writeback. |
1166 | */ | 1154 | */ |
1167 | 1155 | ||
1156 | /* | ||
1157 | * We need controller-specific data to set up slave transfers. | ||
1158 | */ | ||
1159 | if (chan->private && !dw_dma_filter(chan, chan->private)) { | ||
1160 | dev_warn(chan2dev(chan), "Wrong controller-specific data\n"); | ||
1161 | return -EINVAL; | ||
1162 | } | ||
1163 | |||
1168 | /* Enable controller here if needed */ | 1164 | /* Enable controller here if needed */ |
1169 | if (!dw->in_use) | 1165 | if (!dw->in_use) |
1170 | dw_dma_on(dw); | 1166 | dw_dma_on(dw); |
@@ -1226,6 +1222,14 @@ static void dwc_free_chan_resources(struct dma_chan *chan) | |||
1226 | spin_lock_irqsave(&dwc->lock, flags); | 1222 | spin_lock_irqsave(&dwc->lock, flags); |
1227 | list_splice_init(&dwc->free_list, &list); | 1223 | list_splice_init(&dwc->free_list, &list); |
1228 | dwc->descs_allocated = 0; | 1224 | dwc->descs_allocated = 0; |
1225 | |||
1226 | /* Clear custom channel configuration */ | ||
1227 | dwc->src_id = 0; | ||
1228 | dwc->dst_id = 0; | ||
1229 | |||
1230 | dwc->src_master = 0; | ||
1231 | dwc->dst_master = 0; | ||
1232 | |||
1229 | dwc->initialized = false; | 1233 | dwc->initialized = false; |
1230 | 1234 | ||
1231 | /* Disable interrupts */ | 1235 | /* Disable interrupts */ |
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index eef145edb936..ee510515ce18 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c | |||
@@ -64,10 +64,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) | |||
64 | 64 | ||
65 | if (hsuc->direction == DMA_MEM_TO_DEV) { | 65 | if (hsuc->direction == DMA_MEM_TO_DEV) { |
66 | bsr = config->dst_maxburst; | 66 | bsr = config->dst_maxburst; |
67 | mtsr = config->dst_addr_width; | 67 | mtsr = config->src_addr_width; |
68 | } else if (hsuc->direction == DMA_DEV_TO_MEM) { | 68 | } else if (hsuc->direction == DMA_DEV_TO_MEM) { |
69 | bsr = config->src_maxburst; | 69 | bsr = config->src_maxburst; |
70 | mtsr = config->src_addr_width; | 70 | mtsr = config->dst_addr_width; |
71 | } | 71 | } |
72 | 72 | ||
73 | hsu_chan_disable(hsuc); | 73 | hsu_chan_disable(hsuc); |
@@ -135,7 +135,7 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) | |||
135 | sr = hsu_chan_readl(hsuc, HSU_CH_SR); | 135 | sr = hsu_chan_readl(hsuc, HSU_CH_SR); |
136 | spin_unlock_irqrestore(&hsuc->vchan.lock, flags); | 136 | spin_unlock_irqrestore(&hsuc->vchan.lock, flags); |
137 | 137 | ||
138 | return sr; | 138 | return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); |
139 | } | 139 | } |
140 | 140 | ||
141 | irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) | 141 | irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) |
@@ -254,10 +254,13 @@ static void hsu_dma_issue_pending(struct dma_chan *chan) | |||
254 | static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) | 254 | static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) |
255 | { | 255 | { |
256 | struct hsu_dma_desc *desc = hsuc->desc; | 256 | struct hsu_dma_desc *desc = hsuc->desc; |
257 | size_t bytes = desc->length; | 257 | size_t bytes = 0; |
258 | int i; | 258 | int i; |
259 | 259 | ||
260 | i = desc->active % HSU_DMA_CHAN_NR_DESC; | 260 | for (i = desc->active; i < desc->nents; i++) |
261 | bytes += desc->sg[i].len; | ||
262 | |||
263 | i = HSU_DMA_CHAN_NR_DESC - 1; | ||
261 | do { | 264 | do { |
262 | bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); | 265 | bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); |
263 | } while (--i >= 0); | 266 | } while (--i >= 0); |
diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 578a8ee8cd05..6b070c22b1df 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h | |||
@@ -41,6 +41,9 @@ | |||
41 | #define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) | 41 | #define HSU_CH_SR_DESCTO(x) BIT(8 + (x)) |
42 | #define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) | 42 | #define HSU_CH_SR_DESCTO_ANY (BIT(11) | BIT(10) | BIT(9) | BIT(8)) |
43 | #define HSU_CH_SR_CHE BIT(15) | 43 | #define HSU_CH_SR_CHE BIT(15) |
44 | #define HSU_CH_SR_DESCE(x) BIT(16 + (x)) | ||
45 | #define HSU_CH_SR_DESCE_ANY (BIT(19) | BIT(18) | BIT(17) | BIT(16)) | ||
46 | #define HSU_CH_SR_CDESC_ANY (BIT(31) | BIT(30)) | ||
44 | 47 | ||
45 | /* Bits in HSU_CH_CR */ | 48 | /* Bits in HSU_CH_CR */ |
46 | #define HSU_CH_CR_CHA BIT(0) | 49 | #define HSU_CH_CR_CHA BIT(0) |
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 43bd5aee7ffe..1e984e18c126 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c | |||
@@ -48,6 +48,7 @@ struct omap_chan { | |||
48 | unsigned dma_sig; | 48 | unsigned dma_sig; |
49 | bool cyclic; | 49 | bool cyclic; |
50 | bool paused; | 50 | bool paused; |
51 | bool running; | ||
51 | 52 | ||
52 | int dma_ch; | 53 | int dma_ch; |
53 | struct omap_desc *desc; | 54 | struct omap_desc *desc; |
@@ -294,6 +295,8 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) | |||
294 | 295 | ||
295 | /* Enable channel */ | 296 | /* Enable channel */ |
296 | omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE); | 297 | omap_dma_chan_write(c, CCR, d->ccr | CCR_ENABLE); |
298 | |||
299 | c->running = true; | ||
297 | } | 300 | } |
298 | 301 | ||
299 | static void omap_dma_stop(struct omap_chan *c) | 302 | static void omap_dma_stop(struct omap_chan *c) |
@@ -355,6 +358,8 @@ static void omap_dma_stop(struct omap_chan *c) | |||
355 | 358 | ||
356 | omap_dma_chan_write(c, CLNK_CTRL, val); | 359 | omap_dma_chan_write(c, CLNK_CTRL, val); |
357 | } | 360 | } |
361 | |||
362 | c->running = false; | ||
358 | } | 363 | } |
359 | 364 | ||
360 | static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, | 365 | static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, |
@@ -673,15 +678,20 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, | |||
673 | struct omap_chan *c = to_omap_dma_chan(chan); | 678 | struct omap_chan *c = to_omap_dma_chan(chan); |
674 | struct virt_dma_desc *vd; | 679 | struct virt_dma_desc *vd; |
675 | enum dma_status ret; | 680 | enum dma_status ret; |
676 | uint32_t ccr; | ||
677 | unsigned long flags; | 681 | unsigned long flags; |
678 | 682 | ||
679 | ccr = omap_dma_chan_read(c, CCR); | ||
680 | /* The channel is no longer active, handle the completion right away */ | ||
681 | if (!(ccr & CCR_ENABLE)) | ||
682 | omap_dma_callback(c->dma_ch, 0, c); | ||
683 | |||
684 | ret = dma_cookie_status(chan, cookie, txstate); | 683 | ret = dma_cookie_status(chan, cookie, txstate); |
684 | |||
685 | if (!c->paused && c->running) { | ||
686 | uint32_t ccr = omap_dma_chan_read(c, CCR); | ||
687 | /* | ||
688 | * The channel is no longer active, set the return value | ||
689 | * accordingly | ||
690 | */ | ||
691 | if (!(ccr & CCR_ENABLE)) | ||
692 | ret = DMA_COMPLETE; | ||
693 | } | ||
694 | |||
685 | if (ret == DMA_COMPLETE || !txstate) | 695 | if (ret == DMA_COMPLETE || !txstate) |
686 | return ret; | 696 | return ret; |
687 | 697 | ||
@@ -945,9 +955,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_memcpy( | |||
945 | d->ccr = c->ccr; | 955 | d->ccr = c->ccr; |
946 | d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC; | 956 | d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_POSTINC; |
947 | 957 | ||
948 | d->cicr = CICR_DROP_IE; | 958 | d->cicr = CICR_DROP_IE | CICR_FRAME_IE; |
949 | if (tx_flags & DMA_PREP_INTERRUPT) | ||
950 | d->cicr |= CICR_FRAME_IE; | ||
951 | 959 | ||
952 | d->csdp = data_type; | 960 | d->csdp = data_type; |
953 | 961 | ||