aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2006-09-15 18:42:24 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-09-25 05:25:15 -0400
commit505788cccbb96cd496b646594c8a5fcdc26bc2d9 (patch)
tree9dbf59540c937cada2c5ae81e8459c50842374a3 /arch/arm/mach-s3c2410
parentfd88edd20fb0e8e2729aa8ce565316242189ceea (diff)
[ARM] 3796/1: S3C24XX: Add per-cpu DMA channel mapper
Allow each CPU type in the S3C24XX range to select the DMA channel mapping it supports. We change the DMA registration to use an virtual channel number that the DMA system will allocate to a hardware channel at request time. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-s3c2410')
-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
3 files changed, 223 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);