aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-s3c2410/Makefile6
-rw-r--r--arch/arm/mach-s3c2410/dma.c241
-rw-r--r--arch/arm/mach-s3c2410/dma.h45
-rw-r--r--include/asm-arm/arch-s3c2410/dma.h34
4 files changed, 257 insertions, 69 deletions
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 0eadec916214..e4c32f6ffb71 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -9,6 +9,8 @@ obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o
9obj-m := 9obj-m :=
10obj-n := 10obj-n :=
11obj- := 11obj- :=
12obj-dma-y :=
13obj-dma-n :=
12 14
13# DMA 15# DMA
14obj-$(CONFIG_S3C2410_DMA) += dma.o 16obj-$(CONFIG_S3C2410_DMA) += dma.o
@@ -57,6 +59,10 @@ obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
57 59
58obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o 60obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
59 61
62# merge in dma objects
63
64obj-y += $(obj-dma-y)
65
60# machine specific support 66# machine specific support
61 67
62obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o 68obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index cc92a7b2db88..d264bbbd8bef 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,35 +1,16 @@
1/* linux/arch/arm/mach-bast/dma.c 1/* linux/arch/arm/mach-s3c2410/dma.c
2 * 2 *
3 * (c) 2003-2005 Simtec Electronics 3 * (c) 2003-2005,2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C2410 DMA core 6 * S3C2410 DMA core
7 * 7 *
8 * http://www.simtec.co.uk/products/EB2410ITX/ 8 * http://armlinux.simtec.co.uk/
9 * 9 *
10 * This program is free software; you can redistribute it and/or modify 10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as 11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13 * 13*/
14 * Changelog:
15 * 27-Feb-2005 BJD Added kmem cache for dma descriptors
16 * 18-Nov-2004 BJD Removed error for loading onto stopped channel
17 * 10-Nov-2004 BJD Ensure all external symbols exported for modules
18 * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
19 * 08-Aug-2004 BJD Apply rmk's suggestions
20 * 21-Jul-2004 BJD Ported to linux 2.6
21 * 12-Jul-2004 BJD Finished re-write and change of API
22 * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
23 * 23-May-2003 BJD Created file
24 * 19-Aug-2003 BJD Cleanup, header fix, added URL
25 *
26 * This file is based on the Sangwook Lee/Samsung patches, re-written due
27 * to various ommisions from the code (such as flexible dma configuration)
28 * for use with the BAST system board.
29 *
30 * The re-write is pretty much complete, and should be good enough for any
31 * possible DMA function
32 */
33 14
34 15
35#ifdef CONFIG_S3C2410_DMA_DEBUG 16#ifdef CONFIG_S3C2410_DMA_DEBUG
@@ -55,10 +36,14 @@
55#include <asm/mach/dma.h> 36#include <asm/mach/dma.h>
56#include <asm/arch/map.h> 37#include <asm/arch/map.h>
57 38
39#include "dma.h"
40
58/* io map for dma */ 41/* io map for dma */
59static void __iomem *dma_base; 42static void __iomem *dma_base;
60static kmem_cache_t *dma_kmem; 43static kmem_cache_t *dma_kmem;
61 44
45struct s3c24xx_dma_selection dma_sel;
46
62/* dma channel state information */ 47/* dma channel state information */
63struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; 48struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
64 49
@@ -79,7 +64,6 @@ dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
79 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); 64 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
80 writel(val, dma_regaddr(chan, reg)); 65 writel(val, dma_regaddr(chan, reg));
81} 66}
82
83#endif 67#endif
84 68
85#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) 69#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
@@ -151,12 +135,20 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
151#define dbg_showchan(chan) do { } while(0) 135#define dbg_showchan(chan) do { } while(0)
152#endif /* CONFIG_S3C2410_DMA_DEBUG */ 136#endif /* CONFIG_S3C2410_DMA_DEBUG */
153 137
154#define check_channel(chan) \ 138static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
155 do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
156 printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
157 return -EINVAL; \
158 } } while(0)
159 139
140/* lookup_dma_channel
141 *
142 * change the dma channel number given into a real dma channel id
143*/
144
145static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
146{
147 if (channel & DMACH_LOW_LEVEL)
148 return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
149 else
150 return dma_chan_map[channel];
151}
160 152
161/* s3c2410_dma_stats_timeout 153/* s3c2410_dma_stats_timeout
162 * 154 *
@@ -321,8 +313,10 @@ static inline void
321s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, 313s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
322 enum s3c2410_dma_buffresult result) 314 enum s3c2410_dma_buffresult result)
323{ 315{
316#if 0
324 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", 317 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
325 chan->callback_fn, buf, buf->id, buf->size, result); 318 chan->callback_fn, buf, buf->id, buf->size, result);
319#endif
326 320
327 if (chan->callback_fn != NULL) { 321 if (chan->callback_fn != NULL) {
328 (chan->callback_fn)(chan, buf->id, buf->size, result); 322 (chan->callback_fn)(chan, buf->id, buf->size, result);
@@ -439,7 +433,6 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
439 return 0; 433 return 0;
440} 434}
441 435
442
443/* s3c2410_dma_enqueue 436/* s3c2410_dma_enqueue
444 * 437 *
445 * queue an given buffer for dma transfer. 438 * queue an given buffer for dma transfer.
@@ -460,11 +453,12 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
460int s3c2410_dma_enqueue(unsigned int channel, void *id, 453int s3c2410_dma_enqueue(unsigned int channel, void *id,
461 dma_addr_t data, int size) 454 dma_addr_t data, int size)
462{ 455{
463 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 456 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
464 struct s3c2410_dma_buf *buf; 457 struct s3c2410_dma_buf *buf;
465 unsigned long flags; 458 unsigned long flags;
466 459
467 check_channel(channel); 460 if (chan == NULL)
461 return -EINVAL;
468 462
469 pr_debug("%s: id=%p, data=%08x, size=%d\n", 463 pr_debug("%s: id=%p, data=%08x, size=%d\n",
470 __FUNCTION__, id, (unsigned int)data, size); 464 __FUNCTION__, id, (unsigned int)data, size);
@@ -562,8 +556,10 @@ s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
562static inline void 556static inline void
563s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) 557s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
564{ 558{
559#if 0
565 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", 560 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
566 chan->number, chan->load_state); 561 chan->number, chan->load_state);
562#endif
567 563
568 switch (chan->load_state) { 564 switch (chan->load_state) {
569 case S3C2410_DMALOAD_NONE: 565 case S3C2410_DMALOAD_NONE:
@@ -718,7 +714,8 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
718 if (chan->load_state == S3C2410_DMALOAD_NONE) { 714 if (chan->load_state == S3C2410_DMALOAD_NONE) {
719 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", 715 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
720 chan->number, jiffies); 716 chan->number, jiffies);
721 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); 717 s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
718 S3C2410_DMAOP_STOP);
722 } 719 }
723 } 720 }
724 721
@@ -726,37 +723,34 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
726 return IRQ_HANDLED; 723 return IRQ_HANDLED;
727} 724}
728 725
726static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
727
729/* s3c2410_request_dma 728/* s3c2410_request_dma
730 * 729 *
731 * get control of an dma channel 730 * get control of an dma channel
732*/ 731*/
733 732
734int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client, 733int s3c2410_dma_request(unsigned int channel,
734 struct s3c2410_dma_client *client,
735 void *dev) 735 void *dev)
736{ 736{
737 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 737 struct s3c2410_dma_chan *chan;
738 unsigned long flags; 738 unsigned long flags;
739 int err; 739 int err;
740 740
741 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", 741 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
742 channel, client->name, dev); 742 channel, client->name, dev);
743 743
744 check_channel(channel);
745
746 local_irq_save(flags); 744 local_irq_save(flags);
747 745
748 dbg_showchan(chan); 746 chan = s3c2410_dma_map_channel(channel);
749 747 if (chan == NULL) {
750 if (chan->in_use) { 748 local_irq_restore(flags);
751 if (client != chan->client) { 749 return -EBUSY;
752 printk(KERN_ERR "dma%d: already in use\n", channel);
753 local_irq_restore(flags);
754 return -EBUSY;
755 } else {
756 printk(KERN_ERR "dma%d: client already has channel\n", channel);
757 }
758 } 750 }
759 751
752 dbg_showchan(chan);
753
760 chan->client = client; 754 chan->client = client;
761 chan->in_use = 1; 755 chan->in_use = 1;
762 756
@@ -809,14 +803,14 @@ EXPORT_SYMBOL(s3c2410_dma_request);
809 803
810int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) 804int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
811{ 805{
812 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 806 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
813 unsigned long flags; 807 unsigned long flags;
814 808
815 check_channel(channel); 809 if (chan == NULL)
810 return -EINVAL;
816 811
817 local_irq_save(flags); 812 local_irq_save(flags);
818 813
819
820 if (chan->client != client) { 814 if (chan->client != client) {
821 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", 815 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
822 channel, chan->client, client); 816 channel, chan->client, client);
@@ -837,8 +831,12 @@ int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
837 831
838 if (chan->irq_claimed) 832 if (chan->irq_claimed)
839 free_irq(chan->irq, (void *)chan); 833 free_irq(chan->irq, (void *)chan);
834
840 chan->irq_claimed = 0; 835 chan->irq_claimed = 0;
841 836
837 if (!(channel & DMACH_LOW_LEVEL))
838 dma_chan_map[channel] = NULL;
839
842 local_irq_restore(flags); 840 local_irq_restore(flags);
843 841
844 return 0; 842 return 0;
@@ -848,8 +846,8 @@ EXPORT_SYMBOL(s3c2410_dma_free);
848 846
849static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) 847static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
850{ 848{
851 unsigned long tmp;
852 unsigned long flags; 849 unsigned long flags;
850 unsigned long tmp;
853 851
854 pr_debug("%s:\n", __FUNCTION__); 852 pr_debug("%s:\n", __FUNCTION__);
855 853
@@ -997,9 +995,10 @@ s3c2410_dma_started(struct s3c2410_dma_chan *chan)
997int 995int
998s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op) 996s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
999{ 997{
1000 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 998 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1001 999
1002 check_channel(channel); 1000 if (chan == NULL)
1001 return -EINVAL;
1003 1002
1004 switch (op) { 1003 switch (op) {
1005 case S3C2410_DMAOP_START: 1004 case S3C2410_DMAOP_START:
@@ -1046,12 +1045,19 @@ int s3c2410_dma_config(dmach_t channel,
1046 int xferunit, 1045 int xferunit,
1047 int dcon) 1046 int dcon)
1048{ 1047{
1049 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1048 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1050 1049
1051 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", 1050 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
1052 __FUNCTION__, channel, xferunit, dcon); 1051 __FUNCTION__, channel, xferunit, dcon);
1053 1052
1054 check_channel(channel); 1053 if (chan == NULL)
1054 return -EINVAL;
1055
1056 printk("Initial dcon is %08x\n", dcon);
1057
1058 dcon |= chan->dcon & dma_sel.dcon_mask;
1059
1060 printk("New dcon is %08x\n", dcon);
1055 1061
1056 switch (xferunit) { 1062 switch (xferunit) {
1057 case 1: 1063 case 1:
@@ -1086,9 +1092,10 @@ EXPORT_SYMBOL(s3c2410_dma_config);
1086 1092
1087int s3c2410_dma_setflags(dmach_t channel, unsigned int flags) 1093int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
1088{ 1094{
1089 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1095 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1090 1096
1091 check_channel(channel); 1097 if (chan == NULL)
1098 return -EINVAL;
1092 1099
1093 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags); 1100 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
1094 1101
@@ -1106,9 +1113,10 @@ EXPORT_SYMBOL(s3c2410_dma_setflags);
1106 1113
1107int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn) 1114int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
1108{ 1115{
1109 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1116 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1110 1117
1111 check_channel(channel); 1118 if (chan == NULL)
1119 return -EINVAL;
1112 1120
1113 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn); 1121 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
1114 1122
@@ -1121,9 +1129,10 @@ EXPORT_SYMBOL(s3c2410_dma_set_opfn);
1121 1129
1122int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn) 1130int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
1123{ 1131{
1124 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1132 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1125 1133
1126 check_channel(channel); 1134 if (chan == NULL)
1135 return -EINVAL;
1127 1136
1128 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn); 1137 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1129 1138
@@ -1153,9 +1162,10 @@ int s3c2410_dma_devconfig(int channel,
1153 int hwcfg, 1162 int hwcfg,
1154 unsigned long devaddr) 1163 unsigned long devaddr)
1155{ 1164{
1156 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1165 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1157 1166
1158 check_channel(channel); 1167 if (chan == NULL)
1168 return -EINVAL;
1159 1169
1160 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n", 1170 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1161 __FUNCTION__, (int)source, hwcfg, devaddr); 1171 __FUNCTION__, (int)source, hwcfg, devaddr);
@@ -1200,9 +1210,10 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
1200 1210
1201int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst) 1211int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1202{ 1212{
1203 struct s3c2410_dma_chan *chan = &s3c2410_chans[channel]; 1213 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1204 1214
1205 check_channel(channel); 1215 if (chan == NULL)
1216 return -EINVAL;
1206 1217
1207 if (src != NULL) 1218 if (src != NULL)
1208 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC); 1219 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
@@ -1252,7 +1263,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
1252#define s3c2410_dma_resume NULL 1263#define s3c2410_dma_resume NULL
1253#endif /* CONFIG_PM */ 1264#endif /* CONFIG_PM */
1254 1265
1255static struct sysdev_class dma_sysclass = { 1266struct sysdev_class dma_sysclass = {
1256 set_kset_name("s3c24xx-dma"), 1267 set_kset_name("s3c24xx-dma"),
1257 .suspend = s3c2410_dma_suspend, 1268 .suspend = s3c2410_dma_suspend,
1258 .resume = s3c2410_dma_resume, 1269 .resume = s3c2410_dma_resume,
@@ -1265,7 +1276,6 @@ static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
1265 memset(p, 0, sizeof(struct s3c2410_dma_buf)); 1276 memset(p, 0, sizeof(struct s3c2410_dma_buf));
1266} 1277}
1267 1278
1268
1269/* initialisation code */ 1279/* initialisation code */
1270 1280
1271static int __init s3c2410_init_dma(void) 1281static int __init s3c2410_init_dma(void)
@@ -1274,7 +1284,7 @@ static int __init s3c2410_init_dma(void)
1274 int channel; 1284 int channel;
1275 int ret; 1285 int ret;
1276 1286
1277 printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n"); 1287 printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
1278 1288
1279 dma_base = ioremap(S3C24XX_PA_DMA, 0x200); 1289 dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
1280 if (dma_base == NULL) { 1290 if (dma_base == NULL) {
@@ -1282,6 +1292,8 @@ static int __init s3c2410_init_dma(void)
1282 return -ENOMEM; 1292 return -ENOMEM;
1283 } 1293 }
1284 1294
1295 printk("Registering sysclass\n");
1296
1285 ret = sysdev_class_register(&dma_sysclass); 1297 ret = sysdev_class_register(&dma_sysclass);
1286 if (ret != 0) { 1298 if (ret != 0) {
1287 printk(KERN_ERR "dma sysclass registration failed\n"); 1299 printk(KERN_ERR "dma sysclass registration failed\n");
@@ -1335,4 +1347,95 @@ static int __init s3c2410_init_dma(void)
1335 return ret; 1347 return ret;
1336} 1348}
1337 1349
1338__initcall(s3c2410_init_dma); 1350core_initcall(s3c2410_init_dma);
1351
1352static inline int is_channel_valid(unsigned int channel)
1353{
1354 return (channel & DMA_CH_VALID);
1355}
1356
1357/* s3c2410_dma_map_channel()
1358 *
1359 * turn the virtual channel number into a real, and un-used hardware
1360 * channel.
1361 *
1362 * currently this code uses first-free channel from the specified harware
1363 * map, not taking into account anything that the board setup code may
1364 * have to say about the likely peripheral set to be in use.
1365*/
1366
1367struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1368{
1369 struct s3c24xx_dma_map *ch_map;
1370 struct s3c2410_dma_chan *dmach;
1371 int ch;
1372
1373 if (dma_sel.map == NULL || channel > dma_sel.map_size)
1374 return NULL;
1375
1376 ch_map = dma_sel.map + channel;
1377
1378 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
1379 if (!is_channel_valid(ch_map->channels[ch]))
1380 continue;
1381
1382 if (s3c2410_chans[ch].in_use == 0) {
1383 printk("mapped channel %d to %d\n", channel, ch);
1384 break;
1385 }
1386 }
1387
1388 if (ch >= S3C2410_DMA_CHANNELS)
1389 return NULL;
1390
1391 /* update our channel mapping */
1392
1393 dmach = &s3c2410_chans[ch];
1394 dma_chan_map[channel] = dmach;
1395
1396 /* select the channel */
1397
1398 (dma_sel.select)(dmach, ch_map);
1399
1400 return dmach;
1401}
1402
1403static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
1404{
1405 /* show the channel configuration */
1406
1407 printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
1408 (is_channel_valid(map->channels[0]) ? '0' : '-'),
1409 (is_channel_valid(map->channels[1]) ? '1' : '-'),
1410 (is_channel_valid(map->channels[2]) ? '2' : '-'),
1411 (is_channel_valid(map->channels[3]) ? '3' : '-'));
1412}
1413
1414static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
1415{
1416 if (1)
1417 s3c24xx_dma_show_ch(map, ch);
1418
1419 return 0;
1420}
1421
1422int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
1423{
1424 struct s3c24xx_dma_map *nmap;
1425 size_t map_sz = sizeof(*nmap) * sel->map_size;
1426 int ptr;
1427
1428 nmap = kmalloc(map_sz, GFP_KERNEL);
1429 if (nmap == NULL)
1430 return -ENOMEM;
1431
1432 memcpy(nmap, sel->map, map_sz);
1433 memcpy(&dma_sel, sel, sizeof(*sel));
1434
1435 dma_sel.map = nmap;
1436
1437 for (ptr = 0; ptr < sel->map_size; ptr++)
1438 s3c24xx_dma_check_entry(nmap+ptr, ptr);
1439
1440 return 0;
1441}
diff --git a/arch/arm/mach-s3c2410/dma.h b/arch/arm/mach-s3c2410/dma.h
new file mode 100644
index 000000000000..0ebfe0aab80b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/dma.h
@@ -0,0 +1,45 @@
1/* arch/arm/mach-s3c2410/dma.h
2 *
3 * Copyright (C) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Samsung S3C24XX DMA support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13extern struct sysdev_class dma_sysclass;
14extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
15
16#define DMA_CH_VALID (1<<31)
17
18struct s3c24xx_dma_addr {
19 unsigned long from;
20 unsigned long to;
21};
22
23/* struct s3c24xx_dma_map
24 *
25 * this holds the mapping information for the channel selected
26 * to be connected to the specified device
27*/
28
29struct s3c24xx_dma_map {
30 const char *name;
31 struct s3c24xx_dma_addr hw_addr;
32
33 unsigned long channels[S3C2410_DMA_CHANNELS];
34};
35
36struct s3c24xx_dma_selection {
37 struct s3c24xx_dma_map *map;
38 unsigned long map_size;
39 unsigned long dcon_mask;
40
41 void (*select)(struct s3c2410_dma_chan *chan,
42 struct s3c24xx_dma_map *map);
43};
44
45extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
index 3661e465b0a5..166fc89d62d7 100644
--- a/include/asm-arm/arch-s3c2410/dma.h
+++ b/include/asm-arm/arch-s3c2410/dma.h
@@ -23,6 +23,36 @@
23#define MAX_DMA_ADDRESS 0x40000000 23#define MAX_DMA_ADDRESS 0x40000000
24#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */ 24#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
25 25
26/* We use `virtual` dma channels to hide the fact we have only a limited
27 * number of DMA channels, and not of all of them (dependant on the device)
28 * can be attached to any DMA source. We therefore let the DMA core handle
29 * the allocation of hardware channels to clients.
30*/
31
32enum dma_ch {
33 DMACH_XD0,
34 DMACH_XD1,
35 DMACH_SDI,
36 DMACH_SPI0,
37 DMACH_SPI1,
38 DMACH_UART0,
39 DMACH_UART1,
40 DMACH_UART2,
41 DMACH_TIMER,
42 DMACH_I2S_IN,
43 DMACH_I2S_OUT,
44 DMACH_PCM_IN,
45 DMACH_PCM_OUT,
46 DMACH_MIC_IN,
47 DMACH_USB_EP1,
48 DMACH_USB_EP2,
49 DMACH_USB_EP3,
50 DMACH_USB_EP4,
51 DMACH_MAX, /* the end entry */
52};
53
54#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
55
26/* we have 4 dma channels */ 56/* we have 4 dma channels */
27#define S3C2410_DMA_CHANNELS (4) 57#define S3C2410_DMA_CHANNELS (4)
28 58
@@ -149,6 +179,8 @@ struct s3c2410_dma_stats {
149 unsigned long timeout_failed; 179 unsigned long timeout_failed;
150}; 180};
151 181
182struct s3c2410_dma_map;
183
152/* struct s3c2410_dma_chan 184/* struct s3c2410_dma_chan
153 * 185 *
154 * full state information for each DMA channel 186 * full state information for each DMA channel
@@ -174,6 +206,8 @@ struct s3c2410_dma_chan {
174 unsigned long load_timeout; 206 unsigned long load_timeout;
175 unsigned int flags; /* channel flags */ 207 unsigned int flags; /* channel flags */
176 208
209 struct s3c24xx_dma_map *map; /* channel hw maps */
210
177 /* channel's hardware position and configuration */ 211 /* channel's hardware position and configuration */
178 void __iomem *regs; /* channels registers */ 212 void __iomem *regs; /* channels registers */
179 void __iomem *addr_reg; /* data address register */ 213 void __iomem *addr_reg; /* data address register */