]>
Commit | Line | Data |
---|---|---|
fe8c2806 WD |
1 | /* |
2 | * (C) Copyright 2001 | |
3 | * John Clemens <clemens@mclx.com>, Mission Critical Linux, Inc. | |
4 | * | |
5 | * See file CREDITS for list of people who contributed to this | |
6 | * project. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License as | |
10 | * published by the Free Software Foundation; either version 2 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | * MA 02111-1307 USA | |
22 | */ | |
23 | ||
24 | /* | |
25 | * mpsc.c - driver for console over the MPSC. | |
26 | */ | |
27 | ||
28 | #include <common.h> | |
29 | #include <config.h> | |
30 | #include <asm/cache.h> | |
31 | ||
32 | #include <malloc.h> | |
33 | #include "mpsc.h" | |
34 | ||
d87080b7 WD |
35 | DECLARE_GLOBAL_DATA_PTR; |
36 | ||
fe8c2806 WD |
37 | int (*mpsc_putchar)(char ch) = mpsc_putchar_early; |
38 | ||
39 | static volatile unsigned int *rx_desc_base=NULL; | |
40 | static unsigned int rx_desc_index=0; | |
41 | static volatile unsigned int *tx_desc_base=NULL; | |
42 | static unsigned int tx_desc_index=0; | |
43 | ||
44 | /* local function declarations */ | |
45 | static int galmpsc_connect(int channel, int connect); | |
46 | static int galmpsc_route_serial(int channel, int connect); | |
47 | static int galmpsc_route_rx_clock(int channel, int brg); | |
48 | static int galmpsc_route_tx_clock(int channel, int brg); | |
49 | static int galmpsc_write_config_regs(int mpsc, int mode); | |
50 | static int galmpsc_config_channel_regs(int mpsc); | |
51 | static int galmpsc_set_char_length(int mpsc, int value); | |
52 | static int galmpsc_set_stop_bit_length(int mpsc, int value); | |
53 | static int galmpsc_set_parity(int mpsc, int value); | |
54 | static int galmpsc_enter_hunt(int mpsc); | |
55 | static int galmpsc_set_brkcnt(int mpsc, int value); | |
56 | static int galmpsc_set_tcschar(int mpsc, int value); | |
57 | static int galmpsc_set_snoop(int mpsc, int value); | |
58 | static int galmpsc_shutdown(int mpsc); | |
59 | ||
60 | static int galsdma_set_RFT(int channel); | |
61 | static int galsdma_set_SFM(int channel); | |
62 | static int galsdma_set_rxle(int channel); | |
63 | static int galsdma_set_txle(int channel); | |
64 | static int galsdma_set_burstsize(int channel, unsigned int value); | |
65 | static int galsdma_set_RC(int channel, unsigned int value); | |
66 | ||
67 | static int galbrg_set_CDV(int channel, int value); | |
68 | static int galbrg_enable(int channel); | |
69 | static int galbrg_disable(int channel); | |
70 | static int galbrg_set_clksrc(int channel, int value); | |
71 | static int galbrg_set_CUV(int channel, int value); | |
72 | ||
73 | static void galsdma_enable_rx(void); | |
74 | ||
75 | /* static int galbrg_reset(int channel); */ | |
76 | ||
77 | #define SOFTWARE_CACHE_MANAGEMENT | |
78 | ||
79 | #ifdef SOFTWARE_CACHE_MANAGEMENT | |
80 | #define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));} | |
81 | #define FLUSH_AND_INVALIDATE_DCACHE(a,b) if(dcache_status()){flush_dcache_range((u32)(a),(u32)(b));} | |
82 | #define INVALIDATE_DCACHE(a,b) if(dcache_status()){invalidate_dcache_range((u32)(a),(u32)(b));} | |
83 | #else | |
84 | #define FLUSH_DCACHE(a,b) | |
85 | #define FLUSH_AND_INVALIDATE_DCACHE(a,b) | |
86 | #define INVALIDATE_DCACHE(a,b) | |
87 | #endif | |
88 | ||
89 | ||
90 | /* GT64240A errata: cant read MPSC/BRG registers... so make mirrors in ram for read/modify write */ | |
91 | #define MIRROR_HACK ((struct _tag_mirror_hack *)&(gd->mirror_hack)) | |
92 | ||
93 | #define GT_REG_WRITE_MIRROR_G(a,d) {MIRROR_HACK->a ## _M = d; GT_REG_WRITE(a,d);} | |
94 | #define GTREGREAD_MIRROR_G(a) (MIRROR_HACK->a ## _M) | |
95 | ||
96 | #define GT_REG_WRITE_MIRROR(a,i,g,d) {MIRROR_HACK->a ## _M[i] = d; GT_REG_WRITE(a + (i*g),d);} | |
97 | #define GTREGREAD_MIRROR(a,i,g) (MIRROR_HACK->a ## _M[i]) | |
98 | ||
99 | /* make sure this isn't bigger than 16 long words (u-boot.h) */ | |
100 | struct _tag_mirror_hack { | |
101 | unsigned GALMPSC_PROTOCONF_REG_M[2]; /* 8008 */ | |
102 | unsigned GALMPSC_CHANNELREG_1_M[2]; /* 800c */ | |
103 | unsigned GALMPSC_CHANNELREG_2_M[2]; /* 8010 */ | |
104 | unsigned GALBRG_0_CONFREG_M[2]; /* b200 */ | |
105 | ||
106 | unsigned GALMPSC_ROUTING_REGISTER_M; /* b400 */ | |
107 | unsigned GALMPSC_RxC_ROUTE_M; /* b404 */ | |
108 | unsigned GALMPSC_TxC_ROUTE_M; /* b408 */ | |
109 | ||
110 | unsigned int baudrate; /* current baudrate, for tsc delay calc */ | |
111 | }; | |
112 | ||
113 | /* static struct _tag_mirror_hack *mh = NULL; */ | |
114 | ||
115 | /* special function for running out of flash. doesn't modify any | |
116 | * global variables [josh] */ | |
117 | int | |
118 | mpsc_putchar_early(char ch) | |
119 | { | |
fe8c2806 WD |
120 | int mpsc=CHANNEL; |
121 | int temp=GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); | |
122 | galmpsc_set_tcschar(mpsc,ch); | |
123 | GT_REG_WRITE(GALMPSC_CHANNELREG_2+(mpsc*GALMPSC_REG_GAP), temp|0x200); | |
124 | ||
125 | #define MAGIC_FACTOR (10*1000000) | |
126 | ||
127 | udelay(MAGIC_FACTOR / MIRROR_HACK->baudrate); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | /* This is used after relocation, see serial.c and mpsc_init2 */ | |
132 | static int | |
133 | mpsc_putchar_sdma(char ch) | |
134 | { | |
8bde7f77 | 135 | volatile unsigned int *p; |
fe8c2806 WD |
136 | unsigned int temp; |
137 | ||
138 | ||
139 | /* align the descriptor */ | |
140 | p = tx_desc_base; | |
141 | memset((void *)p, 0, 8 * sizeof(unsigned int)); | |
142 | ||
143 | /* fill one 64 bit buffer */ | |
144 | /* word swap, pad with 0 */ | |
145 | p[4] = 0; /* x */ | |
146 | p[5] = (unsigned int)ch; /* x */ | |
147 | ||
148 | /* CHANGED completely according to GT64260A dox - NTL */ | |
149 | p[0] = 0x00010001; /* 0 */ | |
150 | p[1] = DESC_OWNER | DESC_FIRST | DESC_LAST; /* 4 */ | |
151 | p[2] = 0; /* 8 */ | |
152 | p[3] = (unsigned int)&p[4]; /* c */ | |
153 | ||
154 | #if 0 | |
155 | p[9] = DESC_FIRST | DESC_LAST; | |
156 | p[10] = (unsigned int)&p[0]; | |
157 | p[11] = (unsigned int)&p[12]; | |
158 | #endif | |
159 | ||
160 | FLUSH_DCACHE(&p[0], &p[8]); | |
161 | ||
162 | GT_REG_WRITE(GALSDMA_0_CUR_TX_PTR+(CHANNEL*GALSDMA_REG_DIFF), | |
163 | (unsigned int)&p[0]); | |
164 | GT_REG_WRITE(GALSDMA_0_FIR_TX_PTR+(CHANNEL*GALSDMA_REG_DIFF), | |
165 | (unsigned int)&p[0]); | |
166 | ||
167 | temp = GTREGREAD(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF)); | |
168 | temp |= (TX_DEMAND | TX_STOP); | |
169 | GT_REG_WRITE(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF), temp); | |
170 | ||
171 | INVALIDATE_DCACHE(&p[1], &p[2]); | |
172 | ||
173 | while(p[1] & DESC_OWNER) { | |
174 | udelay(100); | |
175 | INVALIDATE_DCACHE(&p[1], &p[2]); | |
176 | } | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
d87080b7 | 181 | char mpsc_getchar (void) |
fe8c2806 | 182 | { |
d87080b7 WD |
183 | static unsigned int done = 0; |
184 | volatile char ch; | |
185 | unsigned int len = 0, idx = 0, temp; | |
fe8c2806 | 186 | |
d87080b7 | 187 | volatile unsigned int *p; |
fe8c2806 | 188 | |
fe8c2806 | 189 | |
d87080b7 WD |
190 | do { |
191 | p = &rx_desc_base[rx_desc_index * 8]; | |
192 | ||
193 | INVALIDATE_DCACHE (&p[0], &p[1]); | |
194 | /* Wait for character */ | |
195 | while (p[1] & DESC_OWNER) { | |
196 | udelay (100); | |
197 | INVALIDATE_DCACHE (&p[0], &p[1]); | |
198 | } | |
199 | ||
200 | /* Handle error case */ | |
201 | if (p[1] & (1 << 15)) { | |
202 | printf ("oops, error: %08x\n", p[1]); | |
203 | ||
204 | temp = GTREGREAD_MIRROR (GALMPSC_CHANNELREG_2, | |
205 | CHANNEL, GALMPSC_REG_GAP); | |
206 | temp |= (1 << 23); | |
207 | GT_REG_WRITE_MIRROR (GALMPSC_CHANNELREG_2, CHANNEL, | |
208 | GALMPSC_REG_GAP, temp); | |
209 | ||
210 | /* Can't poll on abort bit, so we just wait. */ | |
211 | udelay (100); | |
212 | ||
213 | galsdma_enable_rx (); | |
214 | } | |
215 | ||
216 | /* Number of bytes left in this descriptor */ | |
217 | len = p[0] & 0xffff; | |
218 | ||
219 | if (len) { | |
220 | /* Where to look */ | |
221 | idx = 5; | |
222 | if (done > 3) | |
223 | idx = 4; | |
224 | if (done > 7) | |
225 | idx = 7; | |
226 | if (done > 11) | |
227 | idx = 6; | |
228 | ||
229 | INVALIDATE_DCACHE (&p[idx], &p[idx + 1]); | |
230 | ch = p[idx] & 0xff; | |
231 | done++; | |
232 | } | |
233 | ||
234 | if (done < len) { | |
235 | /* this descriptor has more bytes still | |
236 | * shift down the char we just read, and leave the | |
237 | * buffer in place for the next time around | |
238 | */ | |
239 | p[idx] = p[idx] >> 8; | |
240 | FLUSH_DCACHE (&p[idx], &p[idx + 1]); | |
241 | } | |
242 | ||
243 | if (done == len) { | |
244 | /* nothing left in this descriptor. | |
245 | * go to next one | |
246 | */ | |
247 | p[1] = DESC_OWNER | DESC_FIRST | DESC_LAST; | |
248 | p[0] = 0x00100000; | |
249 | FLUSH_DCACHE (&p[0], &p[1]); | |
250 | /* Next descriptor */ | |
251 | rx_desc_index = (rx_desc_index + 1) % RX_DESC; | |
252 | done = 0; | |
253 | } | |
254 | } while (len == 0); /* galileo bug.. len might be zero */ | |
255 | ||
256 | return ch; | |
fe8c2806 WD |
257 | } |
258 | ||
259 | int | |
260 | mpsc_test_char(void) | |
261 | { | |
d0ff51ba | 262 | volatile unsigned int *p = &rx_desc_base[rx_desc_index*8]; |
fe8c2806 WD |
263 | |
264 | INVALIDATE_DCACHE(&p[1], &p[2]); | |
265 | ||
266 | if (p[1] & DESC_OWNER) return 0; | |
267 | else return 1; | |
268 | } | |
269 | ||
270 | int | |
271 | mpsc_init(int baud) | |
272 | { | |
fe8c2806 WD |
273 | memset(MIRROR_HACK, 0, sizeof(struct _tag_mirror_hack)); |
274 | MIRROR_HACK->GALMPSC_ROUTING_REGISTER_M=0x3fffffff; | |
275 | ||
276 | /* BRG CONFIG */ | |
277 | galbrg_set_baudrate(CHANNEL, baud); | |
12f34241 | 278 | #if defined(CONFIG_ZUMA_V2) || defined(CONFIG_P3G4) |
fe8c2806 WD |
279 | galbrg_set_clksrc(CHANNEL,0x8); /* connect TCLK -> BRG */ |
280 | #else | |
281 | galbrg_set_clksrc(CHANNEL,0); | |
282 | #endif | |
283 | galbrg_set_CUV(CHANNEL, 0); | |
284 | galbrg_enable(CHANNEL); | |
285 | ||
286 | /* Set up clock routing */ | |
287 | galmpsc_connect(CHANNEL, GALMPSC_CONNECT); | |
288 | galmpsc_route_serial(CHANNEL, GALMPSC_CONNECT); | |
289 | galmpsc_route_rx_clock(CHANNEL, CHANNEL); | |
290 | galmpsc_route_tx_clock(CHANNEL, CHANNEL); | |
291 | ||
292 | /* reset MPSC state */ | |
293 | galmpsc_shutdown(CHANNEL); | |
294 | ||
295 | /* SDMA CONFIG */ | |
296 | galsdma_set_burstsize(CHANNEL, L1_CACHE_BYTES/8); /* in 64 bit words (8 bytes) */ | |
297 | galsdma_set_txle(CHANNEL); | |
298 | galsdma_set_rxle(CHANNEL); | |
299 | galsdma_set_RC(CHANNEL, 0xf); | |
300 | galsdma_set_SFM(CHANNEL); | |
301 | galsdma_set_RFT(CHANNEL); | |
302 | ||
303 | /* MPSC CONFIG */ | |
304 | galmpsc_write_config_regs(CHANNEL, GALMPSC_UART); | |
305 | galmpsc_config_channel_regs(CHANNEL); | |
306 | galmpsc_set_char_length(CHANNEL, GALMPSC_CHAR_LENGTH_8); /* 8 */ | |
307 | galmpsc_set_parity(CHANNEL, GALMPSC_PARITY_NONE); /* N */ | |
308 | galmpsc_set_stop_bit_length(CHANNEL, GALMPSC_STOP_BITS_1); /* 1 */ | |
309 | ||
310 | /* COMM_MPSC CONFIG */ | |
311 | #ifdef SOFTWARE_CACHE_MANAGEMENT | |
53677ef1 | 312 | galmpsc_set_snoop(CHANNEL, 0); /* disable snoop */ |
fe8c2806 | 313 | #else |
53677ef1 | 314 | galmpsc_set_snoop(CHANNEL, 1); /* enable snoop */ |
fe8c2806 WD |
315 | #endif |
316 | ||
317 | return 0; | |
318 | } | |
319 | ||
320 | void | |
321 | mpsc_init2(void) | |
322 | { | |
323 | int i; | |
324 | ||
325 | mpsc_putchar = mpsc_putchar_sdma; | |
326 | ||
327 | /* RX descriptors */ | |
328 | rx_desc_base = (unsigned int *)malloc(((RX_DESC+1)*8) * | |
329 | sizeof(unsigned int)); | |
330 | ||
331 | /* align descriptors */ | |
332 | rx_desc_base = (unsigned int *) | |
333 | (((unsigned int)rx_desc_base+32) & 0xFFFFFFF0); | |
334 | ||
335 | rx_desc_index = 0; | |
336 | ||
337 | memset((void *)rx_desc_base, 0, (RX_DESC*8)*sizeof(unsigned int)); | |
338 | ||
339 | for (i = 0; i < RX_DESC; i++) { | |
340 | rx_desc_base[i*8 + 3] = (unsigned int)&rx_desc_base[i*8 + 4]; /* Buffer */ | |
341 | rx_desc_base[i*8 + 2] = (unsigned int)&rx_desc_base[(i+1)*8]; /* Next descriptor */ | |
342 | rx_desc_base[i*8 + 1] = DESC_OWNER | DESC_FIRST | DESC_LAST; /* Command & control */ | |
343 | rx_desc_base[i*8] = 0x00100000; | |
344 | } | |
345 | rx_desc_base[(i-1)*8 + 2] = (unsigned int)&rx_desc_base[0]; | |
346 | ||
347 | FLUSH_DCACHE(&rx_desc_base[0], &rx_desc_base[RX_DESC*8]); | |
348 | GT_REG_WRITE(GALSDMA_0_CUR_RX_PTR+(CHANNEL*GALSDMA_REG_DIFF), | |
349 | (unsigned int)&rx_desc_base[0]); | |
350 | ||
351 | /* TX descriptors */ | |
352 | tx_desc_base = (unsigned int *)malloc(((TX_DESC+1)*8) * | |
353 | sizeof(unsigned int)); | |
354 | ||
355 | /* align descriptors */ | |
356 | tx_desc_base = (unsigned int *) | |
357 | (((unsigned int)tx_desc_base+32) & 0xFFFFFFF0); | |
358 | ||
359 | tx_desc_index = -1; | |
360 | ||
361 | memset((void *)tx_desc_base, 0, (TX_DESC*8)*sizeof(unsigned int)); | |
362 | ||
363 | for (i = 0; i < TX_DESC; i++) { | |
364 | tx_desc_base[i*8 + 5] = (unsigned int)0x23232323; | |
365 | tx_desc_base[i*8 + 4] = (unsigned int)0x23232323; | |
366 | tx_desc_base[i*8 + 3] = (unsigned int)&tx_desc_base[i*8 + 4]; | |
367 | tx_desc_base[i*8 + 2] = (unsigned int)&tx_desc_base[(i+1)*8]; | |
368 | tx_desc_base[i*8 + 1] = DESC_OWNER | DESC_FIRST | DESC_LAST; | |
369 | ||
370 | /* set sbytecnt and shadow byte cnt to 1 */ | |
371 | tx_desc_base[i*8] = 0x00010001; | |
372 | } | |
373 | tx_desc_base[(i-1)*8 + 2] = (unsigned int)&tx_desc_base[0]; | |
374 | ||
375 | FLUSH_DCACHE(&tx_desc_base[0], &tx_desc_base[TX_DESC*8]); | |
376 | ||
377 | udelay(100); | |
378 | ||
379 | galsdma_enable_rx(); | |
380 | ||
381 | return; | |
382 | } | |
383 | ||
384 | int | |
385 | galbrg_set_baudrate(int channel, int rate) | |
386 | { | |
fe8c2806 WD |
387 | int clock; |
388 | ||
389 | galbrg_disable(channel); | |
390 | ||
12f34241 | 391 | #if defined(CONFIG_ZUMA_V2) || defined(CONFIG_P3G4) |
fe8c2806 | 392 | /* from tclk */ |
6d0f6bcf | 393 | clock = (CONFIG_SYS_BUS_HZ/(16*rate)) - 1; |
fe8c2806 WD |
394 | #else |
395 | clock = (3686400/(16*rate)) - 1; | |
396 | #endif | |
397 | ||
398 | galbrg_set_CDV(channel, clock); | |
399 | ||
400 | galbrg_enable(channel); | |
401 | ||
402 | MIRROR_HACK->baudrate = rate; | |
403 | ||
404 | return 0; | |
405 | } | |
406 | ||
407 | /* ------------------------------------------------------------------ */ | |
408 | ||
409 | /* Below are all the private functions that no one else needs */ | |
410 | ||
411 | static int | |
412 | galbrg_set_CDV(int channel, int value) | |
413 | { | |
fe8c2806 WD |
414 | unsigned int temp; |
415 | ||
416 | temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); | |
417 | temp &= 0xFFFF0000; | |
418 | temp |= (value & 0x0000FFFF); | |
419 | GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG,channel,GALBRG_REG_GAP, temp); | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | static int | |
425 | galbrg_enable(int channel) | |
426 | { | |
fe8c2806 WD |
427 | unsigned int temp; |
428 | ||
429 | temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); | |
430 | temp |= 0x00010000; | |
431 | GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP,temp); | |
432 | ||
433 | return 0; | |
434 | } | |
435 | ||
436 | static int | |
437 | galbrg_disable(int channel) | |
438 | { | |
fe8c2806 WD |
439 | unsigned int temp; |
440 | ||
441 | temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); | |
442 | temp &= 0xFFFEFFFF; | |
443 | GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP,temp); | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int | |
449 | galbrg_set_clksrc(int channel, int value) | |
450 | { | |
fe8c2806 WD |
451 | unsigned int temp; |
452 | ||
453 | temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG,channel, GALBRG_REG_GAP); | |
454 | temp &= 0xFF83FFFF; | |
455 | temp |= (value << 18); | |
456 | GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG,channel, GALBRG_REG_GAP,temp); | |
457 | ||
458 | return 0; | |
459 | } | |
460 | ||
461 | static int | |
462 | galbrg_set_CUV(int channel, int value) | |
463 | { | |
464 | GT_REG_WRITE(GALBRG_0_BTREG + (channel * GALBRG_REG_GAP), value); | |
465 | ||
466 | return 0; | |
467 | } | |
468 | ||
469 | #if 0 | |
470 | static int | |
471 | galbrg_reset(int channel) | |
472 | { | |
473 | unsigned int temp; | |
474 | ||
475 | temp = GTREGREAD(GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); | |
476 | temp |= 0x20000; | |
477 | GT_REG_WRITE(GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); | |
478 | ||
479 | return 0; | |
480 | } | |
481 | #endif | |
482 | ||
483 | static int | |
484 | galsdma_set_RFT(int channel) | |
485 | { | |
486 | unsigned int temp; | |
487 | ||
8bde7f77 | 488 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); |
fe8c2806 WD |
489 | temp |= 0x00000001; |
490 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); | |
491 | ||
492 | return 0; | |
493 | } | |
494 | ||
495 | static int | |
496 | galsdma_set_SFM(int channel) | |
497 | { | |
498 | unsigned int temp; | |
499 | ||
8bde7f77 | 500 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); |
fe8c2806 WD |
501 | temp |= 0x00000002; |
502 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); | |
503 | ||
504 | return 0; | |
505 | } | |
506 | ||
507 | static int | |
508 | galsdma_set_rxle(int channel) | |
509 | { | |
510 | unsigned int temp; | |
511 | ||
8bde7f77 | 512 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); |
fe8c2806 WD |
513 | temp |= 0x00000040; |
514 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); | |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
519 | static int | |
520 | galsdma_set_txle(int channel) | |
521 | { | |
522 | unsigned int temp; | |
523 | ||
8bde7f77 | 524 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); |
fe8c2806 WD |
525 | temp |= 0x00000080; |
526 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); | |
527 | ||
528 | return 0; | |
529 | } | |
530 | ||
531 | static int | |
532 | galsdma_set_RC(int channel, unsigned int value) | |
533 | { | |
534 | unsigned int temp; | |
535 | ||
536 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); | |
537 | temp &= ~0x0000003c; | |
538 | temp |= (value << 2); | |
539 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
544 | static int | |
545 | galsdma_set_burstsize(int channel, unsigned int value) | |
546 | { | |
547 | unsigned int temp; | |
548 | ||
549 | temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); | |
550 | temp &= 0xFFFFCFFF; | |
551 | switch (value) { | |
552 | case 8: | |
553 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), | |
554 | (temp | (0x3 << 12))); | |
555 | break; | |
556 | ||
557 | case 4: | |
558 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), | |
559 | (temp | (0x2 << 12))); | |
560 | break; | |
561 | ||
562 | case 2: | |
563 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), | |
564 | (temp | (0x1 << 12))); | |
565 | break; | |
566 | ||
567 | case 1: | |
568 | GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), | |
569 | (temp | (0x0 << 12))); | |
570 | break; | |
571 | ||
572 | default: | |
573 | return -1; | |
574 | break; | |
575 | } | |
576 | ||
577 | return 0; | |
578 | } | |
579 | ||
580 | static int | |
581 | galmpsc_connect(int channel, int connect) | |
582 | { | |
fe8c2806 WD |
583 | unsigned int temp; |
584 | ||
585 | temp = GTREGREAD_MIRROR_G(GALMPSC_ROUTING_REGISTER); | |
586 | ||
587 | if ((channel == 0) && connect) | |
588 | temp &= ~0x00000007; | |
589 | else if ((channel == 1) && connect) | |
590 | temp &= ~(0x00000007 << 6); | |
591 | else if ((channel == 0) && !connect) | |
592 | temp |= 0x00000007; | |
593 | else | |
594 | temp |= (0x00000007 << 6); | |
595 | ||
596 | /* Just in case... */ | |
597 | temp &= 0x3fffffff; | |
598 | ||
599 | GT_REG_WRITE_MIRROR_G(GALMPSC_ROUTING_REGISTER, temp); | |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
604 | static int | |
605 | galmpsc_route_serial(int channel, int connect) | |
606 | { | |
607 | unsigned int temp; | |
608 | ||
609 | temp = GTREGREAD(GALMPSC_SERIAL_MULTIPLEX); | |
610 | ||
611 | if ((channel == 0) && connect) | |
612 | temp |= 0x00000100; | |
613 | else if ((channel == 1) && connect) | |
614 | temp |= 0x00001000; | |
615 | else if ((channel == 0) && !connect) | |
616 | temp &= ~0x00000100; | |
617 | else | |
618 | temp &= ~0x00001000; | |
619 | ||
620 | GT_REG_WRITE(GALMPSC_SERIAL_MULTIPLEX,temp); | |
621 | ||
622 | return 0; | |
623 | } | |
624 | ||
625 | static int | |
626 | galmpsc_route_rx_clock(int channel, int brg) | |
627 | { | |
fe8c2806 WD |
628 | unsigned int temp; |
629 | ||
630 | temp = GTREGREAD_MIRROR_G(GALMPSC_RxC_ROUTE); | |
631 | ||
632 | if (channel == 0) | |
633 | temp |= brg; | |
634 | else | |
635 | temp |= (brg << 8); | |
636 | ||
637 | GT_REG_WRITE_MIRROR_G(GALMPSC_RxC_ROUTE,temp); | |
638 | ||
639 | return 0; | |
640 | } | |
641 | ||
642 | static int | |
643 | galmpsc_route_tx_clock(int channel, int brg) | |
644 | { | |
fe8c2806 WD |
645 | unsigned int temp; |
646 | ||
647 | temp = GTREGREAD_MIRROR_G(GALMPSC_TxC_ROUTE); | |
648 | ||
649 | if (channel == 0) | |
650 | temp |= brg; | |
651 | else | |
652 | temp |= (brg << 8); | |
653 | ||
654 | GT_REG_WRITE_MIRROR_G(GALMPSC_TxC_ROUTE,temp); | |
655 | ||
656 | return 0; | |
657 | } | |
658 | ||
659 | static int | |
660 | galmpsc_write_config_regs(int mpsc, int mode) | |
661 | { | |
662 | if (mode == GALMPSC_UART) { | |
663 | /* Main config reg Low (Null modem, Enable Tx/Rx, UART mode) */ | |
664 | GT_REG_WRITE(GALMPSC_MCONF_LOW + (mpsc*GALMPSC_REG_GAP), | |
665 | 0x000004c4); | |
666 | ||
667 | /* Main config reg High (32x Rx/Tx clock mode, width=8bits */ | |
668 | GT_REG_WRITE(GALMPSC_MCONF_HIGH +(mpsc*GALMPSC_REG_GAP), | |
669 | 0x024003f8); | |
670 | /* 22 2222 1111 */ | |
671 | /* 54 3210 9876 */ | |
672 | /* 0000 0010 0000 0000 */ | |
673 | /* 1 */ | |
674 | /* 098 7654 3210 */ | |
675 | /* 0000 0011 1111 1000 */ | |
676 | } else | |
677 | return -1; | |
678 | ||
679 | return 0; | |
680 | } | |
681 | ||
682 | static int | |
683 | galmpsc_config_channel_regs(int mpsc) | |
684 | { | |
fe8c2806 WD |
685 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, 0); |
686 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, 0); | |
687 | GT_REG_WRITE(GALMPSC_CHANNELREG_3+(mpsc*GALMPSC_REG_GAP), 1); | |
688 | GT_REG_WRITE(GALMPSC_CHANNELREG_4+(mpsc*GALMPSC_REG_GAP), 0); | |
689 | GT_REG_WRITE(GALMPSC_CHANNELREG_5+(mpsc*GALMPSC_REG_GAP), 0); | |
690 | GT_REG_WRITE(GALMPSC_CHANNELREG_6+(mpsc*GALMPSC_REG_GAP), 0); | |
691 | GT_REG_WRITE(GALMPSC_CHANNELREG_7+(mpsc*GALMPSC_REG_GAP), 0); | |
692 | GT_REG_WRITE(GALMPSC_CHANNELREG_8+(mpsc*GALMPSC_REG_GAP), 0); | |
693 | GT_REG_WRITE(GALMPSC_CHANNELREG_9+(mpsc*GALMPSC_REG_GAP), 0); | |
694 | GT_REG_WRITE(GALMPSC_CHANNELREG_10+(mpsc*GALMPSC_REG_GAP), 0); | |
695 | ||
696 | galmpsc_set_brkcnt(mpsc, 0x3); | |
697 | galmpsc_set_tcschar(mpsc, 0xab); | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
702 | static int | |
703 | galmpsc_set_brkcnt(int mpsc, int value) | |
704 | { | |
fe8c2806 WD |
705 | unsigned int temp; |
706 | ||
707 | temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP); | |
708 | temp &= 0x0000FFFF; | |
709 | temp |= (value << 16); | |
710 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, temp); | |
711 | ||
712 | return 0; | |
713 | } | |
714 | ||
715 | static int | |
716 | galmpsc_set_tcschar(int mpsc, int value) | |
717 | { | |
fe8c2806 WD |
718 | unsigned int temp; |
719 | ||
720 | temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP); | |
721 | temp &= 0xFFFF0000; | |
722 | temp |= value; | |
723 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, temp); | |
724 | ||
725 | return 0; | |
726 | } | |
727 | ||
728 | static int | |
729 | galmpsc_set_char_length(int mpsc, int value) | |
730 | { | |
fe8c2806 WD |
731 | unsigned int temp; |
732 | ||
733 | temp = GTREGREAD_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP); | |
734 | temp &= 0xFFFFCFFF; | |
735 | temp |= (value << 12); | |
736 | GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP, temp); | |
737 | ||
738 | return 0; | |
739 | } | |
740 | ||
741 | static int | |
742 | galmpsc_set_stop_bit_length(int mpsc, int value) | |
743 | { | |
fe8c2806 WD |
744 | unsigned int temp; |
745 | ||
746 | temp = GTREGREAD_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP); | |
747 | temp |= (value << 14); | |
748 | GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP,temp); | |
749 | ||
750 | return 0; | |
751 | } | |
752 | ||
753 | static int | |
754 | galmpsc_set_parity(int mpsc, int value) | |
755 | { | |
fe8c2806 WD |
756 | unsigned int temp; |
757 | ||
758 | temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); | |
759 | if (value != -1) { | |
760 | temp &= 0xFFF3FFF3; | |
761 | temp |= ((value << 18) | (value << 2)); | |
762 | temp |= ((value << 17) | (value << 1)); | |
763 | } else { | |
764 | temp &= 0xFFF1FFF1; | |
765 | } | |
766 | ||
767 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, temp); | |
768 | ||
769 | return 0; | |
770 | } | |
771 | ||
772 | static int | |
773 | galmpsc_enter_hunt(int mpsc) | |
774 | { | |
fe8c2806 WD |
775 | int temp; |
776 | ||
777 | temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); | |
778 | temp |= 0x80000000; | |
779 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, temp); | |
780 | ||
781 | /* Should Poll on Enter Hunt bit, but the register is write-only */ | |
782 | /* errata suggests pausing 100 system cycles */ | |
783 | udelay(100); | |
784 | ||
785 | return 0; | |
786 | } | |
787 | ||
788 | ||
789 | static int | |
790 | galmpsc_shutdown(int mpsc) | |
791 | { | |
12f34241 | 792 | #if 0 |
fe8c2806 WD |
793 | unsigned int temp; |
794 | ||
795 | /* cause RX abort (clears RX) */ | |
796 | temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); | |
797 | temp |= MPSC_RX_ABORT | MPSC_TX_ABORT; | |
798 | temp &= ~MPSC_ENTER_HUNT; | |
799 | GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP,temp); | |
12f34241 | 800 | #endif |
fe8c2806 | 801 | |
12f34241 WD |
802 | GT_REG_WRITE(GALSDMA_0_COM_REG + CHANNEL * GALSDMA_REG_DIFF, 0); |
803 | GT_REG_WRITE(GALSDMA_0_COM_REG + CHANNEL * GALSDMA_REG_DIFF, | |
804 | SDMA_TX_ABORT | SDMA_RX_ABORT); | |
fe8c2806 WD |
805 | |
806 | /* shut down the MPSC */ | |
807 | GT_REG_WRITE(GALMPSC_MCONF_LOW, 0); | |
808 | GT_REG_WRITE(GALMPSC_MCONF_HIGH, 0); | |
809 | GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG, mpsc, GALMPSC_REG_GAP,0); | |
810 | ||
811 | udelay(100); | |
812 | ||
813 | /* shut down the sdma engines. */ | |
814 | /* reset config to default */ | |
12f34241 WD |
815 | GT_REG_WRITE(GALSDMA_0_CONF_REG + CHANNEL * GALSDMA_REG_DIFF, |
816 | 0x000000fc); | |
fe8c2806 WD |
817 | |
818 | udelay(100); | |
819 | ||
820 | /* clear the SDMA current and first TX and RX pointers */ | |
12f34241 WD |
821 | GT_REG_WRITE(GALSDMA_0_CUR_RX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); |
822 | GT_REG_WRITE(GALSDMA_0_CUR_TX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); | |
823 | GT_REG_WRITE(GALSDMA_0_FIR_TX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); | |
fe8c2806 WD |
824 | |
825 | udelay(100); | |
826 | ||
827 | return 0; | |
828 | } | |
829 | ||
830 | static void | |
831 | galsdma_enable_rx(void) | |
832 | { | |
833 | int temp; | |
834 | ||
835 | /* Enable RX processing */ | |
836 | temp = GTREGREAD(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF)); | |
837 | temp |= RX_ENABLE; | |
838 | GT_REG_WRITE(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF), temp); | |
839 | ||
840 | galmpsc_enter_hunt(CHANNEL); | |
841 | } | |
842 | ||
843 | static int | |
844 | galmpsc_set_snoop(int mpsc, int value) | |
845 | { | |
846 | int reg = mpsc ? MPSC_1_ADDRESS_CONTROL_LOW : MPSC_0_ADDRESS_CONTROL_LOW; | |
847 | int temp=GTREGREAD(reg); | |
848 | if(value) | |
849 | temp |= (1<< 6) | (1<<14) | (1<<22) | (1<<30); | |
850 | else | |
851 | temp &= ~((1<< 6) | (1<<14) | (1<<22) | (1<<30)); | |
852 | GT_REG_WRITE(reg, temp); | |
853 | return 0; | |
854 | } |