diff options
author | Mikael Starvik <mikael.starvik@axis.com> | 2005-07-27 14:44:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-27 19:26:00 -0400 |
commit | 63245d2cde2be64f172388c2c50862f233c05700 (patch) | |
tree | c5f41dca80044bf4820e9c65eaa9844eb89493f6 /arch/cris | |
parent | 7e9204265b4ec6680fad9abc7a78b94087983916 (diff) |
[PATCH] CRIS update: I/O and DMA allocator
Added I/O and DMA allocators to be used by drivers.
Signed-off-by: Mikael Starvik <starvik@axis.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/cris')
-rw-r--r-- | arch/cris/arch-v10/kernel/dma.c | 287 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/head.S | 126 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/io_interface_mux.c | 879 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/shadows.c | 3 |
4 files changed, 1223 insertions, 72 deletions
diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c new file mode 100644 index 000000000000..e9a0311b141d --- /dev/null +++ b/arch/cris/arch-v10/kernel/dma.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* Wrapper for DMA channel allocator that updates DMA client muxing. | ||
2 | * Copyright 2004, Axis Communications AB | ||
3 | * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $ | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/errno.h> | ||
9 | |||
10 | #include <asm/dma.h> | ||
11 | #include <asm/arch/svinto.h> | ||
12 | |||
13 | /* Macro to access ETRAX 100 registers */ | ||
14 | #define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ | ||
15 | IO_STATE_(reg##_, field##_, _##val) | ||
16 | |||
17 | |||
18 | static char used_dma_channels[MAX_DMA_CHANNELS]; | ||
19 | static const char * used_dma_channels_users[MAX_DMA_CHANNELS]; | ||
20 | |||
21 | int cris_request_dma(unsigned int dmanr, const char * device_id, | ||
22 | unsigned options, enum dma_owner owner) | ||
23 | { | ||
24 | unsigned long flags; | ||
25 | unsigned long int gens; | ||
26 | int fail = -EINVAL; | ||
27 | |||
28 | if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { | ||
29 | printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr); | ||
30 | return -EINVAL; | ||
31 | } | ||
32 | |||
33 | local_irq_save(flags); | ||
34 | if (used_dma_channels[dmanr]) { | ||
35 | local_irq_restore(flags); | ||
36 | if (options & DMA_VERBOSE_ON_ERROR) { | ||
37 | printk(KERN_CRIT "Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]); | ||
38 | } | ||
39 | if (options & DMA_PANIC_ON_ERROR) { | ||
40 | panic("request_dma error!"); | ||
41 | } | ||
42 | return -EBUSY; | ||
43 | } | ||
44 | |||
45 | gens = genconfig_shadow; | ||
46 | |||
47 | switch(owner) | ||
48 | { | ||
49 | case dma_eth: | ||
50 | if ((dmanr != NETWORK_TX_DMA_NBR) && | ||
51 | (dmanr != NETWORK_RX_DMA_NBR)) { | ||
52 | printk(KERN_CRIT "Invalid DMA channel for eth\n"); | ||
53 | goto bail; | ||
54 | } | ||
55 | break; | ||
56 | case dma_ser0: | ||
57 | if (dmanr == SER0_TX_DMA_NBR) { | ||
58 | SETS(gens, R_GEN_CONFIG, dma6, serial0); | ||
59 | } else if (dmanr == SER0_RX_DMA_NBR) { | ||
60 | SETS(gens, R_GEN_CONFIG, dma7, serial0); | ||
61 | } else { | ||
62 | printk(KERN_CRIT "Invalid DMA channel for ser0\n"); | ||
63 | goto bail; | ||
64 | } | ||
65 | break; | ||
66 | case dma_ser1: | ||
67 | if (dmanr == SER1_TX_DMA_NBR) { | ||
68 | SETS(gens, R_GEN_CONFIG, dma8, serial1); | ||
69 | } else if (dmanr == SER1_RX_DMA_NBR) { | ||
70 | SETS(gens, R_GEN_CONFIG, dma9, serial1); | ||
71 | } else { | ||
72 | printk(KERN_CRIT "Invalid DMA channel for ser1\n"); | ||
73 | goto bail; | ||
74 | } | ||
75 | break; | ||
76 | case dma_ser2: | ||
77 | if (dmanr == SER2_TX_DMA_NBR) { | ||
78 | SETS(gens, R_GEN_CONFIG, dma2, serial2); | ||
79 | } else if (dmanr == SER2_RX_DMA_NBR) { | ||
80 | SETS(gens, R_GEN_CONFIG, dma3, serial2); | ||
81 | } else { | ||
82 | printk(KERN_CRIT "Invalid DMA channel for ser2\n"); | ||
83 | goto bail; | ||
84 | } | ||
85 | break; | ||
86 | case dma_ser3: | ||
87 | if (dmanr == SER3_TX_DMA_NBR) { | ||
88 | SETS(gens, R_GEN_CONFIG, dma4, serial3); | ||
89 | } else if (dmanr == SER3_RX_DMA_NBR) { | ||
90 | SETS(gens, R_GEN_CONFIG, dma5, serial3); | ||
91 | } else { | ||
92 | printk(KERN_CRIT "Invalid DMA channel for ser3\n"); | ||
93 | goto bail; | ||
94 | } | ||
95 | break; | ||
96 | case dma_ata: | ||
97 | if (dmanr == ATA_TX_DMA_NBR) { | ||
98 | SETS(gens, R_GEN_CONFIG, dma2, ata); | ||
99 | } else if (dmanr == ATA_RX_DMA_NBR) { | ||
100 | SETS(gens, R_GEN_CONFIG, dma3, ata); | ||
101 | } else { | ||
102 | printk(KERN_CRIT "Invalid DMA channel for ata\n"); | ||
103 | goto bail; | ||
104 | } | ||
105 | break; | ||
106 | case dma_ext0: | ||
107 | if (dmanr == EXTDMA0_TX_DMA_NBR) { | ||
108 | SETS(gens, R_GEN_CONFIG, dma4, extdma0); | ||
109 | } else if (dmanr == EXTDMA0_RX_DMA_NBR) { | ||
110 | SETS(gens, R_GEN_CONFIG, dma5, extdma0); | ||
111 | } else { | ||
112 | printk(KERN_CRIT "Invalid DMA channel for ext0\n"); | ||
113 | goto bail; | ||
114 | } | ||
115 | break; | ||
116 | case dma_ext1: | ||
117 | if (dmanr == EXTDMA1_TX_DMA_NBR) { | ||
118 | SETS(gens, R_GEN_CONFIG, dma6, extdma1); | ||
119 | } else if (dmanr == EXTDMA1_RX_DMA_NBR) { | ||
120 | SETS(gens, R_GEN_CONFIG, dma7, extdma1); | ||
121 | } else { | ||
122 | printk(KERN_CRIT "Invalid DMA channel for ext1\n"); | ||
123 | goto bail; | ||
124 | } | ||
125 | break; | ||
126 | case dma_int6: | ||
127 | if (dmanr == MEM2MEM_RX_DMA_NBR) { | ||
128 | SETS(gens, R_GEN_CONFIG, dma7, intdma6); | ||
129 | } else { | ||
130 | printk(KERN_CRIT "Invalid DMA channel for int6\n"); | ||
131 | goto bail; | ||
132 | } | ||
133 | break; | ||
134 | case dma_int7: | ||
135 | if (dmanr == MEM2MEM_TX_DMA_NBR) { | ||
136 | SETS(gens, R_GEN_CONFIG, dma6, intdma7); | ||
137 | } else { | ||
138 | printk(KERN_CRIT "Invalid DMA channel for int7\n"); | ||
139 | goto bail; | ||
140 | } | ||
141 | break; | ||
142 | case dma_usb: | ||
143 | if (dmanr == USB_TX_DMA_NBR) { | ||
144 | SETS(gens, R_GEN_CONFIG, dma8, usb); | ||
145 | } else if (dmanr == USB_RX_DMA_NBR) { | ||
146 | SETS(gens, R_GEN_CONFIG, dma9, usb); | ||
147 | } else { | ||
148 | printk(KERN_CRIT "Invalid DMA channel for usb\n"); | ||
149 | goto bail; | ||
150 | } | ||
151 | break; | ||
152 | case dma_scsi0: | ||
153 | if (dmanr == SCSI0_TX_DMA_NBR) { | ||
154 | SETS(gens, R_GEN_CONFIG, dma2, scsi0); | ||
155 | } else if (dmanr == SCSI0_RX_DMA_NBR) { | ||
156 | SETS(gens, R_GEN_CONFIG, dma3, scsi0); | ||
157 | } else { | ||
158 | printk(KERN_CRIT "Invalid DMA channel for scsi0\n"); | ||
159 | goto bail; | ||
160 | } | ||
161 | break; | ||
162 | case dma_scsi1: | ||
163 | if (dmanr == SCSI1_TX_DMA_NBR) { | ||
164 | SETS(gens, R_GEN_CONFIG, dma4, scsi1); | ||
165 | } else if (dmanr == SCSI1_RX_DMA_NBR) { | ||
166 | SETS(gens, R_GEN_CONFIG, dma5, scsi1); | ||
167 | } else { | ||
168 | printk(KERN_CRIT "Invalid DMA channel for scsi1\n"); | ||
169 | goto bail; | ||
170 | } | ||
171 | break; | ||
172 | case dma_par0: | ||
173 | if (dmanr == PAR0_TX_DMA_NBR) { | ||
174 | SETS(gens, R_GEN_CONFIG, dma2, par0); | ||
175 | } else if (dmanr == PAR0_RX_DMA_NBR) { | ||
176 | SETS(gens, R_GEN_CONFIG, dma3, par0); | ||
177 | } else { | ||
178 | printk(KERN_CRIT "Invalid DMA channel for par0\n"); | ||
179 | goto bail; | ||
180 | } | ||
181 | break; | ||
182 | case dma_par1: | ||
183 | if (dmanr == PAR1_TX_DMA_NBR) { | ||
184 | SETS(gens, R_GEN_CONFIG, dma4, par1); | ||
185 | } else if (dmanr == PAR1_RX_DMA_NBR) { | ||
186 | SETS(gens, R_GEN_CONFIG, dma5, par1); | ||
187 | } else { | ||
188 | printk(KERN_CRIT "Invalid DMA channel for par1\n"); | ||
189 | goto bail; | ||
190 | } | ||
191 | break; | ||
192 | default: | ||
193 | printk(KERN_CRIT "Invalid DMA owner.\n"); | ||
194 | goto bail; | ||
195 | } | ||
196 | |||
197 | used_dma_channels[dmanr] = 1; | ||
198 | used_dma_channels_users[dmanr] = device_id; | ||
199 | |||
200 | { | ||
201 | volatile int i; | ||
202 | genconfig_shadow = gens; | ||
203 | *R_GEN_CONFIG = genconfig_shadow; | ||
204 | /* Wait 12 cycles before doing any DMA command */ | ||
205 | for(i = 6; i > 0; i--) | ||
206 | nop(); | ||
207 | } | ||
208 | fail = 0; | ||
209 | bail: | ||
210 | local_irq_restore(flags); | ||
211 | return fail; | ||
212 | } | ||
213 | |||
214 | void cris_free_dma(unsigned int dmanr, const char * device_id) | ||
215 | { | ||
216 | unsigned long flags; | ||
217 | if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { | ||
218 | printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr); | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | local_irq_save(flags); | ||
223 | if (!used_dma_channels[dmanr]) { | ||
224 | printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated\n", dmanr); | ||
225 | } else if (device_id != used_dma_channels_users[dmanr]) { | ||
226 | printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated by device\n", dmanr); | ||
227 | } else { | ||
228 | switch(dmanr) | ||
229 | { | ||
230 | case 0: | ||
231 | *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, reset); | ||
232 | while (IO_EXTRACT(R_DMA_CH0_CMD, cmd, *R_DMA_CH0_CMD) == | ||
233 | IO_STATE_VALUE(R_DMA_CH0_CMD, cmd, reset)); | ||
234 | break; | ||
235 | case 1: | ||
236 | *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, reset); | ||
237 | while (IO_EXTRACT(R_DMA_CH1_CMD, cmd, *R_DMA_CH1_CMD) == | ||
238 | IO_STATE_VALUE(R_DMA_CH1_CMD, cmd, reset)); | ||
239 | break; | ||
240 | case 2: | ||
241 | *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, reset); | ||
242 | while (IO_EXTRACT(R_DMA_CH2_CMD, cmd, *R_DMA_CH2_CMD) == | ||
243 | IO_STATE_VALUE(R_DMA_CH2_CMD, cmd, reset)); | ||
244 | break; | ||
245 | case 3: | ||
246 | *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, reset); | ||
247 | while (IO_EXTRACT(R_DMA_CH3_CMD, cmd, *R_DMA_CH3_CMD) == | ||
248 | IO_STATE_VALUE(R_DMA_CH3_CMD, cmd, reset)); | ||
249 | break; | ||
250 | case 4: | ||
251 | *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, reset); | ||
252 | while (IO_EXTRACT(R_DMA_CH4_CMD, cmd, *R_DMA_CH4_CMD) == | ||
253 | IO_STATE_VALUE(R_DMA_CH4_CMD, cmd, reset)); | ||
254 | break; | ||
255 | case 5: | ||
256 | *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, reset); | ||
257 | while (IO_EXTRACT(R_DMA_CH5_CMD, cmd, *R_DMA_CH5_CMD) == | ||
258 | IO_STATE_VALUE(R_DMA_CH5_CMD, cmd, reset)); | ||
259 | break; | ||
260 | case 6: | ||
261 | *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, reset); | ||
262 | while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *R_DMA_CH6_CMD) == | ||
263 | IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); | ||
264 | break; | ||
265 | case 7: | ||
266 | *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, reset); | ||
267 | while (IO_EXTRACT(R_DMA_CH7_CMD, cmd, *R_DMA_CH7_CMD) == | ||
268 | IO_STATE_VALUE(R_DMA_CH7_CMD, cmd, reset)); | ||
269 | break; | ||
270 | case 8: | ||
271 | *R_DMA_CH8_CMD = IO_STATE(R_DMA_CH8_CMD, cmd, reset); | ||
272 | while (IO_EXTRACT(R_DMA_CH8_CMD, cmd, *R_DMA_CH8_CMD) == | ||
273 | IO_STATE_VALUE(R_DMA_CH8_CMD, cmd, reset)); | ||
274 | break; | ||
275 | case 9: | ||
276 | *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, reset); | ||
277 | while (IO_EXTRACT(R_DMA_CH9_CMD, cmd, *R_DMA_CH9_CMD) == | ||
278 | IO_STATE_VALUE(R_DMA_CH9_CMD, cmd, reset)); | ||
279 | break; | ||
280 | } | ||
281 | used_dma_channels[dmanr] = 0; | ||
282 | } | ||
283 | local_irq_restore(flags); | ||
284 | } | ||
285 | |||
286 | EXPORT_SYMBOL(cris_request_dma); | ||
287 | EXPORT_SYMBOL(cris_free_dma); | ||
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index 2c1dd1184a8f..f00c145b43f1 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $ | 1 | /* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $ |
2 | * | 2 | * |
3 | * Head of the kernel - alter with care | 3 | * Head of the kernel - alter with care |
4 | * | 4 | * |
@@ -7,6 +7,16 @@ | |||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | 7 | * Authors: Bjorn Wesen (bjornw@axis.com) |
8 | * | 8 | * |
9 | * $Log: head.S,v $ | 9 | * $Log: head.S,v $ |
10 | * Revision 1.10 2005/06/20 05:12:54 starvik | ||
11 | * Remove unnecessary diff to kernel.org tree | ||
12 | * | ||
13 | * Revision 1.9 2004/12/13 12:21:51 starvik | ||
14 | * Added I/O and DMA allocators from Linux 2.4 | ||
15 | * | ||
16 | * Revision 1.8 2004/11/22 11:41:14 starvik | ||
17 | * Kernel command line may be supplied to kernel. Not used by Axis but may | ||
18 | * be used by customers. | ||
19 | * | ||
10 | * Revision 1.7 2004/05/14 07:58:01 starvik | 20 | * Revision 1.7 2004/05/14 07:58:01 starvik |
11 | * Merge of changes from 2.4 | 21 | * Merge of changes from 2.4 |
12 | * | 22 | * |
@@ -181,6 +191,7 @@ | |||
181 | 191 | ||
182 | #define CRAMFS_MAGIC 0x28cd3d45 | 192 | #define CRAMFS_MAGIC 0x28cd3d45 |
183 | #define RAM_INIT_MAGIC 0x56902387 | 193 | #define RAM_INIT_MAGIC 0x56902387 |
194 | #define COMMAND_LINE_MAGIC 0x87109563 | ||
184 | 195 | ||
185 | #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ | 196 | #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ |
186 | IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | 197 | IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
@@ -490,6 +501,23 @@ _no_romfs_in_flash: | |||
490 | 501 | ||
491 | _start_it: | 502 | _start_it: |
492 | 503 | ||
504 | ;; Check if kernel command line is supplied | ||
505 | cmp.d COMMAND_LINE_MAGIC, $r10 | ||
506 | bne no_command_line | ||
507 | nop | ||
508 | |||
509 | move.d 256, $r13 | ||
510 | move.d cris_command_line, $r10 | ||
511 | or.d 0x80000000, $r11 ; Make it virtual | ||
512 | 1: | ||
513 | move.b [$r11+], $r12 | ||
514 | move.b $r12, [$r10+] | ||
515 | subq 1, $r13 | ||
516 | bne 1b | ||
517 | nop | ||
518 | |||
519 | no_command_line: | ||
520 | |||
493 | ;; the kernel stack is overlayed with the task structure for each | 521 | ;; the kernel stack is overlayed with the task structure for each |
494 | ;; task. thus the initial kernel stack is in the same page as the | 522 | ;; task. thus the initial kernel stack is in the same page as the |
495 | ;; init_task (but starts in the top of the page, size 8192) | 523 | ;; init_task (but starts in the top of the page, size 8192) |
@@ -567,76 +595,32 @@ _start_it: | |||
567 | ;; Etrax product HW genconfig setup | 595 | ;; Etrax product HW genconfig setup |
568 | 596 | ||
569 | moveq 0,$r0 | 597 | moveq 0,$r0 |
570 | #if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ | 598 | |
571 | && !defined(CONFIG_DMA_MEMCPY) | 599 | ;; Init interfaces (disable them). |
572 | ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA | 600 | or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \ |
573 | or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ | 601 | | IO_STATE (R_GEN_CONFIG, ata, disable) \ |
574 | | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 | 602 | | IO_STATE (R_GEN_CONFIG, par0, disable) \ |
575 | #endif | 603 | | IO_STATE (R_GEN_CONFIG, ser2, disable) \ |
576 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) | 604 | | IO_STATE (R_GEN_CONFIG, mio, disable) \ |
577 | ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA | 605 | | IO_STATE (R_GEN_CONFIG, scsi1, disable) \ |
578 | or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ | 606 | | IO_STATE (R_GEN_CONFIG, scsi0w, disable) \ |
579 | | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0 | 607 | | IO_STATE (R_GEN_CONFIG, par1, disable) \ |
580 | #endif | 608 | | IO_STATE (R_GEN_CONFIG, ser3, disable) \ |
581 | #ifdef CONFIG_DMA_MEMCPY | 609 | | IO_STATE (R_GEN_CONFIG, mio_w, disable) \ |
582 | ; 6/7 memory-memory DMA | 610 | | IO_STATE (R_GEN_CONFIG, usb1, disable) \ |
583 | or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ | 611 | | IO_STATE (R_GEN_CONFIG, usb2, disable) \ |
584 | | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0 | 612 | | IO_STATE (R_GEN_CONFIG, par_w, disable),$r0 |
585 | #endif | 613 | |
586 | #ifdef CONFIG_ETRAX_SERIAL_PORT2 | 614 | ;; Init DMA channel muxing (set to unused clients). |
587 | ; Enable serial port 2 | 615 | or.d IO_STATE (R_GEN_CONFIG, dma2, ata) \ |
588 | or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0 | 616 | | IO_STATE (R_GEN_CONFIG, dma3, ata) \ |
589 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2) | 617 | | IO_STATE (R_GEN_CONFIG, dma4, scsi1) \ |
590 | ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA | 618 | | IO_STATE (R_GEN_CONFIG, dma5, scsi1) \ |
591 | or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ | 619 | | IO_STATE (R_GEN_CONFIG, dma6, unused) \ |
592 | | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0 | 620 | | IO_STATE (R_GEN_CONFIG, dma7, unused) \ |
593 | #endif | 621 | | IO_STATE (R_GEN_CONFIG, dma8, usb) \ |
594 | #endif | 622 | | IO_STATE (R_GEN_CONFIG, dma9, usb),$r0 |
595 | #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) | 623 | |
596 | ; Enable serial port 3 | ||
597 | or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0 | ||
598 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
599 | ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA | ||
600 | or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ | ||
601 | | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0 | ||
602 | #endif | ||
603 | #endif | ||
604 | #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
605 | ; parport 0 enabled using DMA 2/3 | ||
606 | or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 | ||
607 | #endif | ||
608 | #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
609 | ; parport 1 enabled using DMA 4/5 | ||
610 | or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0 | ||
611 | #endif | ||
612 | #ifdef CONFIG_ETRAX_IDE | ||
613 | ; DMA channels 2 and 3 to ATA, ATA enabled | ||
614 | or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ | ||
615 | | IO_STATE (R_GEN_CONFIG, dma2, ata) \ | ||
616 | | IO_STATE (R_GEN_CONFIG, ata, select),$r0 | ||
617 | #endif | ||
618 | |||
619 | #ifdef CONFIG_ETRAX_USB_HOST_PORT1 | ||
620 | ; Set the USB port 1 enable bit | ||
621 | or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0 | ||
622 | #endif | ||
623 | #ifdef CONFIG_ETRAX_USB_HOST_PORT2 | ||
624 | ; Set the USB port 2 enable bit | ||
625 | or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0 | ||
626 | #endif | ||
627 | #ifdef CONFIG_ETRAX_USB_HOST | ||
628 | ; Connect DMA channels 8 and 9 to USB | ||
629 | and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ | ||
630 | | IO_MASK (R_GEN_CONFIG, dma8))) \ | ||
631 | | IO_STATE (R_GEN_CONFIG, dma9, usb) \ | ||
632 | | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0 | ||
633 | #endif | ||
634 | |||
635 | #ifdef CONFIG_JULIETTE | ||
636 | ; DMA channels 4 and 5 to EXTDMA0, for Juliette | ||
637 | or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ | ||
638 | | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 | ||
639 | #endif | ||
640 | 624 | ||
641 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) | 625 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) |
642 | or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 | 626 | or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 |
diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c new file mode 100644 index 000000000000..29d48ad00df9 --- /dev/null +++ b/arch/cris/arch-v10/kernel/io_interface_mux.c | |||
@@ -0,0 +1,879 @@ | |||
1 | /* IO interface mux allocator for ETRAX100LX. | ||
2 | * Copyright 2004, Axis Communications AB | ||
3 | * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $ | ||
4 | */ | ||
5 | |||
6 | |||
7 | /* C.f. ETRAX100LX Designer's Reference 20.9 */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/slab.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/arch/svinto.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/arch/io_interface_mux.h> | ||
18 | |||
19 | |||
20 | #define DBG(s) | ||
21 | |||
22 | /* Macro to access ETRAX 100 registers */ | ||
23 | #define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ | ||
24 | IO_STATE_(reg##_, field##_, _##val) | ||
25 | |||
26 | enum io_if_group { | ||
27 | group_a = (1<<0), | ||
28 | group_b = (1<<1), | ||
29 | group_c = (1<<2), | ||
30 | group_d = (1<<3), | ||
31 | group_e = (1<<4), | ||
32 | group_f = (1<<5) | ||
33 | }; | ||
34 | |||
35 | struct watcher | ||
36 | { | ||
37 | void (*notify)(const unsigned int gpio_in_available, | ||
38 | const unsigned int gpio_out_available, | ||
39 | const unsigned char pa_available, | ||
40 | const unsigned char pb_available); | ||
41 | struct watcher *next; | ||
42 | }; | ||
43 | |||
44 | |||
45 | struct if_group | ||
46 | { | ||
47 | enum io_if_group group; | ||
48 | unsigned char used; | ||
49 | enum cris_io_interface owner; | ||
50 | }; | ||
51 | |||
52 | |||
53 | struct interface | ||
54 | { | ||
55 | enum cris_io_interface ioif; | ||
56 | unsigned char groups; | ||
57 | unsigned char used; | ||
58 | char *owner; | ||
59 | unsigned int gpio_g_in; | ||
60 | unsigned int gpio_g_out; | ||
61 | unsigned char gpio_b; | ||
62 | }; | ||
63 | |||
64 | static struct if_group if_groups[6] = { | ||
65 | { | ||
66 | .group = group_a, | ||
67 | .used = 0, | ||
68 | }, | ||
69 | { | ||
70 | .group = group_b, | ||
71 | .used = 0, | ||
72 | }, | ||
73 | { | ||
74 | .group = group_c, | ||
75 | .used = 0, | ||
76 | }, | ||
77 | { | ||
78 | .group = group_d, | ||
79 | .used = 0, | ||
80 | }, | ||
81 | { | ||
82 | .group = group_e, | ||
83 | .used = 0, | ||
84 | }, | ||
85 | { | ||
86 | .group = group_f, | ||
87 | .used = 0, | ||
88 | } | ||
89 | }; | ||
90 | |||
91 | /* The order in the array must match the order of enum | ||
92 | * cris_io_interface in io_interface_mux.h */ | ||
93 | static struct interface interfaces[] = { | ||
94 | /* Begin Non-multiplexed interfaces */ | ||
95 | { | ||
96 | .ioif = if_eth, | ||
97 | .groups = 0, | ||
98 | .gpio_g_in = 0, | ||
99 | .gpio_g_out = 0, | ||
100 | .gpio_b = 0 | ||
101 | }, | ||
102 | { | ||
103 | .ioif = if_serial_0, | ||
104 | .groups = 0, | ||
105 | .gpio_g_in = 0, | ||
106 | .gpio_g_out = 0, | ||
107 | .gpio_b = 0 | ||
108 | }, | ||
109 | /* End Non-multiplexed interfaces */ | ||
110 | { | ||
111 | .ioif = if_serial_1, | ||
112 | .groups = group_e, | ||
113 | .gpio_g_in = 0x00000000, | ||
114 | .gpio_g_out = 0x00000000, | ||
115 | .gpio_b = 0x00 | ||
116 | }, | ||
117 | { | ||
118 | .ioif = if_serial_2, | ||
119 | .groups = group_b, | ||
120 | .gpio_g_in = 0x000000c0, | ||
121 | .gpio_g_out = 0x000000c0, | ||
122 | .gpio_b = 0x00 | ||
123 | }, | ||
124 | { | ||
125 | .ioif = if_serial_3, | ||
126 | .groups = group_c, | ||
127 | .gpio_g_in = 0xc0000000, | ||
128 | .gpio_g_out = 0xc0000000, | ||
129 | .gpio_b = 0x00 | ||
130 | }, | ||
131 | { | ||
132 | .ioif = if_sync_serial_1, | ||
133 | .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3 | ||
134 | can be used simultaneously */ | ||
135 | .gpio_g_in = 0x00000000, | ||
136 | .gpio_g_out = 0x00000000, | ||
137 | .gpio_b = 0x10 | ||
138 | }, | ||
139 | { | ||
140 | .ioif = if_sync_serial_3, | ||
141 | .groups = group_c | group_f, | ||
142 | .gpio_g_in = 0xc0000000, | ||
143 | .gpio_g_out = 0xc0000000, | ||
144 | .gpio_b = 0x80 | ||
145 | }, | ||
146 | { | ||
147 | .ioif = if_shared_ram, | ||
148 | .groups = group_a, | ||
149 | .gpio_g_in = 0x0000ff3e, | ||
150 | .gpio_g_out = 0x0000ff38, | ||
151 | .gpio_b = 0x00 | ||
152 | }, | ||
153 | { | ||
154 | .ioif = if_shared_ram_w, | ||
155 | .groups = group_a | group_d, | ||
156 | .gpio_g_in = 0x00ffff3e, | ||
157 | .gpio_g_out = 0x00ffff38, | ||
158 | .gpio_b = 0x00 | ||
159 | }, | ||
160 | { | ||
161 | .ioif = if_par_0, | ||
162 | .groups = group_a, | ||
163 | .gpio_g_in = 0x0000ff3e, | ||
164 | .gpio_g_out = 0x0000ff3e, | ||
165 | .gpio_b = 0x00 | ||
166 | }, | ||
167 | { | ||
168 | .ioif = if_par_1, | ||
169 | .groups = group_d, | ||
170 | .gpio_g_in = 0x3eff0000, | ||
171 | .gpio_g_out = 0x3eff0000, | ||
172 | .gpio_b = 0x00 | ||
173 | }, | ||
174 | { | ||
175 | .ioif = if_par_w, | ||
176 | .groups = group_a | group_d, | ||
177 | .gpio_g_in = 0x00ffff3e, | ||
178 | .gpio_g_out = 0x00ffff3e, | ||
179 | .gpio_b = 0x00 | ||
180 | }, | ||
181 | { | ||
182 | .ioif = if_scsi8_0, | ||
183 | .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1 | ||
184 | can be used simultaneously */ | ||
185 | .gpio_g_in = 0x0000ffff, | ||
186 | .gpio_g_out = 0x0000ffff, | ||
187 | .gpio_b = 0x10 | ||
188 | }, | ||
189 | { | ||
190 | .ioif = if_scsi8_1, | ||
191 | .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1 | ||
192 | can be used simultaneously */ | ||
193 | .gpio_g_in = 0xffff0000, | ||
194 | .gpio_g_out = 0xffff0000, | ||
195 | .gpio_b = 0x80 | ||
196 | }, | ||
197 | { | ||
198 | .ioif = if_scsi_w, | ||
199 | .groups = group_a | group_b | group_d | group_f, | ||
200 | .gpio_g_in = 0x01ffffff, | ||
201 | .gpio_g_out = 0x07ffffff, | ||
202 | .gpio_b = 0x80 | ||
203 | }, | ||
204 | { | ||
205 | .ioif = if_ata, | ||
206 | .groups = group_a | group_b | group_c | group_d, | ||
207 | .gpio_g_in = 0xf9ffffff, | ||
208 | .gpio_g_out = 0xffffffff, | ||
209 | .gpio_b = 0x80 | ||
210 | }, | ||
211 | { | ||
212 | .ioif = if_csp, | ||
213 | .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ | ||
214 | .gpio_g_in = 0x00000000, | ||
215 | .gpio_g_out = 0x00000000, | ||
216 | .gpio_b = 0xfc | ||
217 | }, | ||
218 | { | ||
219 | .ioif = if_i2c, | ||
220 | .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ | ||
221 | .gpio_g_in = 0x00000000, | ||
222 | .gpio_g_out = 0x00000000, | ||
223 | .gpio_b = 0x03 | ||
224 | }, | ||
225 | { | ||
226 | .ioif = if_usb_1, | ||
227 | .groups = group_e | group_f, | ||
228 | .gpio_g_in = 0x00000000, | ||
229 | .gpio_g_out = 0x00000000, | ||
230 | .gpio_b = 0x2c | ||
231 | }, | ||
232 | { | ||
233 | .ioif = if_usb_2, | ||
234 | .groups = group_d, | ||
235 | .gpio_g_in = 0x0e000000, | ||
236 | .gpio_g_out = 0x3c000000, | ||
237 | .gpio_b = 0x00 | ||
238 | }, | ||
239 | /* GPIO pins */ | ||
240 | { | ||
241 | .ioif = if_gpio_grp_a, | ||
242 | .groups = group_a, | ||
243 | .gpio_g_in = 0x0000ff3f, | ||
244 | .gpio_g_out = 0x0000ff3f, | ||
245 | .gpio_b = 0x00 | ||
246 | }, | ||
247 | { | ||
248 | .ioif = if_gpio_grp_b, | ||
249 | .groups = group_b, | ||
250 | .gpio_g_in = 0x000000c0, | ||
251 | .gpio_g_out = 0x000000c0, | ||
252 | .gpio_b = 0x00 | ||
253 | }, | ||
254 | { | ||
255 | .ioif = if_gpio_grp_c, | ||
256 | .groups = group_c, | ||
257 | .gpio_g_in = 0xc0000000, | ||
258 | .gpio_g_out = 0xc0000000, | ||
259 | .gpio_b = 0x00 | ||
260 | }, | ||
261 | { | ||
262 | .ioif = if_gpio_grp_d, | ||
263 | .groups = group_d, | ||
264 | .gpio_g_in = 0x3fff0000, | ||
265 | .gpio_g_out = 0x3fff0000, | ||
266 | .gpio_b = 0x00 | ||
267 | }, | ||
268 | { | ||
269 | .ioif = if_gpio_grp_e, | ||
270 | .groups = group_e, | ||
271 | .gpio_g_in = 0x00000000, | ||
272 | .gpio_g_out = 0x00000000, | ||
273 | .gpio_b = 0x00 | ||
274 | }, | ||
275 | { | ||
276 | .ioif = if_gpio_grp_f, | ||
277 | .groups = group_f, | ||
278 | .gpio_g_in = 0x00000000, | ||
279 | .gpio_g_out = 0x00000000, | ||
280 | .gpio_b = 0xff | ||
281 | } | ||
282 | /* Array end */ | ||
283 | }; | ||
284 | |||
285 | static struct watcher *watchers = NULL; | ||
286 | |||
287 | static unsigned int gpio_in_pins = 0xffffffff; | ||
288 | static unsigned int gpio_out_pins = 0xffffffff; | ||
289 | static unsigned char gpio_pb_pins = 0xff; | ||
290 | static unsigned char gpio_pa_pins = 0xff; | ||
291 | |||
292 | static enum cris_io_interface gpio_pa_owners[8]; | ||
293 | static enum cris_io_interface gpio_pb_owners[8]; | ||
294 | static enum cris_io_interface gpio_pg_owners[32]; | ||
295 | |||
296 | static int cris_io_interface_init(void); | ||
297 | |||
298 | static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group) | ||
299 | { | ||
300 | return (groups & ~group->group); | ||
301 | } | ||
302 | |||
303 | |||
304 | static struct if_group *get_group(const unsigned char groups) | ||
305 | { | ||
306 | int i; | ||
307 | for (i = 0; i < sizeof(if_groups)/sizeof(struct if_group); i++) { | ||
308 | if (groups & if_groups[i].group) { | ||
309 | return &if_groups[i]; | ||
310 | } | ||
311 | } | ||
312 | return NULL; | ||
313 | } | ||
314 | |||
315 | |||
316 | static void notify_watchers(void) | ||
317 | { | ||
318 | struct watcher *w = watchers; | ||
319 | |||
320 | DBG(printk("io_interface_mux: notifying watchers\n")); | ||
321 | |||
322 | while (NULL != w) { | ||
323 | w->notify((const unsigned int)gpio_in_pins, | ||
324 | (const unsigned int)gpio_out_pins, | ||
325 | (const unsigned char)gpio_pa_pins, | ||
326 | (const unsigned char)gpio_pb_pins); | ||
327 | w = w->next; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | |||
332 | int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id) | ||
333 | { | ||
334 | int set_gen_config = 0; | ||
335 | int set_gen_config_ii = 0; | ||
336 | unsigned long int gens; | ||
337 | unsigned long int gens_ii; | ||
338 | struct if_group *grp; | ||
339 | unsigned char group_set; | ||
340 | unsigned long flags; | ||
341 | |||
342 | (void)cris_io_interface_init(); | ||
343 | |||
344 | DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id)); | ||
345 | |||
346 | if ((ioif >= if_max_interfaces) || (ioif < 0)) { | ||
347 | printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n", | ||
348 | ioif, | ||
349 | device_id); | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | |||
353 | local_irq_save(flags); | ||
354 | |||
355 | if (interfaces[ioif].used) { | ||
356 | local_irq_restore(flags); | ||
357 | printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n", | ||
358 | device_id, | ||
359 | interfaces[ioif].owner); | ||
360 | return -EBUSY; | ||
361 | } | ||
362 | |||
363 | /* Check that all required groups are free before allocating, */ | ||
364 | group_set = interfaces[ioif].groups; | ||
365 | while (NULL != (grp = get_group(group_set))) { | ||
366 | if (grp->used) { | ||
367 | if (grp->group == group_f) { | ||
368 | if ((if_sync_serial_1 == ioif) || | ||
369 | (if_sync_serial_3 == ioif)) { | ||
370 | if ((grp->owner != if_sync_serial_1) && | ||
371 | (grp->owner != if_sync_serial_3)) { | ||
372 | local_irq_restore(flags); | ||
373 | return -EBUSY; | ||
374 | } | ||
375 | } else if ((if_scsi8_0 == ioif) || | ||
376 | (if_scsi8_1 == ioif)) { | ||
377 | if ((grp->owner != if_scsi8_0) && | ||
378 | (grp->owner != if_scsi8_1)) { | ||
379 | local_irq_restore(flags); | ||
380 | return -EBUSY; | ||
381 | } | ||
382 | } | ||
383 | } else { | ||
384 | local_irq_restore(flags); | ||
385 | return -EBUSY; | ||
386 | } | ||
387 | } | ||
388 | group_set = clear_group_from_set(group_set, grp); | ||
389 | } | ||
390 | |||
391 | /* Are the required GPIO pins available too? */ | ||
392 | if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) || | ||
393 | ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) || | ||
394 | ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) { | ||
395 | printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n", | ||
396 | ioif); | ||
397 | return -EBUSY; | ||
398 | } | ||
399 | |||
400 | /* All needed I/O pins and pin groups are free, allocate. */ | ||
401 | group_set = interfaces[ioif].groups; | ||
402 | while (NULL != (grp = get_group(group_set))) { | ||
403 | grp->used = 1; | ||
404 | grp->owner = ioif; | ||
405 | group_set = clear_group_from_set(group_set, grp); | ||
406 | } | ||
407 | |||
408 | gens = genconfig_shadow; | ||
409 | gens_ii = gen_config_ii_shadow; | ||
410 | |||
411 | set_gen_config = 1; | ||
412 | switch (ioif) | ||
413 | { | ||
414 | /* Begin Non-multiplexed interfaces */ | ||
415 | case if_eth: | ||
416 | /* fall through */ | ||
417 | case if_serial_0: | ||
418 | set_gen_config = 0; | ||
419 | break; | ||
420 | /* End Non-multiplexed interfaces */ | ||
421 | case if_serial_1: | ||
422 | set_gen_config_ii = 1; | ||
423 | SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async); | ||
424 | break; | ||
425 | case if_serial_2: | ||
426 | SETS(gens, R_GEN_CONFIG, ser2, select); | ||
427 | break; | ||
428 | case if_serial_3: | ||
429 | SETS(gens, R_GEN_CONFIG, ser3, select); | ||
430 | set_gen_config_ii = 1; | ||
431 | SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async); | ||
432 | break; | ||
433 | case if_sync_serial_1: | ||
434 | set_gen_config_ii = 1; | ||
435 | SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync); | ||
436 | break; | ||
437 | case if_sync_serial_3: | ||
438 | SETS(gens, R_GEN_CONFIG, ser3, select); | ||
439 | set_gen_config_ii = 1; | ||
440 | SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync); | ||
441 | break; | ||
442 | case if_shared_ram: | ||
443 | SETS(gens, R_GEN_CONFIG, mio, select); | ||
444 | break; | ||
445 | case if_shared_ram_w: | ||
446 | SETS(gens, R_GEN_CONFIG, mio_w, select); | ||
447 | break; | ||
448 | case if_par_0: | ||
449 | SETS(gens, R_GEN_CONFIG, par0, select); | ||
450 | break; | ||
451 | case if_par_1: | ||
452 | SETS(gens, R_GEN_CONFIG, par1, select); | ||
453 | break; | ||
454 | case if_par_w: | ||
455 | SETS(gens, R_GEN_CONFIG, par0, select); | ||
456 | SETS(gens, R_GEN_CONFIG, par_w, select); | ||
457 | break; | ||
458 | case if_scsi8_0: | ||
459 | SETS(gens, R_GEN_CONFIG, scsi0, select); | ||
460 | break; | ||
461 | case if_scsi8_1: | ||
462 | SETS(gens, R_GEN_CONFIG, scsi1, select); | ||
463 | break; | ||
464 | case if_scsi_w: | ||
465 | SETS(gens, R_GEN_CONFIG, scsi0, select); | ||
466 | SETS(gens, R_GEN_CONFIG, scsi0w, select); | ||
467 | break; | ||
468 | case if_ata: | ||
469 | SETS(gens, R_GEN_CONFIG, ata, select); | ||
470 | break; | ||
471 | case if_csp: | ||
472 | /* fall through */ | ||
473 | case if_i2c: | ||
474 | set_gen_config = 0; | ||
475 | break; | ||
476 | case if_usb_1: | ||
477 | SETS(gens, R_GEN_CONFIG, usb1, select); | ||
478 | break; | ||
479 | case if_usb_2: | ||
480 | SETS(gens, R_GEN_CONFIG, usb2, select); | ||
481 | break; | ||
482 | case if_gpio_grp_a: | ||
483 | /* GPIO groups are only accounted, don't do configuration changes. */ | ||
484 | /* fall through */ | ||
485 | case if_gpio_grp_b: | ||
486 | /* fall through */ | ||
487 | case if_gpio_grp_c: | ||
488 | /* fall through */ | ||
489 | case if_gpio_grp_d: | ||
490 | /* fall through */ | ||
491 | case if_gpio_grp_e: | ||
492 | /* fall through */ | ||
493 | case if_gpio_grp_f: | ||
494 | set_gen_config = 0; | ||
495 | break; | ||
496 | default: | ||
497 | panic("cris_request_io_interface: Bad interface %u submitted for %s\n", | ||
498 | ioif, | ||
499 | device_id); | ||
500 | } | ||
501 | |||
502 | interfaces[ioif].used = 1; | ||
503 | interfaces[ioif].owner = (char*)device_id; | ||
504 | |||
505 | if (set_gen_config) { | ||
506 | volatile int i; | ||
507 | genconfig_shadow = gens; | ||
508 | *R_GEN_CONFIG = genconfig_shadow; | ||
509 | /* Wait 12 cycles before doing any DMA command */ | ||
510 | for(i = 6; i > 0; i--) | ||
511 | nop(); | ||
512 | } | ||
513 | if (set_gen_config_ii) { | ||
514 | gen_config_ii_shadow = gens_ii; | ||
515 | *R_GEN_CONFIG_II = gen_config_ii_shadow; | ||
516 | } | ||
517 | |||
518 | DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
519 | gpio_in_pins, gpio_out_pins, gpio_pb_pins)); | ||
520 | DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
521 | interfaces[ioif].gpio_g_in, | ||
522 | interfaces[ioif].gpio_g_out, | ||
523 | interfaces[ioif].gpio_b)); | ||
524 | |||
525 | gpio_in_pins &= ~interfaces[ioif].gpio_g_in; | ||
526 | gpio_out_pins &= ~interfaces[ioif].gpio_g_out; | ||
527 | gpio_pb_pins &= ~interfaces[ioif].gpio_b; | ||
528 | |||
529 | DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
530 | gpio_in_pins, gpio_out_pins, gpio_pb_pins)); | ||
531 | |||
532 | local_irq_restore(flags); | ||
533 | |||
534 | notify_watchers(); | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | |||
540 | void cris_free_io_interface(enum cris_io_interface ioif) | ||
541 | { | ||
542 | struct if_group *grp; | ||
543 | unsigned char group_set; | ||
544 | unsigned long flags; | ||
545 | |||
546 | (void)cris_io_interface_init(); | ||
547 | |||
548 | if ((ioif >= if_max_interfaces) || (ioif < 0)) { | ||
549 | printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n", | ||
550 | ioif); | ||
551 | return; | ||
552 | } | ||
553 | local_irq_save(flags); | ||
554 | if (!interfaces[ioif].used) { | ||
555 | printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n", | ||
556 | ioif); | ||
557 | local_irq_restore(flags); | ||
558 | return; | ||
559 | } | ||
560 | group_set = interfaces[ioif].groups; | ||
561 | while (NULL != (grp = get_group(group_set))) { | ||
562 | if (grp->group == group_f) { | ||
563 | switch (ioif) | ||
564 | { | ||
565 | case if_sync_serial_1: | ||
566 | if ((grp->owner == if_sync_serial_1) && | ||
567 | interfaces[if_sync_serial_3].used) { | ||
568 | grp->owner = if_sync_serial_3; | ||
569 | } else | ||
570 | grp->used = 0; | ||
571 | break; | ||
572 | case if_sync_serial_3: | ||
573 | if ((grp->owner == if_sync_serial_3) && | ||
574 | interfaces[if_sync_serial_1].used) { | ||
575 | grp->owner = if_sync_serial_1; | ||
576 | } else | ||
577 | grp->used = 0; | ||
578 | break; | ||
579 | case if_scsi8_0: | ||
580 | if ((grp->owner == if_scsi8_0) && | ||
581 | interfaces[if_scsi8_1].used) { | ||
582 | grp->owner = if_scsi8_1; | ||
583 | } else | ||
584 | grp->used = 0; | ||
585 | break; | ||
586 | case if_scsi8_1: | ||
587 | if ((grp->owner == if_scsi8_1) && | ||
588 | interfaces[if_scsi8_0].used) { | ||
589 | grp->owner = if_scsi8_0; | ||
590 | } else | ||
591 | grp->used = 0; | ||
592 | break; | ||
593 | default: | ||
594 | grp->used = 0; | ||
595 | } | ||
596 | } else { | ||
597 | grp->used = 0; | ||
598 | } | ||
599 | group_set = clear_group_from_set(group_set, grp); | ||
600 | } | ||
601 | interfaces[ioif].used = 0; | ||
602 | interfaces[ioif].owner = NULL; | ||
603 | |||
604 | DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
605 | gpio_in_pins, gpio_out_pins, gpio_pb_pins)); | ||
606 | DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
607 | interfaces[ioif].gpio_g_in, | ||
608 | interfaces[ioif].gpio_g_out, | ||
609 | interfaces[ioif].gpio_b)); | ||
610 | |||
611 | gpio_in_pins |= interfaces[ioif].gpio_g_in; | ||
612 | gpio_out_pins |= interfaces[ioif].gpio_g_out; | ||
613 | gpio_pb_pins |= interfaces[ioif].gpio_b; | ||
614 | |||
615 | DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", | ||
616 | gpio_in_pins, gpio_out_pins, gpio_pb_pins)); | ||
617 | |||
618 | local_irq_restore(flags); | ||
619 | |||
620 | notify_watchers(); | ||
621 | } | ||
622 | |||
623 | /* Create a bitmask from bit 0 (inclusive) to bit stop_bit | ||
624 | (non-inclusive). stop_bit == 0 returns 0x0 */ | ||
625 | static inline unsigned int create_mask(const unsigned stop_bit) | ||
626 | { | ||
627 | /* Avoid overflow */ | ||
628 | if (stop_bit >= 32) { | ||
629 | return 0xffffffff; | ||
630 | } | ||
631 | return (1<<stop_bit)-1; | ||
632 | } | ||
633 | |||
634 | |||
635 | /* port can be 'a', 'b' or 'g' */ | ||
636 | int cris_io_interface_allocate_pins(const enum cris_io_interface ioif, | ||
637 | const char port, | ||
638 | const unsigned start_bit, | ||
639 | const unsigned stop_bit) | ||
640 | { | ||
641 | unsigned int i; | ||
642 | unsigned int mask = 0; | ||
643 | unsigned int tmp_mask; | ||
644 | unsigned long int flags; | ||
645 | enum cris_io_interface *owners; | ||
646 | |||
647 | (void)cris_io_interface_init(); | ||
648 | |||
649 | DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u stop=%u\n", | ||
650 | ioif, port, start_bit, stop_bit)); | ||
651 | |||
652 | if (!((start_bit <= stop_bit) && | ||
653 | ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || | ||
654 | ((port == 'g') && (stop_bit < 32))))) { | ||
655 | return -EINVAL; | ||
656 | } | ||
657 | |||
658 | mask = create_mask(stop_bit + 1); | ||
659 | tmp_mask = create_mask(start_bit); | ||
660 | mask &= ~tmp_mask; | ||
661 | |||
662 | DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u mask=0x%08x\n", | ||
663 | port, start_bit, stop_bit, mask)); | ||
664 | |||
665 | local_irq_save(flags); | ||
666 | |||
667 | switch (port) { | ||
668 | case 'a': | ||
669 | if ((gpio_pa_pins & mask) != mask) { | ||
670 | local_irq_restore(flags); | ||
671 | return -EBUSY; | ||
672 | } | ||
673 | owners = gpio_pa_owners; | ||
674 | gpio_pa_pins &= ~mask; | ||
675 | break; | ||
676 | case 'b': | ||
677 | if ((gpio_pb_pins & mask) != mask) { | ||
678 | local_irq_restore(flags); | ||
679 | return -EBUSY; | ||
680 | } | ||
681 | owners = gpio_pb_owners; | ||
682 | gpio_pb_pins &= ~mask; | ||
683 | break; | ||
684 | case 'g': | ||
685 | if (((gpio_in_pins & mask) != mask) || | ||
686 | ((gpio_out_pins & mask) != mask)) { | ||
687 | local_irq_restore(flags); | ||
688 | return -EBUSY; | ||
689 | } | ||
690 | owners = gpio_pg_owners; | ||
691 | gpio_in_pins &= ~mask; | ||
692 | gpio_out_pins &= ~mask; | ||
693 | break; | ||
694 | default: | ||
695 | local_irq_restore(flags); | ||
696 | return -EINVAL; | ||
697 | } | ||
698 | |||
699 | for (i = start_bit; i <= stop_bit; i++) { | ||
700 | owners[i] = ioif; | ||
701 | } | ||
702 | local_irq_restore(flags); | ||
703 | |||
704 | notify_watchers(); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | |||
709 | /* port can be 'a', 'b' or 'g' */ | ||
710 | int cris_io_interface_free_pins(const enum cris_io_interface ioif, | ||
711 | const char port, | ||
712 | const unsigned start_bit, | ||
713 | const unsigned stop_bit) | ||
714 | { | ||
715 | unsigned int i; | ||
716 | unsigned int mask = 0; | ||
717 | unsigned int tmp_mask; | ||
718 | unsigned long int flags; | ||
719 | enum cris_io_interface *owners; | ||
720 | |||
721 | (void)cris_io_interface_init(); | ||
722 | |||
723 | if (!((start_bit <= stop_bit) && | ||
724 | ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || | ||
725 | ((port == 'g') && (stop_bit < 32))))) { | ||
726 | return -EINVAL; | ||
727 | } | ||
728 | |||
729 | mask = create_mask(stop_bit + 1); | ||
730 | tmp_mask = create_mask(start_bit); | ||
731 | mask &= ~tmp_mask; | ||
732 | |||
733 | DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u mask=0x%08x\n", | ||
734 | port, start_bit, stop_bit, mask)); | ||
735 | |||
736 | local_irq_save(flags); | ||
737 | |||
738 | switch (port) { | ||
739 | case 'a': | ||
740 | if ((~gpio_pa_pins & mask) != mask) { | ||
741 | local_irq_restore(flags); | ||
742 | printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); | ||
743 | } | ||
744 | owners = gpio_pa_owners; | ||
745 | break; | ||
746 | case 'b': | ||
747 | if ((~gpio_pb_pins & mask) != mask) { | ||
748 | local_irq_restore(flags); | ||
749 | printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); | ||
750 | } | ||
751 | owners = gpio_pb_owners; | ||
752 | break; | ||
753 | case 'g': | ||
754 | if (((~gpio_in_pins & mask) != mask) || | ||
755 | ((~gpio_out_pins & mask) != mask)) { | ||
756 | local_irq_restore(flags); | ||
757 | printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); | ||
758 | } | ||
759 | owners = gpio_pg_owners; | ||
760 | break; | ||
761 | default: | ||
762 | owners = NULL; /* Cannot happen. Shut up, gcc! */ | ||
763 | } | ||
764 | |||
765 | for (i = start_bit; i <= stop_bit; i++) { | ||
766 | if (owners[i] != ioif) { | ||
767 | printk(KERN_CRIT "cris_io_interface_free_pins: Freeing unowned pins"); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | /* All was ok, change data. */ | ||
772 | switch (port) { | ||
773 | case 'a': | ||
774 | gpio_pa_pins |= mask; | ||
775 | break; | ||
776 | case 'b': | ||
777 | gpio_pb_pins |= mask; | ||
778 | break; | ||
779 | case 'g': | ||
780 | gpio_in_pins |= mask; | ||
781 | gpio_out_pins |= mask; | ||
782 | break; | ||
783 | } | ||
784 | |||
785 | for (i = start_bit; i <= stop_bit; i++) { | ||
786 | owners[i] = if_unclaimed; | ||
787 | } | ||
788 | local_irq_restore(flags); | ||
789 | notify_watchers(); | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | |||
795 | int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available, | ||
796 | const unsigned int gpio_out_available, | ||
797 | const unsigned char pa_available, | ||
798 | const unsigned char pb_available)) | ||
799 | { | ||
800 | struct watcher *w; | ||
801 | |||
802 | (void)cris_io_interface_init(); | ||
803 | |||
804 | if (NULL == notify) { | ||
805 | return -EINVAL; | ||
806 | } | ||
807 | w = kmalloc(sizeof(*w), GFP_KERNEL); | ||
808 | if (!w) { | ||
809 | return -ENOMEM; | ||
810 | } | ||
811 | w->notify = notify; | ||
812 | w->next = watchers; | ||
813 | watchers = w; | ||
814 | |||
815 | w->notify((const unsigned int)gpio_in_pins, | ||
816 | (const unsigned int)gpio_out_pins, | ||
817 | (const unsigned char)gpio_pa_pins, | ||
818 | (const unsigned char)gpio_pb_pins); | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available, | ||
824 | const unsigned int gpio_out_available, | ||
825 | const unsigned char pa_available, | ||
826 | const unsigned char pb_available)) | ||
827 | { | ||
828 | struct watcher *w = watchers, *prev = NULL; | ||
829 | |||
830 | (void)cris_io_interface_init(); | ||
831 | |||
832 | while ((NULL != w) && (w->notify != notify)){ | ||
833 | prev = w; | ||
834 | w = w->next; | ||
835 | } | ||
836 | if (NULL != w) { | ||
837 | if (NULL != prev) { | ||
838 | prev->next = w->next; | ||
839 | } else { | ||
840 | watchers = w->next; | ||
841 | } | ||
842 | kfree(w); | ||
843 | return; | ||
844 | } | ||
845 | printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify); | ||
846 | } | ||
847 | |||
848 | |||
849 | static int cris_io_interface_init(void) | ||
850 | { | ||
851 | static int first = 1; | ||
852 | int i; | ||
853 | |||
854 | if (!first) { | ||
855 | return 0; | ||
856 | } | ||
857 | first = 0; | ||
858 | |||
859 | for (i = 0; i<8; i++) { | ||
860 | gpio_pa_owners[i] = if_unclaimed; | ||
861 | gpio_pb_owners[i] = if_unclaimed; | ||
862 | gpio_pg_owners[i] = if_unclaimed; | ||
863 | } | ||
864 | for (; i<32; i++) { | ||
865 | gpio_pg_owners[i] = if_unclaimed; | ||
866 | } | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | |||
871 | module_init(cris_io_interface_init); | ||
872 | |||
873 | |||
874 | EXPORT_SYMBOL(cris_request_io_interface); | ||
875 | EXPORT_SYMBOL(cris_free_io_interface); | ||
876 | EXPORT_SYMBOL(cris_io_interface_allocate_pins); | ||
877 | EXPORT_SYMBOL(cris_io_interface_free_pins); | ||
878 | EXPORT_SYMBOL(cris_io_interface_register_watcher); | ||
879 | EXPORT_SYMBOL(cris_io_interface_delete_watcher); | ||
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c index 561a890a8e4c..38fd44dfbc5b 100644 --- a/arch/cris/arch-v10/kernel/shadows.c +++ b/arch/cris/arch-v10/kernel/shadows.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | 1 | /* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $ |
2 | * | 2 | * |
3 | * Various shadow registers. Defines for these are in include/asm-etrax100/io.h | 3 | * Various shadow registers. Defines for these are in include/asm-etrax100/io.h |
4 | */ | 4 | */ |
@@ -6,6 +6,7 @@ | |||
6 | /* Shadows for internal Etrax-registers */ | 6 | /* Shadows for internal Etrax-registers */ |
7 | 7 | ||
8 | unsigned long genconfig_shadow; | 8 | unsigned long genconfig_shadow; |
9 | unsigned long gen_config_ii_shadow; | ||
9 | unsigned long port_g_data_shadow; | 10 | unsigned long port_g_data_shadow; |
10 | unsigned char port_pa_dir_shadow; | 11 | unsigned char port_pa_dir_shadow; |
11 | unsigned char port_pa_data_shadow; | 12 | unsigned char port_pa_data_shadow; |