aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2008-01-28 07:01:20 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-01-28 08:20:50 -0500
commitc6709e8ef5752314c22c75bc7575f9be390e215b (patch)
treeb263b43370faf705141dfee1bd2d8300c00fe2c5
parent67d729adc0e76e21c82a2c59853f25f5f784ca79 (diff)
[ARM] 4780/1: S3C2412: Allow for seperate DMA channels for TX and RX
The current S3C24XX DMA code does not allow for an peripheral that has one channel for RX and another for TX. This patch adds a per-cpu dma operation to select the transmit or receive channel, and adds support to the S3C2412 for the seperate DMA channels for TX and RX. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-s3c2412/dma.c39
-rw-r--r--arch/arm/plat-s3c24xx/dma.c16
-rw-r--r--include/asm-arm/plat-s3c24xx/dma.h5
3 files changed, 54 insertions, 6 deletions
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index c9cd51439126..1dd864993566 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -40,106 +40,141 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
40 [DMACH_XD0] = { 40 [DMACH_XD0] = {
41 .name = "xdreq0", 41 .name = "xdreq0",
42 .channels = MAP(S3C2412_DMAREQSEL_XDREQ0), 42 .channels = MAP(S3C2412_DMAREQSEL_XDREQ0),
43 .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ0),
43 }, 44 },
44 [DMACH_XD1] = { 45 [DMACH_XD1] = {
45 .name = "xdreq1", 46 .name = "xdreq1",
46 .channels = MAP(S3C2412_DMAREQSEL_XDREQ1), 47 .channels = MAP(S3C2412_DMAREQSEL_XDREQ1),
48 .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ1),
47 }, 49 },
48 [DMACH_SDI] = { 50 [DMACH_SDI] = {
49 .name = "sdi", 51 .name = "sdi",
50 .channels = MAP(S3C2412_DMAREQSEL_SDI), 52 .channels = MAP(S3C2412_DMAREQSEL_SDI),
53 .channels_rx = MAP(S3C2412_DMAREQSEL_SDI),
51 .hw_addr.to = S3C2410_PA_SDI + S3C2410_SDIDATA, 54 .hw_addr.to = S3C2410_PA_SDI + S3C2410_SDIDATA,
52 .hw_addr.from = S3C2410_PA_SDI + S3C2410_SDIDATA, 55 .hw_addr.from = S3C2410_PA_SDI + S3C2410_SDIDATA,
53 }, 56 },
54 [DMACH_SPI0] = { 57 [DMACH_SPI0] = {
55 .name = "spi0", 58 .name = "spi0",
56 .channels = MAP(S3C2412_DMAREQSEL_SPI0TX), 59 .channels = MAP(S3C2412_DMAREQSEL_SPI0TX),
60 .channels_rx = MAP(S3C2412_DMAREQSEL_SPI0RX),
57 .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT, 61 .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
58 .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT, 62 .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
59 }, 63 },
60 [DMACH_SPI1] = { 64 [DMACH_SPI1] = {
61 .name = "spi1", 65 .name = "spi1",
62 .channels = MAP(S3C2412_DMAREQSEL_SPI1TX), 66 .channels = MAP(S3C2412_DMAREQSEL_SPI1TX),
67 .channels_rx = MAP(S3C2412_DMAREQSEL_SPI1RX),
63 .hw_addr.to = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT, 68 .hw_addr.to = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPTDAT,
64 .hw_addr.from = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPRDAT, 69 .hw_addr.from = S3C2410_PA_SPI + S3C2412_SPI1 + S3C2410_SPRDAT,
65 }, 70 },
66 [DMACH_UART0] = { 71 [DMACH_UART0] = {
67 .name = "uart0", 72 .name = "uart0",
68 .channels = MAP(S3C2412_DMAREQSEL_UART0_0), 73 .channels = MAP(S3C2412_DMAREQSEL_UART0_0),
74 .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_0),
69 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, 75 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
70 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, 76 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
71 }, 77 },
72 [DMACH_UART1] = { 78 [DMACH_UART1] = {
73 .name = "uart1", 79 .name = "uart1",
74 .channels = MAP(S3C2412_DMAREQSEL_UART1_0), 80 .channels = MAP(S3C2412_DMAREQSEL_UART1_0),
81 .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_0),
75 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, 82 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
76 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, 83 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
77 }, 84 },
78 [DMACH_UART2] = { 85 [DMACH_UART2] = {
79 .name = "uart2", 86 .name = "uart2",
80 .channels = MAP(S3C2412_DMAREQSEL_UART2_0), 87 .channels = MAP(S3C2412_DMAREQSEL_UART2_0),
88 .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_0),
81 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, 89 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
82 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, 90 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
83 }, 91 },
84 [DMACH_UART0_SRC2] = { 92 [DMACH_UART0_SRC2] = {
85 .name = "uart0", 93 .name = "uart0",
86 .channels = MAP(S3C2412_DMAREQSEL_UART0_1), 94 .channels = MAP(S3C2412_DMAREQSEL_UART0_1),
95 .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_1),
87 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH, 96 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
88 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH, 97 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
89 }, 98 },
90 [DMACH_UART1_SRC2] = { 99 [DMACH_UART1_SRC2] = {
91 .name = "uart1", 100 .name = "uart1",
92 .channels = MAP(S3C2412_DMAREQSEL_UART1_1), 101 .channels = MAP(S3C2412_DMAREQSEL_UART1_1),
102 .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_1),
93 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH, 103 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
94 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH, 104 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
95 }, 105 },
96 [DMACH_UART2_SRC2] = { 106 [DMACH_UART2_SRC2] = {
97 .name = "uart2", 107 .name = "uart2",
98 .channels = MAP(S3C2412_DMAREQSEL_UART2_1), 108 .channels = MAP(S3C2412_DMAREQSEL_UART2_1),
109 .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_1),
99 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH, 110 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
100 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH, 111 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
101 }, 112 },
102 [DMACH_TIMER] = { 113 [DMACH_TIMER] = {
103 .name = "timer", 114 .name = "timer",
104 .channels = MAP(S3C2412_DMAREQSEL_TIMER), 115 .channels = MAP(S3C2412_DMAREQSEL_TIMER),
116 .channels_rx = MAP(S3C2412_DMAREQSEL_TIMER),
105 }, 117 },
106 [DMACH_I2S_IN] = { 118 [DMACH_I2S_IN] = {
107 .name = "i2s-sdi", 119 .name = "i2s-sdi",
108 .channels = MAP(S3C2412_DMAREQSEL_I2SRX), 120 .channels = MAP(S3C2412_DMAREQSEL_I2SRX),
121 .channels_rx = MAP(S3C2412_DMAREQSEL_I2SRX),
109 .hw_addr.from = S3C2410_PA_IIS + S3C2412_IISRXD, 122 .hw_addr.from = S3C2410_PA_IIS + S3C2412_IISRXD,
110 }, 123 },
111 [DMACH_I2S_OUT] = { 124 [DMACH_I2S_OUT] = {
112 .name = "i2s-sdo", 125 .name = "i2s-sdo",
113 .channels = MAP(S3C2412_DMAREQSEL_I2STX), 126 .channels = MAP(S3C2412_DMAREQSEL_I2STX),
127 .channels_rx = MAP(S3C2412_DMAREQSEL_I2STX),
114 .hw_addr.to = S3C2410_PA_IIS + S3C2412_IISTXD, 128 .hw_addr.to = S3C2410_PA_IIS + S3C2412_IISTXD,
115 }, 129 },
116 [DMACH_USB_EP1] = { 130 [DMACH_USB_EP1] = {
117 .name = "usb-ep1", 131 .name = "usb-ep1",
118 .channels = MAP(S3C2412_DMAREQSEL_USBEP1), 132 .channels = MAP(S3C2412_DMAREQSEL_USBEP1),
133 .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP1),
119 }, 134 },
120 [DMACH_USB_EP2] = { 135 [DMACH_USB_EP2] = {
121 .name = "usb-ep2", 136 .name = "usb-ep2",
122 .channels = MAP(S3C2412_DMAREQSEL_USBEP2), 137 .channels = MAP(S3C2412_DMAREQSEL_USBEP2),
138 .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP2),
123 }, 139 },
124 [DMACH_USB_EP3] = { 140 [DMACH_USB_EP3] = {
125 .name = "usb-ep3", 141 .name = "usb-ep3",
126 .channels = MAP(S3C2412_DMAREQSEL_USBEP3), 142 .channels = MAP(S3C2412_DMAREQSEL_USBEP3),
143 .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP3),
127 }, 144 },
128 [DMACH_USB_EP4] = { 145 [DMACH_USB_EP4] = {
129 .name = "usb-ep4", 146 .name = "usb-ep4",
130 .channels = MAP(S3C2412_DMAREQSEL_USBEP4), 147 .channels = MAP(S3C2412_DMAREQSEL_USBEP4),
148 .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP4),
131 }, 149 },
132}; 150};
133 151
152static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
153 struct s3c24xx_dma_map *map,
154 enum s3c2410_dmasrc dir)
155{
156 unsigned long chsel;
157
158 if (dir == S3C2410_DMASRC_HW)
159 chsel = map->channels_rx[0];
160 else
161 chsel = map->channels[0];
162
163 chsel &= ~DMA_CH_VALID;
164 chsel |= S3C2412_DMAREQSEL_HW;
165
166 writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL);
167}
168
134static void s3c2412_dma_select(struct s3c2410_dma_chan *chan, 169static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
135 struct s3c24xx_dma_map *map) 170 struct s3c24xx_dma_map *map)
136{ 171{
137 writel(map->channels[0] | S3C2412_DMAREQSEL_HW, 172 s3c2412_dma_direction(chan, map, chan->source);
138 chan->regs + S3C2412_DMA_DMAREQSEL);
139} 173}
140 174
141static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { 175static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
142 .select = s3c2412_dma_select, 176 .select = s3c2412_dma_select,
177 .direction = s3c2412_dma_direction,
143 .dcon_mask = 0, 178 .dcon_mask = 0,
144 .map = s3c2412_dma_mappings, 179 .map = s3c2412_dma_mappings,
145 .map_size = ARRAY_SIZE(s3c2412_dma_mappings), 180 .map_size = ARRAY_SIZE(s3c2412_dma_mappings),
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index aae1b9cbaf44..10ef3995b114 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1184,7 +1184,7 @@ int s3c2410_dma_devconfig(int channel,
1184 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); 1184 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1185 1185
1186 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); 1186 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1187 return 0; 1187 break;
1188 1188
1189 case S3C2410_DMASRC_MEM: 1189 case S3C2410_DMASRC_MEM:
1190 /* source is memory */ 1190 /* source is memory */
@@ -1195,11 +1195,19 @@ int s3c2410_dma_devconfig(int channel,
1195 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); 1195 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1196 1196
1197 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); 1197 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1198 return 0; 1198 break;
1199
1200 default:
1201 printk(KERN_ERR "dma%d: invalid source type (%d)\n",
1202 channel, source);
1203
1204 return -EINVAL;
1199 } 1205 }
1200 1206
1201 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source); 1207 if (dma_sel.direction != NULL)
1202 return -EINVAL; 1208 (dma_sel.direction)(chan, chan->map, source);
1209
1210 return 0;
1203} 1211}
1204 1212
1205EXPORT_SYMBOL(s3c2410_dma_devconfig); 1213EXPORT_SYMBOL(s3c2410_dma_devconfig);
diff --git a/include/asm-arm/plat-s3c24xx/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
index 2c59406435e5..c78efe316fc8 100644
--- a/include/asm-arm/plat-s3c24xx/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -32,6 +32,7 @@ struct s3c24xx_dma_map {
32 struct s3c24xx_dma_addr hw_addr; 32 struct s3c24xx_dma_addr hw_addr;
33 33
34 unsigned long channels[S3C2410_DMA_CHANNELS]; 34 unsigned long channels[S3C2410_DMA_CHANNELS];
35 unsigned long channels_rx[S3C2410_DMA_CHANNELS];
35}; 36};
36 37
37struct s3c24xx_dma_selection { 38struct s3c24xx_dma_selection {
@@ -41,6 +42,10 @@ struct s3c24xx_dma_selection {
41 42
42 void (*select)(struct s3c2410_dma_chan *chan, 43 void (*select)(struct s3c2410_dma_chan *chan,
43 struct s3c24xx_dma_map *map); 44 struct s3c24xx_dma_map *map);
45
46 void (*direction)(struct s3c2410_dma_chan *chan,
47 struct s3c24xx_dma_map *map,
48 enum s3c2410_dmasrc dir);
44}; 49};
45 50
46extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel); 51extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);