Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
51533b61 MS |
2 | /* Wrapper for DMA channel allocator that starts clocks etc */ |
3 | ||
4 | #include <linux/kernel.h> | |
5 | #include <linux/spinlock.h> | |
6 | #include <asm/dma.h> | |
035e111f JN |
7 | #include <hwregs/reg_map.h> |
8 | #include <hwregs/reg_rdwr.h> | |
9 | #include <hwregs/marb_defs.h> | |
10 | #include <hwregs/config_defs.h> | |
11 | #include <hwregs/strmux_defs.h> | |
51533b61 | 12 | #include <linux/errno.h> |
556dcee7 | 13 | #include <mach/arbiter.h> |
51533b61 MS |
14 | |
15 | static char used_dma_channels[MAX_DMA_CHANNELS]; | |
035e111f | 16 | static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; |
51533b61 MS |
17 | |
18 | static DEFINE_SPINLOCK(dma_lock); | |
19 | ||
035e111f JN |
20 | int crisv32_request_dma(unsigned int dmanr, const char *device_id, |
21 | unsigned options, unsigned int bandwidth, | |
51533b61 MS |
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 | ||
035e111f JN |
28 | if (crisv32_arbiter_allocate_bandwidth(dmanr, |
29 | options & DMA_INT_MEM ? | |
30 | INT_REGION : EXT_REGION, | |
31 | bandwidth)) | |
32 | return -ENOMEM; | |
51533b61 MS |
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) { | |
035e111f JN |
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]); | |
51533b61 MS |
44 | } |
45 | if (options & DMA_PANIC_ON_ERROR) | |
46 | panic("request_dma error!"); | |
47 | return -EBUSY; | |
48 | } | |
49 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | |
50 | strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); | |
51 | ||
035e111f | 52 | switch (dmanr) { |
51533b61 MS |
53 | case 0: |
54 | case 1: | |
55 | clk_ctrl.dma01_eth0 = 1; | |
56 | break; | |
57 | case 2: | |
58 | case 3: | |
59 | clk_ctrl.dma23 = 1; | |
60 | break; | |
61 | case 4: | |
62 | case 5: | |
63 | clk_ctrl.dma45 = 1; | |
64 | break; | |
65 | case 6: | |
66 | case 7: | |
67 | clk_ctrl.dma67 = 1; | |
68 | break; | |
69 | case 8: | |
70 | case 9: | |
71 | clk_ctrl.dma89_strcop = 1; | |
72 | break; | |
73 | #if MAX_DMA_CHANNELS-1 != 9 | |
74 | #error Check dma.c | |
75 | #endif | |
76 | default: | |
77 | spin_unlock_irqrestore(&dma_lock, flags); | |
78 | if (options & DMA_VERBOSE_ON_ERROR) { | |
035e111f JN |
79 | printk(KERN_ERR "Failed to request DMA %i for %s, " |
80 | "only 0-%i valid)\n", | |
81 | dmanr, device_id, MAX_DMA_CHANNELS - 1); | |
51533b61 MS |
82 | } |
83 | ||
84 | if (options & DMA_PANIC_ON_ERROR) | |
85 | panic("request_dma error!"); | |
86 | return -EINVAL; | |
87 | } | |
88 | ||
035e111f | 89 | switch (owner) { |
51533b61 MS |
90 | case dma_eth0: |
91 | if (dmanr == 0) | |
92 | strmux_cfg.dma0 = regk_strmux_eth0; | |
93 | else if (dmanr == 1) | |
94 | strmux_cfg.dma1 = regk_strmux_eth0; | |
95 | else | |
96 | panic("Invalid DMA channel for eth0\n"); | |
97 | break; | |
98 | case dma_eth1: | |
99 | if (dmanr == 6) | |
100 | strmux_cfg.dma6 = regk_strmux_eth1; | |
101 | else if (dmanr == 7) | |
102 | strmux_cfg.dma7 = regk_strmux_eth1; | |
103 | else | |
104 | panic("Invalid DMA channel for eth1\n"); | |
105 | break; | |
106 | case dma_iop0: | |
107 | if (dmanr == 2) | |
108 | strmux_cfg.dma2 = regk_strmux_iop0; | |
109 | else if (dmanr == 3) | |
110 | strmux_cfg.dma3 = regk_strmux_iop0; | |
111 | else | |
112 | panic("Invalid DMA channel for iop0\n"); | |
113 | break; | |
114 | case dma_iop1: | |
115 | if (dmanr == 4) | |
116 | strmux_cfg.dma4 = regk_strmux_iop1; | |
117 | else if (dmanr == 5) | |
118 | strmux_cfg.dma5 = regk_strmux_iop1; | |
119 | else | |
120 | panic("Invalid DMA channel for iop1\n"); | |
121 | break; | |
122 | case dma_ser0: | |
123 | if (dmanr == 6) | |
124 | strmux_cfg.dma6 = regk_strmux_ser0; | |
125 | else if (dmanr == 7) | |
126 | strmux_cfg.dma7 = regk_strmux_ser0; | |
127 | else | |
128 | panic("Invalid DMA channel for ser0\n"); | |
129 | break; | |
130 | case dma_ser1: | |
131 | if (dmanr == 4) | |
132 | strmux_cfg.dma4 = regk_strmux_ser1; | |
133 | else if (dmanr == 5) | |
134 | strmux_cfg.dma5 = regk_strmux_ser1; | |
135 | else | |
136 | panic("Invalid DMA channel for ser1\n"); | |
137 | break; | |
138 | case dma_ser2: | |
139 | if (dmanr == 2) | |
140 | strmux_cfg.dma2 = regk_strmux_ser2; | |
141 | else if (dmanr == 3) | |
142 | strmux_cfg.dma3 = regk_strmux_ser2; | |
143 | else | |
144 | panic("Invalid DMA channel for ser2\n"); | |
145 | break; | |
146 | case dma_ser3: | |
147 | if (dmanr == 8) | |
148 | strmux_cfg.dma8 = regk_strmux_ser3; | |
149 | else if (dmanr == 9) | |
150 | strmux_cfg.dma9 = regk_strmux_ser3; | |
151 | else | |
152 | panic("Invalid DMA channel for ser3\n"); | |
153 | break; | |
154 | case dma_sser0: | |
155 | if (dmanr == 4) | |
156 | strmux_cfg.dma4 = regk_strmux_sser0; | |
157 | else if (dmanr == 5) | |
158 | strmux_cfg.dma5 = regk_strmux_sser0; | |
159 | else | |
160 | panic("Invalid DMA channel for sser0\n"); | |
161 | break; | |
162 | case dma_sser1: | |
163 | if (dmanr == 6) | |
164 | strmux_cfg.dma6 = regk_strmux_sser1; | |
165 | else if (dmanr == 7) | |
166 | strmux_cfg.dma7 = regk_strmux_sser1; | |
167 | else | |
168 | panic("Invalid DMA channel for sser1\n"); | |
169 | break; | |
170 | case dma_ata: | |
171 | if (dmanr == 2) | |
172 | strmux_cfg.dma2 = regk_strmux_ata; | |
173 | else if (dmanr == 3) | |
174 | strmux_cfg.dma3 = regk_strmux_ata; | |
175 | else | |
176 | panic("Invalid DMA channel for ata\n"); | |
177 | break; | |
178 | case dma_strp: | |
179 | if (dmanr == 8) | |
180 | strmux_cfg.dma8 = regk_strmux_strcop; | |
181 | else if (dmanr == 9) | |
182 | strmux_cfg.dma9 = regk_strmux_strcop; | |
183 | else | |
184 | panic("Invalid DMA channel for strp\n"); | |
185 | break; | |
186 | case dma_ext0: | |
187 | if (dmanr == 6) | |
188 | strmux_cfg.dma6 = regk_strmux_ext0; | |
189 | else | |
190 | panic("Invalid DMA channel for ext0\n"); | |
191 | break; | |
192 | case dma_ext1: | |
193 | if (dmanr == 7) | |
194 | strmux_cfg.dma7 = regk_strmux_ext1; | |
195 | else | |
196 | panic("Invalid DMA channel for ext1\n"); | |
197 | break; | |
198 | case dma_ext2: | |
199 | if (dmanr == 2) | |
200 | strmux_cfg.dma2 = regk_strmux_ext2; | |
201 | else if (dmanr == 8) | |
202 | strmux_cfg.dma8 = regk_strmux_ext2; | |
203 | else | |
204 | panic("Invalid DMA channel for ext2\n"); | |
205 | break; | |
206 | case dma_ext3: | |
207 | if (dmanr == 3) | |
208 | strmux_cfg.dma3 = regk_strmux_ext3; | |
209 | else if (dmanr == 9) | |
210 | strmux_cfg.dma9 = regk_strmux_ext2; | |
211 | else | |
212 | panic("Invalid DMA channel for ext2\n"); | |
213 | break; | |
214 | } | |
215 | ||
216 | used_dma_channels[dmanr] = 1; | |
217 | used_dma_channels_users[dmanr] = device_id; | |
218 | REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); | |
219 | REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); | |
035e111f | 220 | spin_unlock_irqrestore(&dma_lock, flags); |
51533b61 MS |
221 | return 0; |
222 | } | |
223 | ||
224 | void crisv32_free_dma(unsigned int dmanr) | |
225 | { | |
226 | spin_lock(&dma_lock); | |
227 | used_dma_channels[dmanr] = 0; | |
228 | spin_unlock(&dma_lock); | |
229 | } |