aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/Kconfig1
-rw-r--r--drivers/dma/mxs-dma.c188
2 files changed, 128 insertions, 61 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ef378b5b17e4..aadeb5be9dba 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -238,6 +238,7 @@ config IMX_DMA
238config MXS_DMA 238config MXS_DMA
239 bool "MXS DMA support" 239 bool "MXS DMA support"
240 depends on SOC_IMX23 || SOC_IMX28 240 depends on SOC_IMX23 || SOC_IMX28
241 select STMP_DEVICE
241 select DMA_ENGINE 242 select DMA_ENGINE
242 help 243 help
243 Support the MXS DMA engine. This engine including APBH-DMA 244 Support the MXS DMA engine. This engine including APBH-DMA
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 3db3a48d3f01..c96ab15319f2 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -22,11 +22,14 @@
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/dmaengine.h> 23#include <linux/dmaengine.h>
24#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/module.h>
25#include <linux/fsl/mxs-dma.h> 26#include <linux/fsl/mxs-dma.h>
27#include <linux/stmp_device.h>
28#include <linux/of.h>
29#include <linux/of_device.h>
26 30
27#include <asm/irq.h> 31#include <asm/irq.h>
28#include <mach/mxs.h> 32#include <mach/mxs.h>
29#include <mach/common.h>
30 33
31#include "dmaengine.h" 34#include "dmaengine.h"
32 35
@@ -36,12 +39,8 @@
36 * dma can program the controller registers of peripheral devices. 39 * dma can program the controller registers of peripheral devices.
37 */ 40 */
38 41
39#define MXS_DMA_APBH 0 42#define dma_is_apbh(mxs_dma) ((mxs_dma)->type == MXS_DMA_APBH)
40#define MXS_DMA_APBX 1 43#define apbh_is_old(mxs_dma) ((mxs_dma)->dev_id == IMX23_DMA)
41#define dma_is_apbh() (mxs_dma->dev_id == MXS_DMA_APBH)
42
43#define APBH_VERSION_LATEST 3
44#define apbh_is_old() (mxs_dma->version < APBH_VERSION_LATEST)
45 44
46#define HW_APBHX_CTRL0 0x000 45#define HW_APBHX_CTRL0 0x000
47#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29) 46#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
@@ -51,13 +50,14 @@
51#define HW_APBHX_CTRL2 0x020 50#define HW_APBHX_CTRL2 0x020
52#define HW_APBHX_CHANNEL_CTRL 0x030 51#define HW_APBHX_CHANNEL_CTRL 0x030
53#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL 16 52#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL 16
54#define HW_APBH_VERSION (cpu_is_mx23() ? 0x3f0 : 0x800) 53/*
55#define HW_APBX_VERSION 0x800 54 * The offset of NXTCMDAR register is different per both dma type and version,
56#define BP_APBHX_VERSION_MAJOR 24 55 * while stride for each channel is all the same 0x70.
57#define HW_APBHX_CHn_NXTCMDAR(n) \ 56 */
58 (((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70) 57#define HW_APBHX_CHn_NXTCMDAR(d, n) \
59#define HW_APBHX_CHn_SEMA(n) \ 58 (((dma_is_apbh(d) && apbh_is_old(d)) ? 0x050 : 0x110) + (n) * 0x70)
60 (((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70) 59#define HW_APBHX_CHn_SEMA(d, n) \
60 (((dma_is_apbh(d) && apbh_is_old(d)) ? 0x080 : 0x140) + (n) * 0x70)
61 61
62/* 62/*
63 * ccw bits definitions 63 * ccw bits definitions
@@ -121,9 +121,19 @@ struct mxs_dma_chan {
121#define MXS_DMA_CHANNELS 16 121#define MXS_DMA_CHANNELS 16
122#define MXS_DMA_CHANNELS_MASK 0xffff 122#define MXS_DMA_CHANNELS_MASK 0xffff
123 123
124enum mxs_dma_devtype {
125 MXS_DMA_APBH,
126 MXS_DMA_APBX,
127};
128
129enum mxs_dma_id {
130 IMX23_DMA,
131 IMX28_DMA,
132};
133
124struct mxs_dma_engine { 134struct mxs_dma_engine {
125 int dev_id; 135 enum mxs_dma_id dev_id;
126 unsigned int version; 136 enum mxs_dma_devtype type;
127 void __iomem *base; 137 void __iomem *base;
128 struct clk *clk; 138 struct clk *clk;
129 struct dma_device dma_device; 139 struct dma_device dma_device;
@@ -131,17 +141,86 @@ struct mxs_dma_engine {
131 struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; 141 struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS];
132}; 142};
133 143
144struct mxs_dma_type {
145 enum mxs_dma_id id;
146 enum mxs_dma_devtype type;
147};
148
149static struct mxs_dma_type mxs_dma_types[] = {
150 {
151 .id = IMX23_DMA,
152 .type = MXS_DMA_APBH,
153 }, {
154 .id = IMX23_DMA,
155 .type = MXS_DMA_APBX,
156 }, {
157 .id = IMX28_DMA,
158 .type = MXS_DMA_APBH,
159 }, {
160 .id = IMX28_DMA,
161 .type = MXS_DMA_APBX,
162 }
163};
164
165static struct platform_device_id mxs_dma_ids[] = {
166 {
167 .name = "imx23-dma-apbh",
168 .driver_data = (kernel_ulong_t) &mxs_dma_types[0],
169 }, {
170 .name = "imx23-dma-apbx",
171 .driver_data = (kernel_ulong_t) &mxs_dma_types[1],
172 }, {
173 .name = "imx28-dma-apbh",
174 .driver_data = (kernel_ulong_t) &mxs_dma_types[2],
175 }, {
176 .name = "imx28-dma-apbx",
177 .driver_data = (kernel_ulong_t) &mxs_dma_types[3],
178 }, {
179 /* end of list */
180 }
181};
182
183static const struct of_device_id mxs_dma_dt_ids[] = {
184 { .compatible = "fsl,imx23-dma-apbh", .data = &mxs_dma_ids[0], },
185 { .compatible = "fsl,imx23-dma-apbx", .data = &mxs_dma_ids[1], },
186 { .compatible = "fsl,imx28-dma-apbh", .data = &mxs_dma_ids[2], },
187 { .compatible = "fsl,imx28-dma-apbx", .data = &mxs_dma_ids[3], },
188 { /* sentinel */ }
189};
190MODULE_DEVICE_TABLE(of, mxs_dma_dt_ids);
191
192static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
193{
194 return container_of(chan, struct mxs_dma_chan, chan);
195}
196
197int mxs_dma_is_apbh(struct dma_chan *chan)
198{
199 struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
200 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
201
202 return dma_is_apbh(mxs_dma);
203}
204
205int mxs_dma_is_apbx(struct dma_chan *chan)
206{
207 struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
208 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
209
210 return !dma_is_apbh(mxs_dma);
211}
212
134static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) 213static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
135{ 214{
136 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; 215 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
137 int chan_id = mxs_chan->chan.chan_id; 216 int chan_id = mxs_chan->chan.chan_id;
138 217
139 if (dma_is_apbh() && apbh_is_old()) 218 if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
140 writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL), 219 writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL),
141 mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); 220 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
142 else 221 else
143 writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL), 222 writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL),
144 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR); 223 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET);
145} 224}
146 225
147static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) 226static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
@@ -151,10 +230,10 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
151 230
152 /* set cmd_addr up */ 231 /* set cmd_addr up */
153 writel(mxs_chan->ccw_phys, 232 writel(mxs_chan->ccw_phys,
154 mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); 233 mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(mxs_dma, chan_id));
155 234
156 /* write 1 to SEMA to kick off the channel */ 235 /* write 1 to SEMA to kick off the channel */
157 writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); 236 writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(mxs_dma, chan_id));
158} 237}
159 238
160static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) 239static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
@@ -168,12 +247,12 @@ static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
168 int chan_id = mxs_chan->chan.chan_id; 247 int chan_id = mxs_chan->chan.chan_id;
169 248
170 /* freeze the channel */ 249 /* freeze the channel */
171 if (dma_is_apbh() && apbh_is_old()) 250 if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
172 writel(1 << chan_id, 251 writel(1 << chan_id,
173 mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); 252 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
174 else 253 else
175 writel(1 << chan_id, 254 writel(1 << chan_id,
176 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR); 255 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET);
177 256
178 mxs_chan->status = DMA_PAUSED; 257 mxs_chan->status = DMA_PAUSED;
179} 258}
@@ -184,21 +263,16 @@ static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
184 int chan_id = mxs_chan->chan.chan_id; 263 int chan_id = mxs_chan->chan.chan_id;
185 264
186 /* unfreeze the channel */ 265 /* unfreeze the channel */
187 if (dma_is_apbh() && apbh_is_old()) 266 if (dma_is_apbh(mxs_dma) && apbh_is_old(mxs_dma))
188 writel(1 << chan_id, 267 writel(1 << chan_id,
189 mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); 268 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_CLR);
190 else 269 else
191 writel(1 << chan_id, 270 writel(1 << chan_id,
192 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR); 271 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_CLR);
193 272
194 mxs_chan->status = DMA_IN_PROGRESS; 273 mxs_chan->status = DMA_IN_PROGRESS;
195} 274}
196 275
197static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
198{
199 return container_of(chan, struct mxs_dma_chan, chan);
200}
201
202static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx) 276static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
203{ 277{
204 return dma_cookie_assign(tx); 278 return dma_cookie_assign(tx);
@@ -220,11 +294,11 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
220 /* completion status */ 294 /* completion status */
221 stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1); 295 stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1);
222 stat1 &= MXS_DMA_CHANNELS_MASK; 296 stat1 &= MXS_DMA_CHANNELS_MASK;
223 writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR); 297 writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_CLR);
224 298
225 /* error status */ 299 /* error status */
226 stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2); 300 stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2);
227 writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR); 301 writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + STMP_OFFSET_REG_CLR);
228 302
229 /* 303 /*
230 * When both completion and error of termination bits set at the 304 * When both completion and error of termination bits set at the
@@ -567,27 +641,21 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
567 if (ret) 641 if (ret)
568 return ret; 642 return ret;
569 643
570 ret = mxs_reset_block(mxs_dma->base); 644 ret = stmp_reset_block(mxs_dma->base);
571 if (ret) 645 if (ret)
572 goto err_out; 646 goto err_out;
573 647
574 /* only major version matters */
575 mxs_dma->version = readl(mxs_dma->base +
576 ((mxs_dma->dev_id == MXS_DMA_APBX) ?
577 HW_APBX_VERSION : HW_APBH_VERSION)) >>
578 BP_APBHX_VERSION_MAJOR;
579
580 /* enable apbh burst */ 648 /* enable apbh burst */
581 if (dma_is_apbh()) { 649 if (dma_is_apbh(mxs_dma)) {
582 writel(BM_APBH_CTRL0_APB_BURST_EN, 650 writel(BM_APBH_CTRL0_APB_BURST_EN,
583 mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); 651 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
584 writel(BM_APBH_CTRL0_APB_BURST8_EN, 652 writel(BM_APBH_CTRL0_APB_BURST8_EN,
585 mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); 653 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET);
586 } 654 }
587 655
588 /* enable irq for all the channels */ 656 /* enable irq for all the channels */
589 writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS, 657 writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
590 mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR); 658 mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET);
591 659
592err_out: 660err_out:
593 clk_disable_unprepare(mxs_dma->clk); 661 clk_disable_unprepare(mxs_dma->clk);
@@ -596,8 +664,9 @@ err_out:
596 664
597static int __init mxs_dma_probe(struct platform_device *pdev) 665static int __init mxs_dma_probe(struct platform_device *pdev)
598{ 666{
599 const struct platform_device_id *id_entry = 667 const struct platform_device_id *id_entry;
600 platform_get_device_id(pdev); 668 const struct of_device_id *of_id;
669 const struct mxs_dma_type *dma_type;
601 struct mxs_dma_engine *mxs_dma; 670 struct mxs_dma_engine *mxs_dma;
602 struct resource *iores; 671 struct resource *iores;
603 int ret, i; 672 int ret, i;
@@ -606,7 +675,15 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
606 if (!mxs_dma) 675 if (!mxs_dma)
607 return -ENOMEM; 676 return -ENOMEM;
608 677
609 mxs_dma->dev_id = id_entry->driver_data; 678 of_id = of_match_device(mxs_dma_dt_ids, &pdev->dev);
679 if (of_id)
680 id_entry = of_id->data;
681 else
682 id_entry = platform_get_device_id(pdev);
683
684 dma_type = (struct mxs_dma_type *)id_entry->driver_data;
685 mxs_dma->type = dma_type->type;
686 mxs_dma->dev_id = dma_type->id;
610 687
611 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); 688 iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
612 689
@@ -689,23 +766,12 @@ err_request_region:
689 return ret; 766 return ret;
690} 767}
691 768
692static struct platform_device_id mxs_dma_type[] = {
693 {
694 .name = "mxs-dma-apbh",
695 .driver_data = MXS_DMA_APBH,
696 }, {
697 .name = "mxs-dma-apbx",
698 .driver_data = MXS_DMA_APBX,
699 }, {
700 /* end of list */
701 }
702};
703
704static struct platform_driver mxs_dma_driver = { 769static struct platform_driver mxs_dma_driver = {
705 .driver = { 770 .driver = {
706 .name = "mxs-dma", 771 .name = "mxs-dma",
772 .of_match_table = mxs_dma_dt_ids,
707 }, 773 },
708 .id_table = mxs_dma_type, 774 .id_table = mxs_dma_ids,
709}; 775};
710 776
711static int __init mxs_dma_module_init(void) 777static int __init mxs_dma_module_init(void)