diff options
Diffstat (limited to 'arch/cris/arch-v32/mach-fs')
-rw-r--r-- | arch/cris/arch-v32/mach-fs/Kconfig | 216 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/Makefile | 11 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/arbiter.c | 404 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/cpufreq.c | 146 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/dma.c | 230 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/dram_init.S | 116 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/hw_settings.S | 70 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/io.c | 191 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/pinmux.c | 309 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/vcs_hook.c | 100 | ||||
-rw-r--r-- | arch/cris/arch-v32/mach-fs/vcs_hook.h | 42 |
11 files changed, 1835 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/mach-fs/Kconfig b/arch/cris/arch-v32/mach-fs/Kconfig new file mode 100644 index 000000000000..f6d74475f1c6 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/Kconfig | |||
@@ -0,0 +1,216 @@ | |||
1 | if ETRAXFS | ||
2 | |||
3 | menu "ETRAX FS options" | ||
4 | depends on ETRAXFS | ||
5 | |||
6 | config ETRAX_DRAM_VIRTUAL_BASE | ||
7 | hex | ||
8 | depends on ETRAX_ARCH_V32 | ||
9 | default "c0000000" | ||
10 | |||
11 | config ETRAX_SERIAL_PORTS | ||
12 | int | ||
13 | default 4 | ||
14 | |||
15 | config ETRAX_MEM_GRP1_CONFIG | ||
16 | hex "MEM_GRP1_CONFIG" | ||
17 | depends on ETRAX_ARCH_V32 | ||
18 | default "4044a" | ||
19 | help | ||
20 | Waitstates for flash. The default value is suitable for the | ||
21 | standard flashes used in axis products (120 ns). | ||
22 | |||
23 | config ETRAX_MEM_GRP2_CONFIG | ||
24 | hex "MEM_GRP2_CONFIG" | ||
25 | depends on ETRAX_ARCH_V32 | ||
26 | default "0" | ||
27 | help | ||
28 | Waitstates for SRAM. 0 is a good choice for most Axis products. | ||
29 | |||
30 | config ETRAX_MEM_GRP3_CONFIG | ||
31 | hex "MEM_GRP3_CONFIG" | ||
32 | depends on ETRAX_ARCH_V32 | ||
33 | default "0" | ||
34 | help | ||
35 | Waitstates for CSP0-3. 0 is a good choice for most Axis products. | ||
36 | It may need to be changed if external devices such as extra | ||
37 | register-mapped LEDs are used. | ||
38 | |||
39 | config ETRAX_MEM_GRP4_CONFIG | ||
40 | hex "MEM_GRP4_CONFIG" | ||
41 | depends on ETRAX_ARCH_V32 | ||
42 | default "0" | ||
43 | help | ||
44 | Waitstates for CSP4-6. 0 is a good choice for most Axis products. | ||
45 | |||
46 | config ETRAX_SDRAM_GRP0_CONFIG | ||
47 | hex "SDRAM_GRP0_CONFIG" | ||
48 | depends on ETRAX_ARCH_V32 | ||
49 | default "336" | ||
50 | help | ||
51 | SDRAM configuration for group 0. The value depends on the | ||
52 | hardware configuration. The default value is suitable | ||
53 | for 32 MB organized as two 16 bits chips (e.g. Axis | ||
54 | part number 18550) connected as one 32 bit device (i.e. in | ||
55 | the same group). | ||
56 | |||
57 | config ETRAX_SDRAM_GRP1_CONFIG | ||
58 | hex "SDRAM_GRP1_CONFIG" | ||
59 | depends on ETRAX_ARCH_V32 | ||
60 | default "0" | ||
61 | help | ||
62 | SDRAM configuration for group 1. The defult value is 0 | ||
63 | because group 1 is not used in the default configuration, | ||
64 | described in the help for SDRAM_GRP0_CONFIG. | ||
65 | |||
66 | config ETRAX_SDRAM_TIMING | ||
67 | hex "SDRAM_TIMING" | ||
68 | depends on ETRAX_ARCH_V32 | ||
69 | default "104a" | ||
70 | help | ||
71 | SDRAM timing parameters. The default value is ok for | ||
72 | most hardwares but large SDRAMs may require a faster | ||
73 | refresh (a.k.a 8K refresh). The default value implies | ||
74 | 100MHz clock and SDR mode. | ||
75 | |||
76 | config ETRAX_SDRAM_COMMAND | ||
77 | hex "SDRAM_COMMAND" | ||
78 | depends on ETRAX_ARCH_V32 | ||
79 | default "0" | ||
80 | help | ||
81 | SDRAM command. Should be 0 unless you really know what | ||
82 | you are doing (may be != 0 for unusual address line | ||
83 | mappings such as in a MCM).. | ||
84 | |||
85 | config ETRAX_DEF_GIO_PA_OE | ||
86 | hex "GIO_PA_OE" | ||
87 | depends on ETRAX_ARCH_V32 | ||
88 | default "1c" | ||
89 | help | ||
90 | Configures the direction of general port A bits. 1 is out, 0 is in. | ||
91 | This is often totally different depending on the product used. | ||
92 | There are some guidelines though - if you know that only LED's are | ||
93 | connected to port PA, then they are usually connected to bits 2-4 | ||
94 | and you can therefore use 1c. On other boards which don't have the | ||
95 | LED's at the general ports, these bits are used for all kinds of | ||
96 | stuff. If you don't know what to use, it is always safe to put all | ||
97 | as inputs, although floating inputs isn't good. | ||
98 | |||
99 | config ETRAX_DEF_GIO_PA_OUT | ||
100 | hex "GIO_PA_OUT" | ||
101 | depends on ETRAX_ARCH_V32 | ||
102 | default "00" | ||
103 | help | ||
104 | Configures the initial data for the general port A bits. Most | ||
105 | products should use 00 here. | ||
106 | |||
107 | config ETRAX_DEF_GIO_PB_OE | ||
108 | hex "GIO_PB_OE" | ||
109 | depends on ETRAX_ARCH_V32 | ||
110 | default "00000" | ||
111 | help | ||
112 | Configures the direction of general port B bits. 1 is out, 0 is in. | ||
113 | This is often totally different depending on the product used. | ||
114 | There are some guidelines though - if you know that only LED's are | ||
115 | connected to port PA, then they are usually connected to bits 2-4 | ||
116 | and you can therefore use 1c. On other boards which don't have the | ||
117 | LED's at the general ports, these bits are used for all kinds of | ||
118 | stuff. If you don't know what to use, it is always safe to put all | ||
119 | as inputs, although floating inputs isn't good. | ||
120 | |||
121 | config ETRAX_DEF_GIO_PB_OUT | ||
122 | hex "GIO_PB_OUT" | ||
123 | depends on ETRAX_ARCH_V32 | ||
124 | default "00000" | ||
125 | help | ||
126 | Configures the initial data for the general port B bits. Most | ||
127 | products should use 00000 here. | ||
128 | |||
129 | config ETRAX_DEF_GIO_PC_OE | ||
130 | hex "GIO_PC_OE" | ||
131 | depends on ETRAX_ARCH_V32 | ||
132 | default "00000" | ||
133 | help | ||
134 | Configures the direction of general port C bits. 1 is out, 0 is in. | ||
135 | This is often totally different depending on the product used. | ||
136 | There are some guidelines though - if you know that only LED's are | ||
137 | connected to port PA, then they are usually connected to bits 2-4 | ||
138 | and you can therefore use 1c. On other boards which don't have the | ||
139 | LED's at the general ports, these bits are used for all kinds of | ||
140 | stuff. If you don't know what to use, it is always safe to put all | ||
141 | as inputs, although floating inputs isn't good. | ||
142 | |||
143 | config ETRAX_DEF_GIO_PC_OUT | ||
144 | hex "GIO_PC_OUT" | ||
145 | depends on ETRAX_ARCH_V32 | ||
146 | default "00000" | ||
147 | help | ||
148 | Configures the initial data for the general port C bits. Most | ||
149 | products should use 00000 here. | ||
150 | |||
151 | config ETRAX_DEF_GIO_PD_OE | ||
152 | hex "GIO_PD_OE" | ||
153 | depends on ETRAX_ARCH_V32 | ||
154 | default "00000" | ||
155 | help | ||
156 | Configures the direction of general port D bits. 1 is out, 0 is in. | ||
157 | This is often totally different depending on the product used. | ||
158 | There are some guidelines though - if you know that only LED's are | ||
159 | connected to port PA, then they are usually connected to bits 2-4 | ||
160 | and you can therefore use 1c. On other boards which don't have the | ||
161 | LED's at the general ports, these bits are used for all kinds of | ||
162 | stuff. If you don't know what to use, it is always safe to put all | ||
163 | as inputs, although floating inputs isn't good. | ||
164 | |||
165 | config ETRAX_DEF_GIO_PD_OUT | ||
166 | hex "GIO_PD_OUT" | ||
167 | depends on ETRAX_ARCH_V32 | ||
168 | default "00000" | ||
169 | help | ||
170 | Configures the initial data for the general port D bits. Most | ||
171 | products should use 00000 here. | ||
172 | |||
173 | config ETRAX_DEF_GIO_PE_OE | ||
174 | hex "GIO_PE_OE" | ||
175 | depends on ETRAX_ARCH_V32 | ||
176 | default "00000" | ||
177 | help | ||
178 | Configures the direction of general port E bits. 1 is out, 0 is in. | ||
179 | This is often totally different depending on the product used. | ||
180 | There are some guidelines though - if you know that only LED's are | ||
181 | connected to port PA, then they are usually connected to bits 2-4 | ||
182 | and you can therefore use 1c. On other boards which don't have the | ||
183 | LED's at the general ports, these bits are used for all kinds of | ||
184 | stuff. If you don't know what to use, it is always safe to put all | ||
185 | as inputs, although floating inputs isn't good. | ||
186 | |||
187 | config ETRAX_DEF_GIO_PE_OUT | ||
188 | hex "GIO_PE_OUT" | ||
189 | depends on ETRAX_ARCH_V32 | ||
190 | default "00000" | ||
191 | help | ||
192 | Configures the initial data for the general port E bits. Most | ||
193 | products should use 00000 here. | ||
194 | |||
195 | config ETRAX_DEF_GIO_PV_OE | ||
196 | hex "GIO_PV_OE" | ||
197 | depends on ETRAX_VIRTUAL_GPIO | ||
198 | default "0000" | ||
199 | help | ||
200 | Configures the direction of virtual general port V bits. 1 is out, | ||
201 | 0 is in. This is often totally different depending on the product | ||
202 | used. These bits are used for all kinds of stuff. If you don't know | ||
203 | what to use, it is always safe to put all as inputs, although | ||
204 | floating inputs isn't good. | ||
205 | |||
206 | config ETRAX_DEF_GIO_PV_OUT | ||
207 | hex "GIO_PV_OUT" | ||
208 | depends on ETRAX_VIRTUAL_GPIO | ||
209 | default "0000" | ||
210 | help | ||
211 | Configures the initial data for the virtual general port V bits. | ||
212 | Most products should use 0000 here. | ||
213 | |||
214 | endmenu | ||
215 | |||
216 | endif | ||
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile new file mode 100644 index 000000000000..4ff407a1b931 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | obj-y := dma.o pinmux.o io.o arbiter.o | ||
7 | bj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o | ||
8 | obj-$(CONFIG_CPU_FREQ) += cpufreq.o | ||
9 | |||
10 | clean: | ||
11 | |||
diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c new file mode 100644 index 000000000000..84d31bd7b692 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/arbiter.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * Memory arbiter functions. Allocates bandwidth through the | ||
3 | * arbiter and sets up arbiter breakpoints. | ||
4 | * | ||
5 | * The algorithm first assigns slots to the clients that has specified | ||
6 | * bandwidth (e.g. ethernet) and then the remaining slots are divided | ||
7 | * on all the active clients. | ||
8 | * | ||
9 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
10 | */ | ||
11 | |||
12 | #include <hwregs/reg_map.h> | ||
13 | #include <hwregs/reg_rdwr.h> | ||
14 | #include <hwregs/marb_defs.h> | ||
15 | #include <arbiter.h> | ||
16 | #include <hwregs/intr_vect.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/irq_regs.h> | ||
23 | |||
24 | struct crisv32_watch_entry { | ||
25 | unsigned long instance; | ||
26 | watch_callback *cb; | ||
27 | unsigned long start; | ||
28 | unsigned long end; | ||
29 | int used; | ||
30 | }; | ||
31 | |||
32 | #define NUMBER_OF_BP 4 | ||
33 | #define NBR_OF_CLIENTS 14 | ||
34 | #define NBR_OF_SLOTS 64 | ||
35 | #define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ | ||
36 | #define INTMEM_BANDWIDTH 400000000 | ||
37 | #define NBR_OF_REGIONS 2 | ||
38 | |||
39 | static struct crisv32_watch_entry watches[NUMBER_OF_BP] = { | ||
40 | {regi_marb_bp0}, | ||
41 | {regi_marb_bp1}, | ||
42 | {regi_marb_bp2}, | ||
43 | {regi_marb_bp3} | ||
44 | }; | ||
45 | |||
46 | static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
47 | static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; | ||
48 | static int max_bandwidth[NBR_OF_REGIONS] = | ||
49 | { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH }; | ||
50 | |||
51 | DEFINE_SPINLOCK(arbiter_lock); | ||
52 | |||
53 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id); | ||
54 | |||
55 | /* | ||
56 | * "I'm the arbiter, I know the score. | ||
57 | * From square one I'll be watching all 64." | ||
58 | * (memory arbiter slots, that is) | ||
59 | * | ||
60 | * Or in other words: | ||
61 | * Program the memory arbiter slots for "region" according to what's | ||
62 | * in requested_slots[] and active_clients[], while minimizing | ||
63 | * latency. A caller may pass a non-zero positive amount for | ||
64 | * "unused_slots", which must then be the unallocated, remaining | ||
65 | * number of slots, free to hand out to any client. | ||
66 | */ | ||
67 | |||
68 | static void crisv32_arbiter_config(int region, int unused_slots) | ||
69 | { | ||
70 | int slot; | ||
71 | int client; | ||
72 | int interval = 0; | ||
73 | |||
74 | /* | ||
75 | * This vector corresponds to the hardware arbiter slots (see | ||
76 | * the hardware documentation for semantics). We initialize | ||
77 | * each slot with a suitable sentinel value outside the valid | ||
78 | * range {0 .. NBR_OF_CLIENTS - 1} and replace them with | ||
79 | * client indexes. Then it's fed to the hardware. | ||
80 | */ | ||
81 | s8 val[NBR_OF_SLOTS]; | ||
82 | |||
83 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) | ||
84 | val[slot] = -1; | ||
85 | |||
86 | for (client = 0; client < NBR_OF_CLIENTS; client++) { | ||
87 | int pos; | ||
88 | /* Allocate the requested non-zero number of slots, but | ||
89 | * also give clients with zero-requests one slot each | ||
90 | * while stocks last. We do the latter here, in client | ||
91 | * order. This makes sure zero-request clients are the | ||
92 | * first to get to any spare slots, else those slots | ||
93 | * could, when bandwidth is allocated close to the limit, | ||
94 | * all be allocated to low-index non-zero-request clients | ||
95 | * in the default-fill loop below. Another positive but | ||
96 | * secondary effect is a somewhat better spread of the | ||
97 | * zero-bandwidth clients in the vector, avoiding some of | ||
98 | * the latency that could otherwise be caused by the | ||
99 | * partitioning of non-zero-bandwidth clients at low | ||
100 | * indexes and zero-bandwidth clients at high | ||
101 | * indexes. (Note that this spreading can only affect the | ||
102 | * unallocated bandwidth.) All the above only matters for | ||
103 | * memory-intensive situations, of course. | ||
104 | */ | ||
105 | if (!requested_slots[region][client]) { | ||
106 | /* | ||
107 | * Skip inactive clients. Also skip zero-slot | ||
108 | * allocations in this pass when there are no known | ||
109 | * free slots. | ||
110 | */ | ||
111 | if (!active_clients[region][client] | ||
112 | || unused_slots <= 0) | ||
113 | continue; | ||
114 | |||
115 | unused_slots--; | ||
116 | |||
117 | /* Only allocate one slot for this client. */ | ||
118 | interval = NBR_OF_SLOTS; | ||
119 | } else | ||
120 | interval = | ||
121 | NBR_OF_SLOTS / requested_slots[region][client]; | ||
122 | |||
123 | pos = 0; | ||
124 | while (pos < NBR_OF_SLOTS) { | ||
125 | if (val[pos] >= 0) | ||
126 | pos++; | ||
127 | else { | ||
128 | val[pos] = client; | ||
129 | pos += interval; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | client = 0; | ||
135 | for (slot = 0; slot < NBR_OF_SLOTS; slot++) { | ||
136 | /* | ||
137 | * Allocate remaining slots in round-robin | ||
138 | * client-number order for active clients. For this | ||
139 | * pass, we ignore requested bandwidth and previous | ||
140 | * allocations. | ||
141 | */ | ||
142 | if (val[slot] < 0) { | ||
143 | int first = client; | ||
144 | while (!active_clients[region][client]) { | ||
145 | client = (client + 1) % NBR_OF_CLIENTS; | ||
146 | if (client == first) | ||
147 | break; | ||
148 | } | ||
149 | val[slot] = client; | ||
150 | client = (client + 1) % NBR_OF_CLIENTS; | ||
151 | } | ||
152 | if (region == EXT_REGION) | ||
153 | REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, | ||
154 | val[slot]); | ||
155 | else if (region == INT_REGION) | ||
156 | REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, | ||
157 | val[slot]); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | extern char _stext, _etext; | ||
162 | |||
163 | static void crisv32_arbiter_init(void) | ||
164 | { | ||
165 | static int initialized; | ||
166 | |||
167 | if (initialized) | ||
168 | return; | ||
169 | |||
170 | initialized = 1; | ||
171 | |||
172 | /* | ||
173 | * CPU caches are always set to active, but with zero | ||
174 | * bandwidth allocated. It should be ok to allocate zero | ||
175 | * bandwidth for the caches, because DMA for other channels | ||
176 | * will supposedly finish, once their programmed amount is | ||
177 | * done, and then the caches will get access according to the | ||
178 | * "fixed scheme" for unclaimed slots. Though, if for some | ||
179 | * use-case somewhere, there's a maximum CPU latency for | ||
180 | * e.g. some interrupt, we have to start allocating specific | ||
181 | * bandwidth for the CPU caches too. | ||
182 | */ | ||
183 | active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; | ||
184 | crisv32_arbiter_config(EXT_REGION, 0); | ||
185 | crisv32_arbiter_config(INT_REGION, 0); | ||
186 | |||
187 | if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED, | ||
188 | "arbiter", NULL)) | ||
189 | printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); | ||
190 | |||
191 | #ifndef CONFIG_ETRAX_KGDB | ||
192 | /* Global watch for writes to kernel text segment. */ | ||
193 | crisv32_arbiter_watch(virt_to_phys(&_stext), &_etext - &_stext, | ||
194 | arbiter_all_clients, arbiter_all_write, NULL); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | /* Main entry for bandwidth allocation. */ | ||
199 | |||
200 | int crisv32_arbiter_allocate_bandwidth(int client, int region, | ||
201 | unsigned long bandwidth) | ||
202 | { | ||
203 | int i; | ||
204 | int total_assigned = 0; | ||
205 | int total_clients = 0; | ||
206 | int req; | ||
207 | |||
208 | crisv32_arbiter_init(); | ||
209 | |||
210 | for (i = 0; i < NBR_OF_CLIENTS; i++) { | ||
211 | total_assigned += requested_slots[region][i]; | ||
212 | total_clients += active_clients[region][i]; | ||
213 | } | ||
214 | |||
215 | /* Avoid division by 0 for 0-bandwidth requests. */ | ||
216 | req = bandwidth == 0 | ||
217 | ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); | ||
218 | |||
219 | /* | ||
220 | * We make sure that there are enough slots only for non-zero | ||
221 | * requests. Requesting 0 bandwidth *may* allocate slots, | ||
222 | * though if all bandwidth is allocated, such a client won't | ||
223 | * get any and will have to rely on getting memory access | ||
224 | * according to the fixed scheme that's the default when one | ||
225 | * of the slot-allocated clients doesn't claim their slot. | ||
226 | */ | ||
227 | if (total_assigned + req > NBR_OF_SLOTS) | ||
228 | return -ENOMEM; | ||
229 | |||
230 | active_clients[region][client] = 1; | ||
231 | requested_slots[region][client] = req; | ||
232 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Main entry for bandwidth deallocation. | ||
239 | * | ||
240 | * Strictly speaking, for a somewhat constant set of clients where | ||
241 | * each client gets a constant bandwidth and is just enabled or | ||
242 | * disabled (somewhat dynamically), no action is necessary here to | ||
243 | * avoid starvation for non-zero-allocation clients, as the allocated | ||
244 | * slots will just be unused. However, handing out those unused slots | ||
245 | * to active clients avoids needless latency if the "fixed scheme" | ||
246 | * would give unclaimed slots to an eager low-index client. | ||
247 | */ | ||
248 | |||
249 | void crisv32_arbiter_deallocate_bandwidth(int client, int region) | ||
250 | { | ||
251 | int i; | ||
252 | int total_assigned = 0; | ||
253 | |||
254 | requested_slots[region][client] = 0; | ||
255 | active_clients[region][client] = 0; | ||
256 | |||
257 | for (i = 0; i < NBR_OF_CLIENTS; i++) | ||
258 | total_assigned += requested_slots[region][i]; | ||
259 | |||
260 | crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); | ||
261 | } | ||
262 | |||
263 | int crisv32_arbiter_watch(unsigned long start, unsigned long size, | ||
264 | unsigned long clients, unsigned long accesses, | ||
265 | watch_callback *cb) | ||
266 | { | ||
267 | int i; | ||
268 | |||
269 | crisv32_arbiter_init(); | ||
270 | |||
271 | if (start > 0x80000000) { | ||
272 | printk(KERN_ERR "Arbiter: %lX doesn't look like a " | ||
273 | "physical address", start); | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | spin_lock(&arbiter_lock); | ||
278 | |||
279 | for (i = 0; i < NUMBER_OF_BP; i++) { | ||
280 | if (!watches[i].used) { | ||
281 | reg_marb_rw_intr_mask intr_mask = | ||
282 | REG_RD(marb, regi_marb, rw_intr_mask); | ||
283 | |||
284 | watches[i].used = 1; | ||
285 | watches[i].start = start; | ||
286 | watches[i].end = start + size; | ||
287 | watches[i].cb = cb; | ||
288 | |||
289 | REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, | ||
290 | watches[i].start); | ||
291 | REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, | ||
292 | watches[i].end); | ||
293 | REG_WR_INT(marb_bp, watches[i].instance, rw_op, | ||
294 | accesses); | ||
295 | REG_WR_INT(marb_bp, watches[i].instance, rw_clients, | ||
296 | clients); | ||
297 | |||
298 | if (i == 0) | ||
299 | intr_mask.bp0 = regk_marb_yes; | ||
300 | else if (i == 1) | ||
301 | intr_mask.bp1 = regk_marb_yes; | ||
302 | else if (i == 2) | ||
303 | intr_mask.bp2 = regk_marb_yes; | ||
304 | else if (i == 3) | ||
305 | intr_mask.bp3 = regk_marb_yes; | ||
306 | |||
307 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
308 | spin_unlock(&arbiter_lock); | ||
309 | |||
310 | return i; | ||
311 | } | ||
312 | } | ||
313 | spin_unlock(&arbiter_lock); | ||
314 | return -ENOMEM; | ||
315 | } | ||
316 | |||
317 | int crisv32_arbiter_unwatch(int id) | ||
318 | { | ||
319 | reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); | ||
320 | |||
321 | crisv32_arbiter_init(); | ||
322 | |||
323 | spin_lock(&arbiter_lock); | ||
324 | |||
325 | if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { | ||
326 | spin_unlock(&arbiter_lock); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); | ||
331 | |||
332 | if (id == 0) | ||
333 | intr_mask.bp0 = regk_marb_no; | ||
334 | else if (id == 1) | ||
335 | intr_mask.bp2 = regk_marb_no; | ||
336 | else if (id == 2) | ||
337 | intr_mask.bp2 = regk_marb_no; | ||
338 | else if (id == 3) | ||
339 | intr_mask.bp3 = regk_marb_no; | ||
340 | |||
341 | REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); | ||
342 | |||
343 | spin_unlock(&arbiter_lock); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | extern void show_registers(struct pt_regs *regs); | ||
348 | |||
349 | static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id) | ||
350 | { | ||
351 | reg_marb_r_masked_intr masked_intr = | ||
352 | REG_RD(marb, regi_marb, r_masked_intr); | ||
353 | reg_marb_bp_r_brk_clients r_clients; | ||
354 | reg_marb_bp_r_brk_addr r_addr; | ||
355 | reg_marb_bp_r_brk_op r_op; | ||
356 | reg_marb_bp_r_brk_first_client r_first; | ||
357 | reg_marb_bp_r_brk_size r_size; | ||
358 | reg_marb_bp_rw_ack ack = { 0 }; | ||
359 | reg_marb_rw_ack_intr ack_intr = { | ||
360 | .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 | ||
361 | }; | ||
362 | struct crisv32_watch_entry *watch; | ||
363 | |||
364 | if (masked_intr.bp0) { | ||
365 | watch = &watches[0]; | ||
366 | ack_intr.bp0 = regk_marb_yes; | ||
367 | } else if (masked_intr.bp1) { | ||
368 | watch = &watches[1]; | ||
369 | ack_intr.bp1 = regk_marb_yes; | ||
370 | } else if (masked_intr.bp2) { | ||
371 | watch = &watches[2]; | ||
372 | ack_intr.bp2 = regk_marb_yes; | ||
373 | } else if (masked_intr.bp3) { | ||
374 | watch = &watches[3]; | ||
375 | ack_intr.bp3 = regk_marb_yes; | ||
376 | } else { | ||
377 | return IRQ_NONE; | ||
378 | } | ||
379 | |||
380 | /* Retrieve all useful information and print it. */ | ||
381 | r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); | ||
382 | r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); | ||
383 | r_op = REG_RD(marb_bp, watch->instance, r_brk_op); | ||
384 | r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); | ||
385 | r_size = REG_RD(marb_bp, watch->instance, r_brk_size); | ||
386 | |||
387 | printk(KERN_INFO "Arbiter IRQ\n"); | ||
388 | printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n", | ||
389 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), | ||
390 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), | ||
391 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), | ||
392 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), | ||
393 | REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); | ||
394 | |||
395 | REG_WR(marb_bp, watch->instance, rw_ack, ack); | ||
396 | REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); | ||
397 | |||
398 | printk(KERN_INFO "IRQ occured at %lX\n", get_irq_regs()->erp); | ||
399 | |||
400 | if (watch->cb) | ||
401 | watch->cb(); | ||
402 | |||
403 | return IRQ_HANDLED; | ||
404 | } | ||
diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/arch/cris/arch-v32/mach-fs/cpufreq.c new file mode 100644 index 000000000000..d57631c0d8d1 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/cpufreq.c | |||
@@ -0,0 +1,146 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/cpufreq.h> | ||
4 | #include <hwregs/reg_map.h> | ||
5 | #include <asm/arch/hwregs/reg_rdwr.h> | ||
6 | #include <asm/arch/hwregs/config_defs.h> | ||
7 | #include <asm/arch/hwregs/bif_core_defs.h> | ||
8 | |||
9 | static int | ||
10 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
11 | void *data); | ||
12 | |||
13 | static struct notifier_block cris_sdram_freq_notifier_block = { | ||
14 | .notifier_call = cris_sdram_freq_notifier | ||
15 | }; | ||
16 | |||
17 | static struct cpufreq_frequency_table cris_freq_table[] = { | ||
18 | {0x01, 6000}, | ||
19 | {0x02, 200000}, | ||
20 | {0, CPUFREQ_TABLE_END}, | ||
21 | }; | ||
22 | |||
23 | static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) | ||
24 | { | ||
25 | reg_config_rw_clk_ctrl clk_ctrl; | ||
26 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | ||
27 | return clk_ctrl.pll ? 200000 : 6000; | ||
28 | } | ||
29 | |||
30 | static void cris_freq_set_cpu_state(unsigned int state) | ||
31 | { | ||
32 | int i; | ||
33 | struct cpufreq_freqs freqs; | ||
34 | reg_config_rw_clk_ctrl clk_ctrl; | ||
35 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | ||
36 | |||
37 | for_each_possible_cpu(i) { | ||
38 | freqs.old = cris_freq_get_cpu_frequency(i); | ||
39 | freqs.new = cris_freq_table[state].frequency; | ||
40 | freqs.cpu = i; | ||
41 | } | ||
42 | |||
43 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
44 | |||
45 | local_irq_disable(); | ||
46 | |||
47 | /* Even though we may be SMP they will share the same clock | ||
48 | * so all settings are made on CPU0. */ | ||
49 | if (cris_freq_table[state].frequency == 200000) | ||
50 | clk_ctrl.pll = 1; | ||
51 | else | ||
52 | clk_ctrl.pll = 0; | ||
53 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); | ||
54 | |||
55 | local_irq_enable(); | ||
56 | |||
57 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
58 | }; | ||
59 | |||
60 | static int cris_freq_verify(struct cpufreq_policy *policy) | ||
61 | { | ||
62 | return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]); | ||
63 | } | ||
64 | |||
65 | static int cris_freq_target(struct cpufreq_policy *policy, | ||
66 | unsigned int target_freq, unsigned int relation) | ||
67 | { | ||
68 | unsigned int newstate = 0; | ||
69 | |||
70 | if (cpufreq_frequency_table_target | ||
71 | (policy, cris_freq_table, target_freq, relation, &newstate)) | ||
72 | return -EINVAL; | ||
73 | |||
74 | cris_freq_set_cpu_state(newstate); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int cris_freq_cpu_init(struct cpufreq_policy *policy) | ||
80 | { | ||
81 | int result; | ||
82 | |||
83 | /* cpuinfo and default policy values */ | ||
84 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
85 | policy->cpuinfo.transition_latency = 1000000; /* 1ms */ | ||
86 | policy->cur = cris_freq_get_cpu_frequency(0); | ||
87 | |||
88 | result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table); | ||
89 | if (result) | ||
90 | return (result); | ||
91 | |||
92 | cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int cris_freq_cpu_exit(struct cpufreq_policy *policy) | ||
98 | { | ||
99 | cpufreq_frequency_table_put_attr(policy->cpu); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static struct freq_attr *cris_freq_attr[] = { | ||
104 | &cpufreq_freq_attr_scaling_available_freqs, | ||
105 | NULL, | ||
106 | }; | ||
107 | |||
108 | static struct cpufreq_driver cris_freq_driver = { | ||
109 | .get = cris_freq_get_cpu_frequency, | ||
110 | .verify = cris_freq_verify, | ||
111 | .target = cris_freq_target, | ||
112 | .init = cris_freq_cpu_init, | ||
113 | .exit = cris_freq_cpu_exit, | ||
114 | .name = "cris_freq", | ||
115 | .owner = THIS_MODULE, | ||
116 | .attr = cris_freq_attr, | ||
117 | }; | ||
118 | |||
119 | static int __init cris_freq_init(void) | ||
120 | { | ||
121 | int ret; | ||
122 | ret = cpufreq_register_driver(&cris_freq_driver); | ||
123 | cpufreq_register_notifier(&cris_sdram_freq_notifier_block, | ||
124 | CPUFREQ_TRANSITION_NOTIFIER); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | static int | ||
129 | cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val, | ||
130 | void *data) | ||
131 | { | ||
132 | int i; | ||
133 | struct cpufreq_freqs *freqs = data; | ||
134 | if (val == CPUFREQ_PRECHANGE) { | ||
135 | reg_bif_core_rw_sdram_timing timing = | ||
136 | REG_RD(bif_core, regi_bif_core, rw_sdram_timing); | ||
137 | timing.cpd = (freqs->new == 200000 ? 0 : 1); | ||
138 | |||
139 | if (freqs->new == 200000) | ||
140 | for (i = 0; i < 50000; i++) ; | ||
141 | REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing); | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | module_init(cris_freq_init); | ||
diff --git a/arch/cris/arch-v32/mach-fs/dma.c b/arch/cris/arch-v32/mach-fs/dma.c new file mode 100644 index 000000000000..a6acf4e6345c --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/dma.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* Wrapper for DMA channel allocator that starts clocks etc */ | ||
2 | |||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/spinlock.h> | ||
5 | #include <asm/dma.h> | ||
6 | #include <hwregs/reg_map.h> | ||
7 | #include <hwregs/reg_rdwr.h> | ||
8 | #include <hwregs/marb_defs.h> | ||
9 | #include <hwregs/config_defs.h> | ||
10 | #include <hwregs/strmux_defs.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <asm/system.h> | ||
13 | #include <asm/arch/mach/arbiter.h> | ||
14 | |||
15 | static char used_dma_channels[MAX_DMA_CHANNELS]; | ||
16 | static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; | ||
17 | |||
18 | static DEFINE_SPINLOCK(dma_lock); | ||
19 | |||
20 | int crisv32_request_dma(unsigned int dmanr, const char *device_id, | ||
21 | unsigned options, unsigned int bandwidth, | ||
22 | enum dma_owner owner) | ||
23 | { | ||
24 | unsigned long flags; | ||
25 | reg_config_rw_clk_ctrl clk_ctrl; | ||
26 | reg_strmux_rw_cfg strmux_cfg; | ||
27 | |||
28 | if (crisv32_arbiter_allocate_bandwidth(dmanr, | ||
29 | options & DMA_INT_MEM ? | ||
30 | INT_REGION : EXT_REGION, | ||
31 | bandwidth)) | ||
32 | return -ENOMEM; | ||
33 | |||
34 | spin_lock_irqsave(&dma_lock, flags); | ||
35 | |||
36 | if (used_dma_channels[dmanr]) { | ||
37 | spin_unlock_irqrestore(&dma_lock, flags); | ||
38 | if (options & DMA_VERBOSE_ON_ERROR) { | ||
39 | printk(KERN_ERR "Failed to request DMA %i for %s, " | ||
40 | "already allocated by %s\n", | ||
41 | dmanr, | ||
42 | device_id, | ||
43 | used_dma_channels_users[dmanr]); | ||
44 | } | ||
45 | if (options & DMA_PANIC_ON_ERROR) | ||
46 | panic("request_dma error!"); | ||
47 | spin_unlock_irqrestore(&dma_lock, flags); | ||
48 | return -EBUSY; | ||
49 | } | ||
50 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | ||
51 | strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); | ||
52 | |||
53 | switch (dmanr) { | ||
54 | case 0: | ||
55 | case 1: | ||
56 | clk_ctrl.dma01_eth0 = 1; | ||
57 | break; | ||
58 | case 2: | ||
59 | case 3: | ||
60 | clk_ctrl.dma23 = 1; | ||
61 | break; | ||
62 | case 4: | ||
63 | case 5: | ||
64 | clk_ctrl.dma45 = 1; | ||
65 | break; | ||
66 | case 6: | ||
67 | case 7: | ||
68 | clk_ctrl.dma67 = 1; | ||
69 | break; | ||
70 | case 8: | ||
71 | case 9: | ||
72 | clk_ctrl.dma89_strcop = 1; | ||
73 | break; | ||
74 | #if MAX_DMA_CHANNELS-1 != 9 | ||
75 | #error Check dma.c | ||
76 | #endif | ||
77 | default: | ||
78 | spin_unlock_irqrestore(&dma_lock, flags); | ||
79 | if (options & DMA_VERBOSE_ON_ERROR) { | ||
80 | printk(KERN_ERR "Failed to request DMA %i for %s, " | ||
81 | "only 0-%i valid)\n", | ||
82 | dmanr, device_id, MAX_DMA_CHANNELS - 1); | ||
83 | } | ||
84 | |||
85 | if (options & DMA_PANIC_ON_ERROR) | ||
86 | panic("request_dma error!"); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | switch (owner) { | ||
91 | case dma_eth0: | ||
92 | if (dmanr == 0) | ||
93 | strmux_cfg.dma0 = regk_strmux_eth0; | ||
94 | else if (dmanr == 1) | ||
95 | strmux_cfg.dma1 = regk_strmux_eth0; | ||
96 | else | ||
97 | panic("Invalid DMA channel for eth0\n"); | ||
98 | break; | ||
99 | case dma_eth1: | ||
100 | if (dmanr == 6) | ||
101 | strmux_cfg.dma6 = regk_strmux_eth1; | ||
102 | else if (dmanr == 7) | ||
103 | strmux_cfg.dma7 = regk_strmux_eth1; | ||
104 | else | ||
105 | panic("Invalid DMA channel for eth1\n"); | ||
106 | break; | ||
107 | case dma_iop0: | ||
108 | if (dmanr == 2) | ||
109 | strmux_cfg.dma2 = regk_strmux_iop0; | ||
110 | else if (dmanr == 3) | ||
111 | strmux_cfg.dma3 = regk_strmux_iop0; | ||
112 | else | ||
113 | panic("Invalid DMA channel for iop0\n"); | ||
114 | break; | ||
115 | case dma_iop1: | ||
116 | if (dmanr == 4) | ||
117 | strmux_cfg.dma4 = regk_strmux_iop1; | ||
118 | else if (dmanr == 5) | ||
119 | strmux_cfg.dma5 = regk_strmux_iop1; | ||
120 | else | ||
121 | panic("Invalid DMA channel for iop1\n"); | ||
122 | break; | ||
123 | case dma_ser0: | ||
124 | if (dmanr == 6) | ||
125 | strmux_cfg.dma6 = regk_strmux_ser0; | ||
126 | else if (dmanr == 7) | ||
127 | strmux_cfg.dma7 = regk_strmux_ser0; | ||
128 | else | ||
129 | panic("Invalid DMA channel for ser0\n"); | ||
130 | break; | ||
131 | case dma_ser1: | ||
132 | if (dmanr == 4) | ||
133 | strmux_cfg.dma4 = regk_strmux_ser1; | ||
134 | else if (dmanr == 5) | ||
135 | strmux_cfg.dma5 = regk_strmux_ser1; | ||
136 | else | ||
137 | panic("Invalid DMA channel for ser1\n"); | ||
138 | break; | ||
139 | case dma_ser2: | ||
140 | if (dmanr == 2) | ||
141 | strmux_cfg.dma2 = regk_strmux_ser2; | ||
142 | else if (dmanr == 3) | ||
143 | strmux_cfg.dma3 = regk_strmux_ser2; | ||
144 | else | ||
145 | panic("Invalid DMA channel for ser2\n"); | ||
146 | break; | ||
147 | case dma_ser3: | ||
148 | if (dmanr == 8) | ||
149 | strmux_cfg.dma8 = regk_strmux_ser3; | ||
150 | else if (dmanr == 9) | ||
151 | strmux_cfg.dma9 = regk_strmux_ser3; | ||
152 | else | ||
153 | panic("Invalid DMA channel for ser3\n"); | ||
154 | break; | ||
155 | case dma_sser0: | ||
156 | if (dmanr == 4) | ||
157 | strmux_cfg.dma4 = regk_strmux_sser0; | ||
158 | else if (dmanr == 5) | ||
159 | strmux_cfg.dma5 = regk_strmux_sser0; | ||
160 | else | ||
161 | panic("Invalid DMA channel for sser0\n"); | ||
162 | break; | ||
163 | case dma_sser1: | ||
164 | if (dmanr == 6) | ||
165 | strmux_cfg.dma6 = regk_strmux_sser1; | ||
166 | else if (dmanr == 7) | ||
167 | strmux_cfg.dma7 = regk_strmux_sser1; | ||
168 | else | ||
169 | panic("Invalid DMA channel for sser1\n"); | ||
170 | break; | ||
171 | case dma_ata: | ||
172 | if (dmanr == 2) | ||
173 | strmux_cfg.dma2 = regk_strmux_ata; | ||
174 | else if (dmanr == 3) | ||
175 | strmux_cfg.dma3 = regk_strmux_ata; | ||
176 | else | ||
177 | panic("Invalid DMA channel for ata\n"); | ||
178 | break; | ||
179 | case dma_strp: | ||
180 | if (dmanr == 8) | ||
181 | strmux_cfg.dma8 = regk_strmux_strcop; | ||
182 | else if (dmanr == 9) | ||
183 | strmux_cfg.dma9 = regk_strmux_strcop; | ||
184 | else | ||
185 | panic("Invalid DMA channel for strp\n"); | ||
186 | break; | ||
187 | case dma_ext0: | ||
188 | if (dmanr == 6) | ||
189 | strmux_cfg.dma6 = regk_strmux_ext0; | ||
190 | else | ||
191 | panic("Invalid DMA channel for ext0\n"); | ||
192 | break; | ||
193 | case dma_ext1: | ||
194 | if (dmanr == 7) | ||
195 | strmux_cfg.dma7 = regk_strmux_ext1; | ||
196 | else | ||
197 | panic("Invalid DMA channel for ext1\n"); | ||
198 | break; | ||
199 | case dma_ext2: | ||
200 | if (dmanr == 2) | ||
201 | strmux_cfg.dma2 = regk_strmux_ext2; | ||
202 | else if (dmanr == 8) | ||
203 | strmux_cfg.dma8 = regk_strmux_ext2; | ||
204 | else | ||
205 | panic("Invalid DMA channel for ext2\n"); | ||
206 | break; | ||
207 | case dma_ext3: | ||
208 | if (dmanr == 3) | ||
209 | strmux_cfg.dma3 = regk_strmux_ext3; | ||
210 | else if (dmanr == 9) | ||
211 | strmux_cfg.dma9 = regk_strmux_ext2; | ||
212 | else | ||
213 | panic("Invalid DMA channel for ext2\n"); | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | used_dma_channels[dmanr] = 1; | ||
218 | used_dma_channels_users[dmanr] = device_id; | ||
219 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); | ||
220 | REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); | ||
221 | spin_unlock_irqrestore(&dma_lock, flags); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | void crisv32_free_dma(unsigned int dmanr) | ||
226 | { | ||
227 | spin_lock(&dma_lock); | ||
228 | used_dma_channels[dmanr] = 0; | ||
229 | spin_unlock(&dma_lock); | ||
230 | } | ||
diff --git a/arch/cris/arch-v32/mach-fs/dram_init.S b/arch/cris/arch-v32/mach-fs/dram_init.S new file mode 100644 index 000000000000..6fbad336527b --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/dram_init.S | |||
@@ -0,0 +1,116 @@ | |||
1 | /* | ||
2 | * DRAM/SDRAM initialization - alter with care | ||
3 | * This file is intended to be included from other assembler files | ||
4 | * | ||
5 | * Note: This file may not modify r8 or r9 because they are used to | ||
6 | * carry information from the decompresser to the kernel | ||
7 | * | ||
8 | * Copyright (C) 2000-2007 Axis Communications AB | ||
9 | * | ||
10 | * Authors: Mikael Starvik <starvik@axis.com> | ||
11 | */ | ||
12 | |||
13 | /* Just to be certain the config file is included, we include it here | ||
14 | * explicitely instead of depending on it being included in the file that | ||
15 | * uses this code. | ||
16 | */ | ||
17 | |||
18 | #include <hwregs/asm/reg_map_asm.h> | ||
19 | #include <hwregs/asm/bif_core_defs_asm.h> | ||
20 | |||
21 | ;; WARNING! The registers r8 and r9 are used as parameters carrying | ||
22 | ;; information from the decompressor (if the kernel was compressed). | ||
23 | ;; They should not be used in the code below. | ||
24 | |||
25 | ; Refer to BIF MDS for a description of SDRAM initialization | ||
26 | |||
27 | ; Bank configuration | ||
28 | move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0), $r0 | ||
29 | move.d CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1 | ||
30 | move.d $r1, [$r0] | ||
31 | move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1), $r0 | ||
32 | move.d CONFIG_ETRAX_SDRAM_GRP1_CONFIG, $r1 | ||
33 | move.d $r1, [$r0] | ||
34 | |||
35 | ; Calculate value of mrs_data | ||
36 | ; CAS latency = 2 && bus_width = 32 => 0x40 | ||
37 | ; CAS latency = 3 && bus_width = 32 => 0x60 | ||
38 | ; CAS latency = 2 && bus_width = 16 => 0x20 | ||
39 | ; CAS latency = 3 && bus_width = 16 => 0x30 | ||
40 | |||
41 | ; Check if value is already supplied in kernel config | ||
42 | move.d CONFIG_ETRAX_SDRAM_COMMAND, $r2 | ||
43 | bne _set_timing | ||
44 | nop | ||
45 | |||
46 | move.d 0x40, $r4 ; Assume 32 bits and CAS latency = 2 | ||
47 | move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 | ||
48 | and.d 0x07, $r1 ; Get CAS latency | ||
49 | cmpq 2, $r1 ; CL = 2 ? | ||
50 | beq _bw_check | ||
51 | nop | ||
52 | move.d 0x60, $r4 | ||
53 | |||
54 | _bw_check: | ||
55 | ; Assume that group 0 width is equal to group 1. This assumption | ||
56 | ; is wrong for a group 1 only hardware (such as the grand old | ||
57 | ; StorPoint+). | ||
58 | move.d CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1 | ||
59 | and.d 0x200, $r1 ; DRAM width is bit 9 | ||
60 | beq _set_timing | ||
61 | lslq 2, $r4 ; mrs_data starts at bit 2 | ||
62 | lsrq 1, $r4 ; 16 bits. Shift down value. | ||
63 | |||
64 | ; Set timing parameters (refresh off to avoid Guinness TR 83) | ||
65 | _set_timing: | ||
66 | move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 | ||
67 | and.d ~(3 << reg_bif_core_rw_sdram_timing___ref___lsb), $r1 | ||
68 | move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0 | ||
69 | move.d $r1, [$r0] | ||
70 | |||
71 | ; Issue NOP command | ||
72 | move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd), $r5 | ||
73 | moveq regk_bif_core_nop, $r1 | ||
74 | move.d $r1, [$r5] | ||
75 | |||
76 | ; Wait 200us | ||
77 | move.d 10000, $r2 | ||
78 | 1: bne 1b | ||
79 | subq 1, $r2 | ||
80 | |||
81 | ; Issue initialization command sequence | ||
82 | lapc _sdram_commands_start, $r2 | ||
83 | lapc _sdram_commands_end, $r3 | ||
84 | 1: clear.d $r6 | ||
85 | move.b [$r2+], $r6 ; Load command | ||
86 | or.d $r4, $r6 ; Add calculated mrs | ||
87 | move.d $r6, [$r5] ; Write rw_sdram_cmd | ||
88 | ; Wait 80 ns between each command | ||
89 | move.d 4000, $r7 | ||
90 | 2: bne 2b | ||
91 | subq 1, $r7 | ||
92 | cmp.d $r2, $r3 ; Last command? | ||
93 | bne 1b | ||
94 | nop | ||
95 | |||
96 | ; Start refresh | ||
97 | move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 | ||
98 | move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0 | ||
99 | move.d $r1, [$r0] | ||
100 | |||
101 | ; Initialization finished | ||
102 | ba _sdram_commands_end | ||
103 | nop | ||
104 | |||
105 | _sdram_commands_start: | ||
106 | .byte regk_bif_core_pre ; Precharge | ||
107 | .byte regk_bif_core_ref ; refresh | ||
108 | .byte regk_bif_core_ref ; refresh | ||
109 | .byte regk_bif_core_ref ; refresh | ||
110 | .byte regk_bif_core_ref ; refresh | ||
111 | .byte regk_bif_core_ref ; refresh | ||
112 | .byte regk_bif_core_ref ; refresh | ||
113 | .byte regk_bif_core_ref ; refresh | ||
114 | .byte regk_bif_core_ref ; refresh | ||
115 | .byte regk_bif_core_mrs ; mrs | ||
116 | _sdram_commands_end: | ||
diff --git a/arch/cris/arch-v32/mach-fs/hw_settings.S b/arch/cris/arch-v32/mach-fs/hw_settings.S new file mode 100644 index 000000000000..8bde93c36214 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/hw_settings.S | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * This table is used by some tools to extract hardware parameters. | ||
3 | * The table should be included in the kernel and the decompressor. | ||
4 | * Don't forget to update the tools if you change this table. | ||
5 | * | ||
6 | * Copyright (C) 2001-2007 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Mikael Starvik <starvik@axis.com> | ||
9 | */ | ||
10 | |||
11 | #include <hwregs/asm/reg_map_asm.h> | ||
12 | #include <hwregs/asm/bif_core_defs_asm.h> | ||
13 | #include <hwregs/asm/gio_defs_asm.h> | ||
14 | |||
15 | .ascii "HW_PARAM_MAGIC" ; Magic number | ||
16 | .dword 0xc0004000 ; Kernel start address | ||
17 | |||
18 | ; Debug port | ||
19 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | ||
20 | .dword 0 | ||
21 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
22 | .dword 1 | ||
23 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
24 | .dword 2 | ||
25 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
26 | .dword 3 | ||
27 | #else | ||
28 | .dword 4 ; No debug | ||
29 | #endif | ||
30 | |||
31 | ; Register values | ||
32 | .dword REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg) | ||
33 | .dword CONFIG_ETRAX_MEM_GRP1_CONFIG | ||
34 | .dword REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg) | ||
35 | .dword CONFIG_ETRAX_MEM_GRP2_CONFIG | ||
36 | .dword REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg) | ||
37 | .dword CONFIG_ETRAX_MEM_GRP3_CONFIG | ||
38 | .dword REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg) | ||
39 | .dword CONFIG_ETRAX_MEM_GRP4_CONFIG | ||
40 | .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0) | ||
41 | .dword CONFIG_ETRAX_SDRAM_GRP0_CONFIG | ||
42 | .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1) | ||
43 | .dword CONFIG_ETRAX_SDRAM_GRP1_CONFIG | ||
44 | .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing) | ||
45 | .dword CONFIG_ETRAX_SDRAM_TIMING | ||
46 | .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd) | ||
47 | .dword CONFIG_ETRAX_SDRAM_COMMAND | ||
48 | |||
49 | .dword REG_ADDR(gio, regi_gio, rw_pa_dout) | ||
50 | .dword CONFIG_ETRAX_DEF_GIO_PA_OUT | ||
51 | .dword REG_ADDR(gio, regi_gio, rw_pa_oe) | ||
52 | .dword CONFIG_ETRAX_DEF_GIO_PA_OE | ||
53 | .dword REG_ADDR(gio, regi_gio, rw_pb_dout) | ||
54 | .dword CONFIG_ETRAX_DEF_GIO_PB_OUT | ||
55 | .dword REG_ADDR(gio, regi_gio, rw_pb_oe) | ||
56 | .dword CONFIG_ETRAX_DEF_GIO_PB_OE | ||
57 | .dword REG_ADDR(gio, regi_gio, rw_pc_dout) | ||
58 | .dword CONFIG_ETRAX_DEF_GIO_PC_OUT | ||
59 | .dword REG_ADDR(gio, regi_gio, rw_pc_oe) | ||
60 | .dword CONFIG_ETRAX_DEF_GIO_PC_OE | ||
61 | .dword REG_ADDR(gio, regi_gio, rw_pd_dout) | ||
62 | .dword CONFIG_ETRAX_DEF_GIO_PD_OUT | ||
63 | .dword REG_ADDR(gio, regi_gio, rw_pd_oe) | ||
64 | .dword CONFIG_ETRAX_DEF_GIO_PD_OE | ||
65 | .dword REG_ADDR(gio, regi_gio, rw_pe_dout) | ||
66 | .dword CONFIG_ETRAX_DEF_GIO_PE_OUT | ||
67 | .dword REG_ADDR(gio, regi_gio, rw_pe_oe) | ||
68 | .dword CONFIG_ETRAX_DEF_GIO_PE_OE | ||
69 | |||
70 | .dword 0 ; No more register values | ||
diff --git a/arch/cris/arch-v32/mach-fs/io.c b/arch/cris/arch-v32/mach-fs/io.c new file mode 100644 index 000000000000..a03a3ad3a188 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/io.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * Helper functions for I/O pins. | ||
3 | * | ||
4 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
5 | */ | ||
6 | |||
7 | #include <linux/types.h> | ||
8 | #include <linux/errno.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/arch/pinmux.h> | ||
16 | #include <asm/arch/hwregs/gio_defs.h> | ||
17 | |||
18 | #ifndef DEBUG | ||
19 | #define DEBUG(x) | ||
20 | #endif | ||
21 | |||
22 | struct crisv32_ioport crisv32_ioports[] = { | ||
23 | { | ||
24 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_oe), | ||
25 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pa_dout), | ||
26 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pa_din), | ||
27 | 8 | ||
28 | }, | ||
29 | { | ||
30 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_oe), | ||
31 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pb_dout), | ||
32 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pb_din), | ||
33 | 18 | ||
34 | }, | ||
35 | { | ||
36 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_oe), | ||
37 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pc_dout), | ||
38 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pc_din), | ||
39 | 18 | ||
40 | }, | ||
41 | { | ||
42 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_oe), | ||
43 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pd_dout), | ||
44 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pd_din), | ||
45 | 18 | ||
46 | }, | ||
47 | { | ||
48 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_oe), | ||
49 | (unsigned long *)REG_ADDR(gio, regi_gio, rw_pe_dout), | ||
50 | (unsigned long *)REG_ADDR(gio, regi_gio, r_pe_din), | ||
51 | 18 | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | #define NBR_OF_PORTS sizeof(crisv32_ioports)/sizeof(struct crisv32_ioport) | ||
56 | |||
57 | struct crisv32_iopin crisv32_led_net0_green; | ||
58 | struct crisv32_iopin crisv32_led_net0_red; | ||
59 | struct crisv32_iopin crisv32_led_net1_green; | ||
60 | struct crisv32_iopin crisv32_led_net1_red; | ||
61 | struct crisv32_iopin crisv32_led2_green; | ||
62 | struct crisv32_iopin crisv32_led2_red; | ||
63 | struct crisv32_iopin crisv32_led3_green; | ||
64 | struct crisv32_iopin crisv32_led3_red; | ||
65 | |||
66 | /* Dummy port used when green LED and red LED is on the same bit */ | ||
67 | static unsigned long io_dummy; | ||
68 | static struct crisv32_ioport dummy_port = { | ||
69 | &io_dummy, | ||
70 | &io_dummy, | ||
71 | &io_dummy, | ||
72 | 18 | ||
73 | }; | ||
74 | static struct crisv32_iopin dummy_led = { | ||
75 | &dummy_port, | ||
76 | 0 | ||
77 | }; | ||
78 | |||
79 | static int __init crisv32_io_init(void) | ||
80 | { | ||
81 | int ret = 0; | ||
82 | |||
83 | u32 i; | ||
84 | |||
85 | /* Locks *should* be dynamically initialized. */ | ||
86 | for (i = 0; i < ARRAY_SIZE(crisv32_ioports); i++) | ||
87 | spin_lock_init(&crisv32_ioports[i].lock); | ||
88 | spin_lock_init(&dummy_port.lock); | ||
89 | |||
90 | /* Initialize LEDs */ | ||
91 | #if (defined(CONFIG_ETRAX_NBR_LED_GRP_ONE) || defined(CONFIG_ETRAX_NBR_LED_GRP_TWO)) | ||
92 | ret += | ||
93 | crisv32_io_get_name(&crisv32_led_net0_green, | ||
94 | CONFIG_ETRAX_LED_G_NET0); | ||
95 | crisv32_io_set_dir(&crisv32_led_net0_green, crisv32_io_dir_out); | ||
96 | if (strcmp(CONFIG_ETRAX_LED_G_NET0, CONFIG_ETRAX_LED_R_NET0)) { | ||
97 | ret += | ||
98 | crisv32_io_get_name(&crisv32_led_net0_red, | ||
99 | CONFIG_ETRAX_LED_R_NET0); | ||
100 | crisv32_io_set_dir(&crisv32_led_net0_red, crisv32_io_dir_out); | ||
101 | } else | ||
102 | crisv32_led_net0_red = dummy_led; | ||
103 | #endif | ||
104 | |||
105 | #ifdef CONFIG_ETRAX_NBR_LED_GRP_TWO | ||
106 | ret += | ||
107 | crisv32_io_get_name(&crisv32_led_net1_green, | ||
108 | CONFIG_ETRAX_LED_G_NET1); | ||
109 | crisv32_io_set_dir(&crisv32_led_net1_green, crisv32_io_dir_out); | ||
110 | if (strcmp(CONFIG_ETRAX_LED_G_NET1, CONFIG_ETRAX_LED_R_NET1)) { | ||
111 | crisv32_io_get_name(&crisv32_led_net1_red, | ||
112 | CONFIG_ETRAX_LED_R_NET1); | ||
113 | crisv32_io_set_dir(&crisv32_led_net1_red, crisv32_io_dir_out); | ||
114 | } else | ||
115 | crisv32_led_net1_red = dummy_led; | ||
116 | #endif | ||
117 | |||
118 | ret += crisv32_io_get_name(&crisv32_led2_green, CONFIG_ETRAX_V32_LED2G); | ||
119 | ret += crisv32_io_get_name(&crisv32_led2_red, CONFIG_ETRAX_V32_LED2R); | ||
120 | ret += crisv32_io_get_name(&crisv32_led3_green, CONFIG_ETRAX_V32_LED3G); | ||
121 | ret += crisv32_io_get_name(&crisv32_led3_red, CONFIG_ETRAX_V32_LED3R); | ||
122 | |||
123 | crisv32_io_set_dir(&crisv32_led2_green, crisv32_io_dir_out); | ||
124 | crisv32_io_set_dir(&crisv32_led2_red, crisv32_io_dir_out); | ||
125 | crisv32_io_set_dir(&crisv32_led3_green, crisv32_io_dir_out); | ||
126 | crisv32_io_set_dir(&crisv32_led3_red, crisv32_io_dir_out); | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | __initcall(crisv32_io_init); | ||
132 | |||
133 | int crisv32_io_get(struct crisv32_iopin *iopin, | ||
134 | unsigned int port, unsigned int pin) | ||
135 | { | ||
136 | if (port > NBR_OF_PORTS) | ||
137 | return -EINVAL; | ||
138 | if (port > crisv32_ioports[port].pin_count) | ||
139 | return -EINVAL; | ||
140 | |||
141 | iopin->bit = 1 << pin; | ||
142 | iopin->port = &crisv32_ioports[port]; | ||
143 | |||
144 | /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ | ||
145 | /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ | ||
146 | if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) | ||
147 | return -EIO; | ||
148 | DEBUG(printk(KERN_DEBUG "crisv32_io_get: Allocated pin %d on port %d\n", | ||
149 | pin, port)); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | int crisv32_io_get_name(struct crisv32_iopin *iopin, const char *name) | ||
155 | { | ||
156 | int port; | ||
157 | int pin; | ||
158 | |||
159 | if (toupper(*name) == 'P') | ||
160 | name++; | ||
161 | |||
162 | if (toupper(*name) < 'A' || toupper(*name) > 'E') | ||
163 | return -EINVAL; | ||
164 | |||
165 | port = toupper(*name) - 'A'; | ||
166 | name++; | ||
167 | pin = simple_strtoul(name, NULL, 10); | ||
168 | |||
169 | if (pin < 0 || pin > crisv32_ioports[port].pin_count) | ||
170 | return -EINVAL; | ||
171 | |||
172 | iopin->bit = 1 << pin; | ||
173 | iopin->port = &crisv32_ioports[port]; | ||
174 | |||
175 | /* Only allocate pinmux gpiopins if port != PORT_A (port 0) */ | ||
176 | /* NOTE! crisv32_pinmux_alloc thinks PORT_B is port 0 */ | ||
177 | if (port != 0 && crisv32_pinmux_alloc(port - 1, pin, pin, pinmux_gpio)) | ||
178 | return -EIO; | ||
179 | |||
180 | DEBUG(printk(KERN_DEBUG | ||
181 | "crisv32_io_get_name: Allocated pin %d on port %d\n", | ||
182 | pin, port)); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | #ifdef CONFIG_PCI | ||
188 | /* PCI I/O access stuff */ | ||
189 | struct cris_io_operations *cris_iops = NULL; | ||
190 | EXPORT_SYMBOL(cris_iops); | ||
191 | #endif | ||
diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c new file mode 100644 index 000000000000..d722ad9ae626 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/pinmux.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Allocator for I/O pins. All pins are allocated to GPIO at bootup. | ||
3 | * Unassigned pins and GPIO pins can be allocated to a fixed interface | ||
4 | * or the I/O processor instead. | ||
5 | * | ||
6 | * Copyright (c) 2004-2007 Axis Communications AB. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <hwregs/reg_map.h> | ||
15 | #include <hwregs/reg_rdwr.h> | ||
16 | #include <pinmux.h> | ||
17 | #include <hwregs/pinmux_defs.h> | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #define PORT_PINS 18 | ||
22 | #define PORTS 4 | ||
23 | |||
24 | static char pins[PORTS][PORT_PINS]; | ||
25 | static DEFINE_SPINLOCK(pinmux_lock); | ||
26 | |||
27 | static void crisv32_pinmux_set(int port); | ||
28 | |||
29 | int crisv32_pinmux_init(void) | ||
30 | { | ||
31 | static int initialized; | ||
32 | |||
33 | if (!initialized) { | ||
34 | reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa); | ||
35 | initialized = 1; | ||
36 | REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0); | ||
37 | pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 = | ||
38 | pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes; | ||
39 | REG_WR(pinmux, regi_pinmux, rw_pa, pa); | ||
40 | crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); | ||
41 | crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); | ||
42 | crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); | ||
43 | crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); | ||
44 | } | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | int | ||
50 | crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) | ||
51 | { | ||
52 | int i; | ||
53 | unsigned long flags; | ||
54 | |||
55 | crisv32_pinmux_init(); | ||
56 | |||
57 | if (port > PORTS) | ||
58 | return -EINVAL; | ||
59 | |||
60 | spin_lock_irqsave(&pinmux_lock, flags); | ||
61 | |||
62 | for (i = first_pin; i <= last_pin; i++) { | ||
63 | if ((pins[port][i] != pinmux_none) | ||
64 | && (pins[port][i] != pinmux_gpio) | ||
65 | && (pins[port][i] != mode)) { | ||
66 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
67 | #ifdef DEBUG | ||
68 | panic("Pinmux alloc failed!\n"); | ||
69 | #endif | ||
70 | return -EPERM; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | for (i = first_pin; i <= last_pin; i++) | ||
75 | pins[port][i] = mode; | ||
76 | |||
77 | crisv32_pinmux_set(port); | ||
78 | |||
79 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int crisv32_pinmux_alloc_fixed(enum fixed_function function) | ||
85 | { | ||
86 | int ret = -EINVAL; | ||
87 | char saved[sizeof pins]; | ||
88 | unsigned long flags; | ||
89 | |||
90 | spin_lock_irqsave(&pinmux_lock, flags); | ||
91 | |||
92 | /* Save internal data for recovery */ | ||
93 | memcpy(saved, pins, sizeof pins); | ||
94 | |||
95 | crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ | ||
96 | |||
97 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
98 | |||
99 | switch (function) { | ||
100 | case pinmux_ser1: | ||
101 | ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); | ||
102 | hwprot.ser1 = regk_pinmux_yes; | ||
103 | break; | ||
104 | case pinmux_ser2: | ||
105 | ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); | ||
106 | hwprot.ser2 = regk_pinmux_yes; | ||
107 | break; | ||
108 | case pinmux_ser3: | ||
109 | ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); | ||
110 | hwprot.ser3 = regk_pinmux_yes; | ||
111 | break; | ||
112 | case pinmux_sser0: | ||
113 | ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); | ||
114 | ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | ||
115 | hwprot.sser0 = regk_pinmux_yes; | ||
116 | break; | ||
117 | case pinmux_sser1: | ||
118 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | ||
119 | hwprot.sser1 = regk_pinmux_yes; | ||
120 | break; | ||
121 | case pinmux_ata0: | ||
122 | ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); | ||
123 | ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); | ||
124 | hwprot.ata0 = regk_pinmux_yes; | ||
125 | break; | ||
126 | case pinmux_ata1: | ||
127 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | ||
128 | ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); | ||
129 | hwprot.ata1 = regk_pinmux_yes; | ||
130 | break; | ||
131 | case pinmux_ata2: | ||
132 | ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); | ||
133 | ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); | ||
134 | hwprot.ata2 = regk_pinmux_yes; | ||
135 | break; | ||
136 | case pinmux_ata3: | ||
137 | ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); | ||
138 | ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); | ||
139 | hwprot.ata2 = regk_pinmux_yes; | ||
140 | break; | ||
141 | case pinmux_ata: | ||
142 | ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); | ||
143 | ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); | ||
144 | hwprot.ata = regk_pinmux_yes; | ||
145 | break; | ||
146 | case pinmux_eth1: | ||
147 | ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); | ||
148 | hwprot.eth1 = regk_pinmux_yes; | ||
149 | hwprot.eth1_mgm = regk_pinmux_yes; | ||
150 | break; | ||
151 | case pinmux_timer: | ||
152 | ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | ||
153 | hwprot.timer = regk_pinmux_yes; | ||
154 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | if (!ret) | ||
159 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
160 | else | ||
161 | memcpy(pins, saved, sizeof pins); | ||
162 | |||
163 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | void crisv32_pinmux_set(int port) | ||
169 | { | ||
170 | int i; | ||
171 | int gpio_val = 0; | ||
172 | int iop_val = 0; | ||
173 | |||
174 | for (i = 0; i < PORT_PINS; i++) { | ||
175 | if (pins[port][i] == pinmux_gpio) | ||
176 | gpio_val |= (1 << i); | ||
177 | else if (pins[port][i] == pinmux_iop) | ||
178 | iop_val |= (1 << i); | ||
179 | } | ||
180 | |||
181 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port, | ||
182 | gpio_val); | ||
183 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port, | ||
184 | iop_val); | ||
185 | |||
186 | #ifdef DEBUG | ||
187 | crisv32_pinmux_dump(); | ||
188 | #endif | ||
189 | } | ||
190 | |||
191 | int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) | ||
192 | { | ||
193 | int i; | ||
194 | unsigned long flags; | ||
195 | |||
196 | crisv32_pinmux_init(); | ||
197 | |||
198 | if (port > PORTS) | ||
199 | return -EINVAL; | ||
200 | |||
201 | spin_lock_irqsave(&pinmux_lock, flags); | ||
202 | |||
203 | for (i = first_pin; i <= last_pin; i++) | ||
204 | pins[port][i] = pinmux_none; | ||
205 | |||
206 | crisv32_pinmux_set(port); | ||
207 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int crisv32_pinmux_dealloc_fixed(enum fixed_function function) | ||
213 | { | ||
214 | int ret = -EINVAL; | ||
215 | char saved[sizeof pins]; | ||
216 | unsigned long flags; | ||
217 | |||
218 | spin_lock_irqsave(&pinmux_lock, flags); | ||
219 | |||
220 | /* Save internal data for recovery */ | ||
221 | memcpy(saved, pins, sizeof pins); | ||
222 | |||
223 | crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ | ||
224 | |||
225 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | ||
226 | |||
227 | switch (function) { | ||
228 | case pinmux_ser1: | ||
229 | ret = crisv32_pinmux_dealloc(PORT_C, 4, 7); | ||
230 | hwprot.ser1 = regk_pinmux_no; | ||
231 | break; | ||
232 | case pinmux_ser2: | ||
233 | ret = crisv32_pinmux_dealloc(PORT_C, 8, 11); | ||
234 | hwprot.ser2 = regk_pinmux_no; | ||
235 | break; | ||
236 | case pinmux_ser3: | ||
237 | ret = crisv32_pinmux_dealloc(PORT_C, 12, 15); | ||
238 | hwprot.ser3 = regk_pinmux_no; | ||
239 | break; | ||
240 | case pinmux_sser0: | ||
241 | ret = crisv32_pinmux_dealloc(PORT_C, 0, 3); | ||
242 | ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16); | ||
243 | hwprot.sser0 = regk_pinmux_no; | ||
244 | break; | ||
245 | case pinmux_sser1: | ||
246 | ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); | ||
247 | hwprot.sser1 = regk_pinmux_no; | ||
248 | break; | ||
249 | case pinmux_ata0: | ||
250 | ret = crisv32_pinmux_dealloc(PORT_D, 5, 7); | ||
251 | ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17); | ||
252 | hwprot.ata0 = regk_pinmux_no; | ||
253 | break; | ||
254 | case pinmux_ata1: | ||
255 | ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); | ||
256 | ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17); | ||
257 | hwprot.ata1 = regk_pinmux_no; | ||
258 | break; | ||
259 | case pinmux_ata2: | ||
260 | ret = crisv32_pinmux_dealloc(PORT_C, 11, 15); | ||
261 | ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3); | ||
262 | hwprot.ata2 = regk_pinmux_no; | ||
263 | break; | ||
264 | case pinmux_ata3: | ||
265 | ret = crisv32_pinmux_dealloc(PORT_C, 8, 10); | ||
266 | ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2); | ||
267 | hwprot.ata2 = regk_pinmux_no; | ||
268 | break; | ||
269 | case pinmux_ata: | ||
270 | ret = crisv32_pinmux_dealloc(PORT_B, 0, 15); | ||
271 | ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15); | ||
272 | hwprot.ata = regk_pinmux_no; | ||
273 | break; | ||
274 | case pinmux_eth1: | ||
275 | ret = crisv32_pinmux_dealloc(PORT_E, 0, 17); | ||
276 | hwprot.eth1 = regk_pinmux_no; | ||
277 | hwprot.eth1_mgm = regk_pinmux_no; | ||
278 | break; | ||
279 | case pinmux_timer: | ||
280 | ret = crisv32_pinmux_dealloc(PORT_C, 16, 16); | ||
281 | hwprot.timer = regk_pinmux_no; | ||
282 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | if (!ret) | ||
287 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | ||
288 | else | ||
289 | memcpy(pins, saved, sizeof pins); | ||
290 | |||
291 | spin_unlock_irqrestore(&pinmux_lock, flags); | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | void crisv32_pinmux_dump(void) | ||
297 | { | ||
298 | int i, j; | ||
299 | |||
300 | crisv32_pinmux_init(); | ||
301 | |||
302 | for (i = 0; i < PORTS; i++) { | ||
303 | printk(KERN_DEBUG "Port %c\n", 'B' + i); | ||
304 | for (j = 0; j < PORT_PINS; j++) | ||
305 | printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | __initcall(crisv32_pinmux_init); | ||
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c new file mode 100644 index 000000000000..593b10f07ef1 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/vcs_hook.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Call simulator hook. This is the part running in the | ||
3 | * simulated program. | ||
4 | */ | ||
5 | |||
6 | #include "vcs_hook.h" | ||
7 | #include <stdarg.h> | ||
8 | #include <asm/arch-v32/hwregs/reg_map.h> | ||
9 | #include <asm/arch-v32/hwregs/intr_vect_defs.h> | ||
10 | |||
11 | #define HOOK_TRIG_ADDR 0xb7000000 /* hook cvlog model reg address */ | ||
12 | #define HOOK_MEM_BASE_ADDR 0xa0000000 /* csp4 (shared mem) base addr */ | ||
13 | |||
14 | #define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset] | ||
15 | #define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset] | ||
16 | #define HOOK_TRIG(funcid) \ | ||
17 | do { \ | ||
18 | *((unsigned *) HOOK_TRIG_ADDR) = funcid; \ | ||
19 | } while (0) | ||
20 | #define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset] | ||
21 | |||
22 | int hook_call(unsigned id, unsigned pcnt, ...) | ||
23 | { | ||
24 | va_list ap; | ||
25 | unsigned i; | ||
26 | unsigned ret; | ||
27 | #ifdef USING_SOS | ||
28 | PREEMPT_OFF_SAVE(); | ||
29 | #endif | ||
30 | |||
31 | /* pass parameters */ | ||
32 | HOOK_DATA(0) = id; | ||
33 | |||
34 | /* Have to make hook_print_str a special case since we call with a | ||
35 | * parameter of byte type. Should perhaps be a separate | ||
36 | * hook_call. */ | ||
37 | |||
38 | if (id == hook_print_str) { | ||
39 | int i; | ||
40 | char *str; | ||
41 | |||
42 | HOOK_DATA(1) = pcnt; | ||
43 | |||
44 | va_start(ap, pcnt); | ||
45 | str = (char *)va_arg(ap, unsigned); | ||
46 | |||
47 | for (i = 0; i != pcnt; i++) | ||
48 | HOOK_DATA_BYTE(8 + i) = str[i]; | ||
49 | |||
50 | HOOK_DATA_BYTE(8 + i) = 0; /* null byte */ | ||
51 | } else { | ||
52 | va_start(ap, pcnt); | ||
53 | for (i = 1; i <= pcnt; i++) | ||
54 | HOOK_DATA(i) = va_arg(ap, unsigned); | ||
55 | va_end(ap); | ||
56 | } | ||
57 | |||
58 | /* read from mem to make sure data has propagated to memory before | ||
59 | * trigging */ | ||
60 | ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR); | ||
61 | |||
62 | /* trigger hook */ | ||
63 | HOOK_TRIG(id); | ||
64 | |||
65 | /* wait for call to finish */ | ||
66 | while (VHOOK_DATA(0) > 0) ; | ||
67 | |||
68 | /* extract return value */ | ||
69 | |||
70 | ret = VHOOK_DATA(1); | ||
71 | |||
72 | #ifdef USING_SOS | ||
73 | PREEMPT_RESTORE(); | ||
74 | #endif | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | unsigned hook_buf(unsigned i) | ||
79 | { | ||
80 | return (HOOK_DATA(i)); | ||
81 | } | ||
82 | |||
83 | void print_str(const char *str) | ||
84 | { | ||
85 | int i; | ||
86 | /* find null at end of string */ | ||
87 | for (i = 1; str[i]; i++) ; | ||
88 | hook_call(hook_print_str, i, str); | ||
89 | } | ||
90 | |||
91 | void CPU_KICK_DOG(void) | ||
92 | { | ||
93 | (void)hook_call(hook_kick_dog, 0); | ||
94 | } | ||
95 | |||
96 | void CPU_WATCHDOG_TIMEOUT(unsigned t) | ||
97 | { | ||
98 | (void)hook_call(hook_dog_timeout, 1, t); | ||
99 | } | ||
100 | |||
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h new file mode 100644 index 000000000000..c000b9fece41 --- /dev/null +++ b/arch/cris/arch-v32/mach-fs/vcs_hook.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Call simulator hook functions | ||
3 | */ | ||
4 | |||
5 | #ifndef HOOK_H | ||
6 | #define HOOK_H | ||
7 | |||
8 | int hook_call(unsigned id, unsigned pcnt, ...); | ||
9 | |||
10 | enum hook_ids { | ||
11 | hook_debug_on = 1, | ||
12 | hook_debug_off, | ||
13 | hook_stop_sim_ok, | ||
14 | hook_stop_sim_fail, | ||
15 | hook_alloc_shared, | ||
16 | hook_ptr_shared, | ||
17 | hook_free_shared, | ||
18 | hook_file2shared, | ||
19 | hook_cmp_shared, | ||
20 | hook_print_params, | ||
21 | hook_sim_time, | ||
22 | hook_stop_sim, | ||
23 | hook_kick_dog, | ||
24 | hook_dog_timeout, | ||
25 | hook_rand, | ||
26 | hook_srand, | ||
27 | hook_rand_range, | ||
28 | hook_print_str, | ||
29 | hook_print_hex, | ||
30 | hook_cmp_offset_shared, | ||
31 | hook_fill_random_shared, | ||
32 | hook_alloc_random_data, | ||
33 | hook_calloc_random_data, | ||
34 | hook_print_int, | ||
35 | hook_print_uint, | ||
36 | hook_fputc, | ||
37 | hook_init_fd, | ||
38 | hook_sbrk | ||
39 | |||
40 | }; | ||
41 | |||
42 | #endif | ||