diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-05-08 21:29:27 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2009-05-08 21:29:27 -0400 |
commit | d585a021c0b10b0477d6b608c53e1feb8cde0507 (patch) | |
tree | 5ca059da1db7f15d4b29427644ad9c08270c885c /arch/arm/mach-ep93xx | |
parent | 84e5b0d00f8f84c4ae226be131d4bebbcee88bd3 (diff) | |
parent | 091bf7624d1c90cec9e578a18529f615213ff847 (diff) |
Merge commit 'v2.6.30-rc5' into next
Diffstat (limited to 'arch/arm/mach-ep93xx')
-rw-r--r-- | arch/arm/mach-ep93xx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/clock.c | 79 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/core.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/dma-m2p.c | 408 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/edb9307a.c | 12 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/dma.h | 52 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/platform.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-ep93xx/include/mach/system.h | 2 |
9 files changed, 558 insertions, 4 deletions
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index 944e42d51646..9522e205b73f 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
3 | # | 3 | # |
4 | obj-y := core.o clock.o gpio.o | 4 | obj-y := core.o clock.o dma-m2p.o gpio.o |
5 | obj-m := | 5 | obj-m := |
6 | obj-n := | 6 | obj-n := |
7 | obj- := | 7 | obj- := |
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 96049283a10a..e8ebeaea6c48 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c | |||
@@ -41,6 +41,56 @@ static struct clk clk_usb_host = { | |||
41 | .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, | 41 | .enable_mask = EP93XX_SYSCON_CLOCK_USH_EN, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | /* DMA Clocks */ | ||
45 | static struct clk clk_m2p0 = { | ||
46 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
47 | .enable_mask = 0x00020000, | ||
48 | }; | ||
49 | static struct clk clk_m2p1 = { | ||
50 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
51 | .enable_mask = 0x00010000, | ||
52 | }; | ||
53 | static struct clk clk_m2p2 = { | ||
54 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
55 | .enable_mask = 0x00080000, | ||
56 | }; | ||
57 | static struct clk clk_m2p3 = { | ||
58 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
59 | .enable_mask = 0x00040000, | ||
60 | }; | ||
61 | static struct clk clk_m2p4 = { | ||
62 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
63 | .enable_mask = 0x00200000, | ||
64 | }; | ||
65 | static struct clk clk_m2p5 = { | ||
66 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
67 | .enable_mask = 0x00100000, | ||
68 | }; | ||
69 | static struct clk clk_m2p6 = { | ||
70 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
71 | .enable_mask = 0x00800000, | ||
72 | }; | ||
73 | static struct clk clk_m2p7 = { | ||
74 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
75 | .enable_mask = 0x00400000, | ||
76 | }; | ||
77 | static struct clk clk_m2p8 = { | ||
78 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
79 | .enable_mask = 0x02000000, | ||
80 | }; | ||
81 | static struct clk clk_m2p9 = { | ||
82 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
83 | .enable_mask = 0x01000000, | ||
84 | }; | ||
85 | static struct clk clk_m2m0 = { | ||
86 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
87 | .enable_mask = 0x04000000, | ||
88 | }; | ||
89 | static struct clk clk_m2m1 = { | ||
90 | .enable_reg = EP93XX_SYSCON_CLOCK_CONTROL, | ||
91 | .enable_mask = 0x08000000, | ||
92 | }; | ||
93 | |||
44 | #define INIT_CK(dev,con,ck) \ | 94 | #define INIT_CK(dev,con,ck) \ |
45 | { .dev_id = dev, .con_id = con, .clk = ck } | 95 | { .dev_id = dev, .con_id = con, .clk = ck } |
46 | 96 | ||
@@ -54,6 +104,18 @@ static struct clk_lookup clocks[] = { | |||
54 | INIT_CK(NULL, "pclk", &clk_p), | 104 | INIT_CK(NULL, "pclk", &clk_p), |
55 | INIT_CK(NULL, "pll2", &clk_pll2), | 105 | INIT_CK(NULL, "pll2", &clk_pll2), |
56 | INIT_CK(NULL, "usb_host", &clk_usb_host), | 106 | INIT_CK(NULL, "usb_host", &clk_usb_host), |
107 | INIT_CK(NULL, "m2p0", &clk_m2p0), | ||
108 | INIT_CK(NULL, "m2p1", &clk_m2p1), | ||
109 | INIT_CK(NULL, "m2p2", &clk_m2p2), | ||
110 | INIT_CK(NULL, "m2p3", &clk_m2p3), | ||
111 | INIT_CK(NULL, "m2p4", &clk_m2p4), | ||
112 | INIT_CK(NULL, "m2p5", &clk_m2p5), | ||
113 | INIT_CK(NULL, "m2p6", &clk_m2p6), | ||
114 | INIT_CK(NULL, "m2p7", &clk_m2p7), | ||
115 | INIT_CK(NULL, "m2p8", &clk_m2p8), | ||
116 | INIT_CK(NULL, "m2p9", &clk_m2p9), | ||
117 | INIT_CK(NULL, "m2m0", &clk_m2m0), | ||
118 | INIT_CK(NULL, "m2m1", &clk_m2m1), | ||
57 | }; | 119 | }; |
58 | 120 | ||
59 | 121 | ||
@@ -110,6 +172,22 @@ static unsigned long calc_pll_rate(u32 config_word) | |||
110 | return (unsigned long)rate; | 172 | return (unsigned long)rate; |
111 | } | 173 | } |
112 | 174 | ||
175 | static void __init ep93xx_dma_clock_init(void) | ||
176 | { | ||
177 | clk_m2p0.rate = clk_h.rate; | ||
178 | clk_m2p1.rate = clk_h.rate; | ||
179 | clk_m2p2.rate = clk_h.rate; | ||
180 | clk_m2p3.rate = clk_h.rate; | ||
181 | clk_m2p4.rate = clk_h.rate; | ||
182 | clk_m2p5.rate = clk_h.rate; | ||
183 | clk_m2p6.rate = clk_h.rate; | ||
184 | clk_m2p7.rate = clk_h.rate; | ||
185 | clk_m2p8.rate = clk_h.rate; | ||
186 | clk_m2p9.rate = clk_h.rate; | ||
187 | clk_m2m0.rate = clk_h.rate; | ||
188 | clk_m2m1.rate = clk_h.rate; | ||
189 | } | ||
190 | |||
113 | static int __init ep93xx_clock_init(void) | 191 | static int __init ep93xx_clock_init(void) |
114 | { | 192 | { |
115 | u32 value; | 193 | u32 value; |
@@ -124,6 +202,7 @@ static int __init ep93xx_clock_init(void) | |||
124 | clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; | 202 | clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; |
125 | clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; | 203 | clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; |
126 | clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; | 204 | clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; |
205 | ep93xx_dma_clock_init(); | ||
127 | 206 | ||
128 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); | 207 | value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2); |
129 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ | 208 | if (!(value & 0x00080000)) { /* PLL2 bypassed? */ |
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 6d9152de6074..ae24486f858a 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c | |||
@@ -100,7 +100,7 @@ static unsigned int last_jiffy_time; | |||
100 | 100 | ||
101 | #define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) | 101 | #define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ) |
102 | 102 | ||
103 | static int ep93xx_timer_interrupt(int irq, void *dev_id) | 103 | static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id) |
104 | { | 104 | { |
105 | __raw_writel(1, EP93XX_TIMER1_CLEAR); | 105 | __raw_writel(1, EP93XX_TIMER1_CLEAR); |
106 | while ((signed long) | 106 | while ((signed long) |
diff --git a/arch/arm/mach-ep93xx/dma-m2p.c b/arch/arm/mach-ep93xx/dma-m2p.c new file mode 100644 index 000000000000..a2df5bb7dff0 --- /dev/null +++ b/arch/arm/mach-ep93xx/dma-m2p.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-ep93xx/dma-m2p.c | ||
3 | * M2P DMA handling for Cirrus EP93xx chips. | ||
4 | * | ||
5 | * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> | ||
6 | * Copyright (C) 2006 Applied Data Systems | ||
7 | * | ||
8 | * Copyright (C) 2009 Ryan Mallon <ryan@bluewatersys.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or (at | ||
13 | * your option) any later version. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * On the EP93xx chip the following peripherals my be allocated to the 10 | ||
18 | * Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive). | ||
19 | * | ||
20 | * I2S contains 3 Tx and 3 Rx DMA Channels | ||
21 | * AAC contains 3 Tx and 3 Rx DMA Channels | ||
22 | * UART1 contains 1 Tx and 1 Rx DMA Channels | ||
23 | * UART2 contains 1 Tx and 1 Rx DMA Channels | ||
24 | * UART3 contains 1 Tx and 1 Rx DMA Channels | ||
25 | * IrDA contains 1 Tx and 1 Rx DMA Channels | ||
26 | * | ||
27 | * SSP and IDE use the Memory to Memory (M2M) channels and are not covered | ||
28 | * with this implementation. | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/clk.h> | ||
33 | #include <linux/err.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/module.h> | ||
36 | |||
37 | #include <mach/dma.h> | ||
38 | #include <mach/hardware.h> | ||
39 | |||
40 | #define M2P_CONTROL 0x00 | ||
41 | #define M2P_CONTROL_STALL_IRQ_EN (1 << 0) | ||
42 | #define M2P_CONTROL_NFB_IRQ_EN (1 << 1) | ||
43 | #define M2P_CONTROL_ERROR_IRQ_EN (1 << 3) | ||
44 | #define M2P_CONTROL_ENABLE (1 << 4) | ||
45 | #define M2P_INTERRUPT 0x04 | ||
46 | #define M2P_INTERRUPT_STALL (1 << 0) | ||
47 | #define M2P_INTERRUPT_NFB (1 << 1) | ||
48 | #define M2P_INTERRUPT_ERROR (1 << 3) | ||
49 | #define M2P_PPALLOC 0x08 | ||
50 | #define M2P_STATUS 0x0c | ||
51 | #define M2P_REMAIN 0x14 | ||
52 | #define M2P_MAXCNT0 0x20 | ||
53 | #define M2P_BASE0 0x24 | ||
54 | #define M2P_MAXCNT1 0x30 | ||
55 | #define M2P_BASE1 0x34 | ||
56 | |||
57 | #define STATE_IDLE 0 /* Channel is inactive. */ | ||
58 | #define STATE_STALL 1 /* Channel is active, no buffers pending. */ | ||
59 | #define STATE_ON 2 /* Channel is active, one buffer pending. */ | ||
60 | #define STATE_NEXT 3 /* Channel is active, two buffers pending. */ | ||
61 | |||
62 | struct m2p_channel { | ||
63 | char *name; | ||
64 | void __iomem *base; | ||
65 | int irq; | ||
66 | |||
67 | struct clk *clk; | ||
68 | spinlock_t lock; | ||
69 | |||
70 | void *client; | ||
71 | unsigned next_slot:1; | ||
72 | struct ep93xx_dma_buffer *buffer_xfer; | ||
73 | struct ep93xx_dma_buffer *buffer_next; | ||
74 | struct list_head buffers_pending; | ||
75 | }; | ||
76 | |||
77 | static struct m2p_channel m2p_rx[] = { | ||
78 | {"m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1}, | ||
79 | {"m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3}, | ||
80 | {"m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5}, | ||
81 | {"m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7}, | ||
82 | {"m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9}, | ||
83 | {NULL}, | ||
84 | }; | ||
85 | |||
86 | static struct m2p_channel m2p_tx[] = { | ||
87 | {"m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0}, | ||
88 | {"m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2}, | ||
89 | {"m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4}, | ||
90 | {"m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6}, | ||
91 | {"m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8}, | ||
92 | {NULL}, | ||
93 | }; | ||
94 | |||
95 | static void feed_buf(struct m2p_channel *ch, struct ep93xx_dma_buffer *buf) | ||
96 | { | ||
97 | if (ch->next_slot == 0) { | ||
98 | writel(buf->size, ch->base + M2P_MAXCNT0); | ||
99 | writel(buf->bus_addr, ch->base + M2P_BASE0); | ||
100 | } else { | ||
101 | writel(buf->size, ch->base + M2P_MAXCNT1); | ||
102 | writel(buf->bus_addr, ch->base + M2P_BASE1); | ||
103 | } | ||
104 | ch->next_slot ^= 1; | ||
105 | } | ||
106 | |||
107 | static void choose_buffer_xfer(struct m2p_channel *ch) | ||
108 | { | ||
109 | struct ep93xx_dma_buffer *buf; | ||
110 | |||
111 | ch->buffer_xfer = NULL; | ||
112 | if (!list_empty(&ch->buffers_pending)) { | ||
113 | buf = list_entry(ch->buffers_pending.next, | ||
114 | struct ep93xx_dma_buffer, list); | ||
115 | list_del(&buf->list); | ||
116 | feed_buf(ch, buf); | ||
117 | ch->buffer_xfer = buf; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static void choose_buffer_next(struct m2p_channel *ch) | ||
122 | { | ||
123 | struct ep93xx_dma_buffer *buf; | ||
124 | |||
125 | ch->buffer_next = NULL; | ||
126 | if (!list_empty(&ch->buffers_pending)) { | ||
127 | buf = list_entry(ch->buffers_pending.next, | ||
128 | struct ep93xx_dma_buffer, list); | ||
129 | list_del(&buf->list); | ||
130 | feed_buf(ch, buf); | ||
131 | ch->buffer_next = buf; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static inline void m2p_set_control(struct m2p_channel *ch, u32 v) | ||
136 | { | ||
137 | /* | ||
138 | * The control register must be read immediately after being written so | ||
139 | * that the internal state machine is correctly updated. See the ep93xx | ||
140 | * users' guide for details. | ||
141 | */ | ||
142 | writel(v, ch->base + M2P_CONTROL); | ||
143 | readl(ch->base + M2P_CONTROL); | ||
144 | } | ||
145 | |||
146 | static inline int m2p_channel_state(struct m2p_channel *ch) | ||
147 | { | ||
148 | return (readl(ch->base + M2P_STATUS) >> 4) & 0x3; | ||
149 | } | ||
150 | |||
151 | static irqreturn_t m2p_irq(int irq, void *dev_id) | ||
152 | { | ||
153 | struct m2p_channel *ch = dev_id; | ||
154 | struct ep93xx_dma_m2p_client *cl; | ||
155 | u32 irq_status, v; | ||
156 | int error = 0; | ||
157 | |||
158 | cl = ch->client; | ||
159 | |||
160 | spin_lock(&ch->lock); | ||
161 | irq_status = readl(ch->base + M2P_INTERRUPT); | ||
162 | |||
163 | if (irq_status & M2P_INTERRUPT_ERROR) { | ||
164 | writel(M2P_INTERRUPT_ERROR, ch->base + M2P_INTERRUPT); | ||
165 | error = 1; | ||
166 | } | ||
167 | |||
168 | if ((irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)) == 0) { | ||
169 | spin_unlock(&ch->lock); | ||
170 | return IRQ_NONE; | ||
171 | } | ||
172 | |||
173 | switch (m2p_channel_state(ch)) { | ||
174 | case STATE_IDLE: | ||
175 | pr_crit("m2p_irq: dma interrupt without a dma buffer\n"); | ||
176 | BUG(); | ||
177 | break; | ||
178 | |||
179 | case STATE_STALL: | ||
180 | cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error); | ||
181 | if (ch->buffer_next != NULL) { | ||
182 | cl->buffer_finished(cl->cookie, ch->buffer_next, | ||
183 | 0, error); | ||
184 | } | ||
185 | choose_buffer_xfer(ch); | ||
186 | choose_buffer_next(ch); | ||
187 | if (ch->buffer_xfer != NULL) | ||
188 | cl->buffer_started(cl->cookie, ch->buffer_xfer); | ||
189 | break; | ||
190 | |||
191 | case STATE_ON: | ||
192 | cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error); | ||
193 | ch->buffer_xfer = ch->buffer_next; | ||
194 | choose_buffer_next(ch); | ||
195 | cl->buffer_started(cl->cookie, ch->buffer_xfer); | ||
196 | break; | ||
197 | |||
198 | case STATE_NEXT: | ||
199 | pr_crit("m2p_irq: dma interrupt while next\n"); | ||
200 | BUG(); | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | v = readl(ch->base + M2P_CONTROL) & ~(M2P_CONTROL_STALL_IRQ_EN | | ||
205 | M2P_CONTROL_NFB_IRQ_EN); | ||
206 | if (ch->buffer_xfer != NULL) | ||
207 | v |= M2P_CONTROL_STALL_IRQ_EN; | ||
208 | if (ch->buffer_next != NULL) | ||
209 | v |= M2P_CONTROL_NFB_IRQ_EN; | ||
210 | m2p_set_control(ch, v); | ||
211 | |||
212 | spin_unlock(&ch->lock); | ||
213 | return IRQ_HANDLED; | ||
214 | } | ||
215 | |||
216 | static struct m2p_channel *find_free_channel(struct ep93xx_dma_m2p_client *cl) | ||
217 | { | ||
218 | struct m2p_channel *ch; | ||
219 | int i; | ||
220 | |||
221 | if (cl->flags & EP93XX_DMA_M2P_RX) | ||
222 | ch = m2p_rx; | ||
223 | else | ||
224 | ch = m2p_tx; | ||
225 | |||
226 | for (i = 0; ch[i].base; i++) { | ||
227 | struct ep93xx_dma_m2p_client *client; | ||
228 | |||
229 | client = ch[i].client; | ||
230 | if (client != NULL) { | ||
231 | int port; | ||
232 | |||
233 | port = cl->flags & EP93XX_DMA_M2P_PORT_MASK; | ||
234 | if (port == (client->flags & | ||
235 | EP93XX_DMA_M2P_PORT_MASK)) { | ||
236 | pr_warning("DMA channel already used by %s\n", | ||
237 | cl->name ? : "unknown client"); | ||
238 | return ERR_PTR(-EBUSY); | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | |||
243 | for (i = 0; ch[i].base; i++) { | ||
244 | if (ch[i].client == NULL) | ||
245 | return ch + i; | ||
246 | } | ||
247 | |||
248 | pr_warning("No free DMA channel for %s\n", | ||
249 | cl->name ? : "unknown client"); | ||
250 | return ERR_PTR(-ENODEV); | ||
251 | } | ||
252 | |||
253 | static void channel_enable(struct m2p_channel *ch) | ||
254 | { | ||
255 | struct ep93xx_dma_m2p_client *cl = ch->client; | ||
256 | u32 v; | ||
257 | |||
258 | clk_enable(ch->clk); | ||
259 | |||
260 | v = cl->flags & EP93XX_DMA_M2P_PORT_MASK; | ||
261 | writel(v, ch->base + M2P_PPALLOC); | ||
262 | |||
263 | v = cl->flags & EP93XX_DMA_M2P_ERROR_MASK; | ||
264 | v |= M2P_CONTROL_ENABLE | M2P_CONTROL_ERROR_IRQ_EN; | ||
265 | m2p_set_control(ch, v); | ||
266 | } | ||
267 | |||
268 | static void channel_disable(struct m2p_channel *ch) | ||
269 | { | ||
270 | u32 v; | ||
271 | |||
272 | v = readl(ch->base + M2P_CONTROL); | ||
273 | v &= ~(M2P_CONTROL_STALL_IRQ_EN | M2P_CONTROL_NFB_IRQ_EN); | ||
274 | m2p_set_control(ch, v); | ||
275 | |||
276 | while (m2p_channel_state(ch) == STATE_ON) | ||
277 | cpu_relax(); | ||
278 | |||
279 | m2p_set_control(ch, 0x0); | ||
280 | |||
281 | while (m2p_channel_state(ch) == STATE_STALL) | ||
282 | cpu_relax(); | ||
283 | |||
284 | clk_disable(ch->clk); | ||
285 | } | ||
286 | |||
287 | int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *cl) | ||
288 | { | ||
289 | struct m2p_channel *ch; | ||
290 | int err; | ||
291 | |||
292 | ch = find_free_channel(cl); | ||
293 | if (IS_ERR(ch)) | ||
294 | return PTR_ERR(ch); | ||
295 | |||
296 | err = request_irq(ch->irq, m2p_irq, 0, cl->name ? : "dma-m2p", ch); | ||
297 | if (err) | ||
298 | return err; | ||
299 | |||
300 | ch->client = cl; | ||
301 | ch->next_slot = 0; | ||
302 | ch->buffer_xfer = NULL; | ||
303 | ch->buffer_next = NULL; | ||
304 | INIT_LIST_HEAD(&ch->buffers_pending); | ||
305 | |||
306 | cl->channel = ch; | ||
307 | |||
308 | channel_enable(ch); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_register); | ||
313 | |||
314 | void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *cl) | ||
315 | { | ||
316 | struct m2p_channel *ch = cl->channel; | ||
317 | |||
318 | channel_disable(ch); | ||
319 | free_irq(ch->irq, ch); | ||
320 | ch->client = NULL; | ||
321 | } | ||
322 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_unregister); | ||
323 | |||
324 | void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *cl, | ||
325 | struct ep93xx_dma_buffer *buf) | ||
326 | { | ||
327 | struct m2p_channel *ch = cl->channel; | ||
328 | unsigned long flags; | ||
329 | u32 v; | ||
330 | |||
331 | spin_lock_irqsave(&ch->lock, flags); | ||
332 | v = readl(ch->base + M2P_CONTROL); | ||
333 | if (ch->buffer_xfer == NULL) { | ||
334 | ch->buffer_xfer = buf; | ||
335 | feed_buf(ch, buf); | ||
336 | cl->buffer_started(cl->cookie, buf); | ||
337 | |||
338 | v |= M2P_CONTROL_STALL_IRQ_EN; | ||
339 | m2p_set_control(ch, v); | ||
340 | |||
341 | } else if (ch->buffer_next == NULL) { | ||
342 | ch->buffer_next = buf; | ||
343 | feed_buf(ch, buf); | ||
344 | |||
345 | v |= M2P_CONTROL_NFB_IRQ_EN; | ||
346 | m2p_set_control(ch, v); | ||
347 | } else { | ||
348 | list_add_tail(&buf->list, &ch->buffers_pending); | ||
349 | } | ||
350 | spin_unlock_irqrestore(&ch->lock, flags); | ||
351 | } | ||
352 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit); | ||
353 | |||
354 | void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *cl, | ||
355 | struct ep93xx_dma_buffer *buf) | ||
356 | { | ||
357 | struct m2p_channel *ch = cl->channel; | ||
358 | |||
359 | list_add_tail(&buf->list, &ch->buffers_pending); | ||
360 | } | ||
361 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit_recursive); | ||
362 | |||
363 | void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *cl) | ||
364 | { | ||
365 | struct m2p_channel *ch = cl->channel; | ||
366 | |||
367 | channel_disable(ch); | ||
368 | ch->next_slot = 0; | ||
369 | ch->buffer_xfer = NULL; | ||
370 | ch->buffer_next = NULL; | ||
371 | INIT_LIST_HEAD(&ch->buffers_pending); | ||
372 | channel_enable(ch); | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_flush); | ||
375 | |||
376 | static int init_channel(struct m2p_channel *ch) | ||
377 | { | ||
378 | ch->clk = clk_get(NULL, ch->name); | ||
379 | if (IS_ERR(ch->clk)) | ||
380 | return PTR_ERR(ch->clk); | ||
381 | |||
382 | spin_lock_init(&ch->lock); | ||
383 | ch->client = NULL; | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int __init ep93xx_dma_m2p_init(void) | ||
389 | { | ||
390 | int i; | ||
391 | int ret; | ||
392 | |||
393 | for (i = 0; m2p_rx[i].base; i++) { | ||
394 | ret = init_channel(m2p_rx + i); | ||
395 | if (ret) | ||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | for (i = 0; m2p_tx[i].base; i++) { | ||
400 | ret = init_channel(m2p_tx + i); | ||
401 | if (ret) | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | pr_info("M2P DMA subsystem initialized\n"); | ||
406 | return 0; | ||
407 | } | ||
408 | arch_initcall(ep93xx_dma_m2p_init); | ||
diff --git a/arch/arm/mach-ep93xx/edb9307a.c b/arch/arm/mach-ep93xx/edb9307a.c index 5b5c22b681be..6171167d3315 100644 --- a/arch/arm/mach-ep93xx/edb9307a.c +++ b/arch/arm/mach-ep93xx/edb9307a.c | |||
@@ -48,12 +48,24 @@ static struct ep93xx_eth_data edb9307a_eth_data = { | |||
48 | .phy_id = 1, | 48 | .phy_id = 1, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static struct i2c_board_info __initdata edb9307a_i2c_data[] = { | ||
52 | { | ||
53 | /* On-board battery backed RTC */ | ||
54 | I2C_BOARD_INFO("isl1208", 0x6f), | ||
55 | }, | ||
56 | /* | ||
57 | * The I2C signals are also routed to the Expansion Connector (J4) | ||
58 | */ | ||
59 | }; | ||
60 | |||
51 | static void __init edb9307a_init_machine(void) | 61 | static void __init edb9307a_init_machine(void) |
52 | { | 62 | { |
53 | ep93xx_init_devices(); | 63 | ep93xx_init_devices(); |
54 | platform_device_register(&edb9307a_flash); | 64 | platform_device_register(&edb9307a_flash); |
55 | 65 | ||
56 | ep93xx_register_eth(&edb9307a_eth_data, 1); | 66 | ep93xx_register_eth(&edb9307a_eth_data, 1); |
67 | |||
68 | ep93xx_init_i2c(edb9307a_i2c_data, ARRAY_SIZE(edb9307a_i2c_data)); | ||
57 | } | 69 | } |
58 | 70 | ||
59 | MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") | 71 | MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board") |
diff --git a/arch/arm/mach-ep93xx/include/mach/dma.h b/arch/arm/mach-ep93xx/include/mach/dma.h new file mode 100644 index 000000000000..ef6bd9d13148 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/dma.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifndef __ASM_ARCH_DMA_H | ||
2 | #define __ASM_ARCH_DMA_H | ||
3 | |||
4 | #include <linux/list.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | struct ep93xx_dma_buffer { | ||
8 | struct list_head list; | ||
9 | u32 bus_addr; | ||
10 | u16 size; | ||
11 | }; | ||
12 | |||
13 | struct ep93xx_dma_m2p_client { | ||
14 | char *name; | ||
15 | u8 flags; | ||
16 | void *cookie; | ||
17 | void (*buffer_started)(void *cookie, | ||
18 | struct ep93xx_dma_buffer *buf); | ||
19 | void (*buffer_finished)(void *cookie, | ||
20 | struct ep93xx_dma_buffer *buf, | ||
21 | int bytes, int error); | ||
22 | |||
23 | /* Internal to the DMA code. */ | ||
24 | void *channel; | ||
25 | }; | ||
26 | |||
27 | #define EP93XX_DMA_M2P_PORT_I2S1 0x00 | ||
28 | #define EP93XX_DMA_M2P_PORT_I2S2 0x01 | ||
29 | #define EP93XX_DMA_M2P_PORT_AAC1 0x02 | ||
30 | #define EP93XX_DMA_M2P_PORT_AAC2 0x03 | ||
31 | #define EP93XX_DMA_M2P_PORT_AAC3 0x04 | ||
32 | #define EP93XX_DMA_M2P_PORT_I2S3 0x05 | ||
33 | #define EP93XX_DMA_M2P_PORT_UART1 0x06 | ||
34 | #define EP93XX_DMA_M2P_PORT_UART2 0x07 | ||
35 | #define EP93XX_DMA_M2P_PORT_UART3 0x08 | ||
36 | #define EP93XX_DMA_M2P_PORT_IRDA 0x09 | ||
37 | #define EP93XX_DMA_M2P_PORT_MASK 0x0f | ||
38 | #define EP93XX_DMA_M2P_TX 0x00 | ||
39 | #define EP93XX_DMA_M2P_RX 0x10 | ||
40 | #define EP93XX_DMA_M2P_ABORT_ON_ERROR 0x20 | ||
41 | #define EP93XX_DMA_M2P_IGNORE_ERROR 0x40 | ||
42 | #define EP93XX_DMA_M2P_ERROR_MASK 0x60 | ||
43 | |||
44 | int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p); | ||
45 | void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *m2p); | ||
46 | void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *m2p, | ||
47 | struct ep93xx_dma_buffer *buf); | ||
48 | void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *m2p, | ||
49 | struct ep93xx_dma_buffer *buf); | ||
50 | void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *m2p); | ||
51 | |||
52 | #endif /* __ASM_ARCH_DMA_H */ | ||
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h index 22d6c9a6e4ca..f66be12b856e 100644 --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h | |||
@@ -58,7 +58,8 @@ | |||
58 | 58 | ||
59 | 59 | ||
60 | /* AHB peripherals */ | 60 | /* AHB peripherals */ |
61 | #define EP93XX_DMA_BASE (EP93XX_AHB_VIRT_BASE + 0x00000000) | 61 | #define EP93XX_DMA_BASE ((void __iomem *) \ |
62 | (EP93XX_AHB_VIRT_BASE + 0x00000000)) | ||
62 | 63 | ||
63 | #define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000) | 64 | #define EP93XX_ETHERNET_BASE (EP93XX_AHB_VIRT_BASE + 0x00010000) |
64 | #define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000) | 65 | #define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000) |
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h index 88f7e88f152f..05f0f4f2f3ce 100644 --- a/arch/arm/mach-ep93xx/include/mach/platform.h +++ b/arch/arm/mach-ep93xx/include/mach/platform.h | |||
@@ -4,6 +4,8 @@ | |||
4 | 4 | ||
5 | #ifndef __ASSEMBLY__ | 5 | #ifndef __ASSEMBLY__ |
6 | 6 | ||
7 | struct i2c_board_info; | ||
8 | |||
7 | struct ep93xx_eth_data | 9 | struct ep93xx_eth_data |
8 | { | 10 | { |
9 | unsigned char dev_addr[6]; | 11 | unsigned char dev_addr[6]; |
diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h index 67789d0f329e..ed8f35e4f068 100644 --- a/arch/arm/mach-ep93xx/include/mach/system.h +++ b/arch/arm/mach-ep93xx/include/mach/system.h | |||
@@ -9,7 +9,7 @@ static inline void arch_idle(void) | |||
9 | cpu_do_idle(); | 9 | cpu_do_idle(); |
10 | } | 10 | } |
11 | 11 | ||
12 | static inline void arch_reset(char mode) | 12 | static inline void arch_reset(char mode, const char *cmd) |
13 | { | 13 | { |
14 | u32 devicecfg; | 14 | u32 devicecfg; |
15 | 15 | ||