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