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