]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/serial_io.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / osfmk / ppc / serial_io.c
CommitLineData
1c79356b 1/*
3a60a9f5 2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * @APPLE_FREE_COPYRIGHT@
33 */
34/*
35 * Mach Operating System
36 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
37 * All Rights Reserved.
38 *
39 * Permission to use, copy, modify and distribute this software and its
40 * documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
47 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 *
49 * Carnegie Mellon requests users of this software to return to
50 *
51 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
52 * School of Computer Science
53 * Carnegie Mellon University
54 * Pittsburgh PA 15213-3890
55 *
56 * any improvements or extensions that they make and grant Carnegie Mellon
57 * the rights to redistribute these changes.
58 */
59/*
60 */
61/*
62 * File: scc_8530_hdw.c
63 * Author: Alessandro Forin, Carnegie Mellon University
64 * Date: 6/91
65 *
66 * Hardware-level operations for the SCC Serial Line Driver
67 */
68
69#define NSCC 1 /* Number of serial chips, two ports per chip. */
70#if NSCC > 0
71
72#include <mach_kdb.h>
73#include <platforms.h>
74#include <kern/spl.h>
75#include <mach/std_types.h>
76#include <types.h>
77#include <sys/syslog.h>
91447636 78#include <kern/thread.h>
1c79356b
A
79#include <ppc/misc_protos.h>
80#include <ppc/proc_reg.h>
81#include <ppc/exception.h>
82#include <ppc/Firmware.h>
55e303ae
A
83#include <ppc/serial_io.h>
84#include <ppc/scc_8530.h>
1c79356b
A
85
86#if MACH_KDB
87#include <machine/db_machdep.h>
88#endif /* MACH_KDB */
89
90#define kdebug_state() (1)
91#define delay(x) { volatile int _d_; for (_d_ = 0; _d_ < (10000*x); _d_++) ; }
92
93#define NSCC_LINE 2 /* 2 ttys per chip */
94
95#define SCC_DMA_TRANSFERS 0
96
97struct scc_tty scc_tty[NSCC_LINE];
98
99#define scc_tty_for(chan) (&scc_tty[chan])
100/* #define scc_unit(dev_no) (dev_no) */
101
102#define scc_dev_no(chan) ((chan)^0x01)
103#define scc_chan(dev_no) ((dev_no)^0x01)
104
d7e50217
A
105extern unsigned int disableSerialOuput;
106
1c79356b 107int serial_initted = 0;
3a60a9f5 108unsigned int scc_parm_done = 0;
1c79356b
A
109
110static struct scc_byte {
111 unsigned char reg;
112 unsigned char val;
113} scc_init_hw[] = {
114
115 9, 0x80,
116 4, 0x44,
117 3, 0xC0,
118 5, 0xE2,
119 2, 0x00,
120 10, 0x00,
121 11, 0x50,
122 12, 0x0A,
123 13, 0x00,
124 3, 0xC1,
125 5, 0xEA,
126 14, 0x01,
127 15, 0x00,
128 0, 0x10,
129 0, 0x10,
130#if 0
131 1, 0x12, /* int or Rx, Tx int enable */
132#else
133 1, 0x10, /* int or Rx, no Tx int enable */
134#endif
135 9, 0x0A
136};
137
138static int scc_init_hw_count = sizeof(scc_init_hw)/sizeof(scc_init_hw[0]);
139
140enum scc_error {SCC_ERR_NONE, SCC_ERR_PARITY, SCC_ERR_BREAK, SCC_ERR_OVERRUN};
141
142
143/*
144 * BRG formula is:
145 * ClockFrequency (115200 for Power Mac)
146 * BRGconstant = --------------------------- - 2
147 * BaudRate
148 */
de355530 149
1c79356b
A
150#define SERIAL_CLOCK_FREQUENCY (115200*2) /* Power Mac value */
151#define convert_baud_rate(rate) ((((SERIAL_CLOCK_FREQUENCY) + (rate)) / (2 * (rate))) - 2)
152
0b4e3aa0 153#define DEFAULT_SPEED 57600
55e303ae 154#define DEFAULT_PORT0_SPEED 1200
1c79356b
A
155#define DEFAULT_FLAGS (TF_LITOUT|TF_ECHO)
156
157int scc_param(struct scc_tty *tp);
158
de355530 159
1c79356b
A
160struct scc_softc scc_softc[NSCC];
161caddr_t scc_std[NSCC] = { (caddr_t) 0};
162
de355530
A
163
164#define SCC_RR1_ERRS (SCC_RR1_FRAME_ERR|SCC_RR1_RX_OVERRUN|SCC_RR1_PARITY_ERR)
165#define SCC_RR3_ALL (SCC_RR3_RX_IP_A|SCC_RR3_TX_IP_A|SCC_RR3_EXT_IP_A|\
166 SCC_RR3_RX_IP_B|SCC_RR3_TX_IP_B|SCC_RR3_EXT_IP_B)
167
168#define DEBUG_SCC
169#undef DEBUG_SCC
170
171#ifdef DEBUG_SCC
172static int total_chars, total_ints, total_overruns, total_errors, num_ints, max_chars;
173static int chars_received[8];
174static int __SCC_STATS = 0;
175static int max_in_q = 0;
176static int max_out_q = 0;
177#endif
178
179DECL_FUNNEL(, scc_funnel) /* funnel to serialize the SCC driver */
180boolean_t scc_funnel_initted = FALSE;
181#define SCC_FUNNEL scc_funnel
182#define SCC_FUNNEL_INITTED scc_funnel_initted
183
184
185/*
186 * Adapt/Probe/Attach functions
187 */
188boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */
3a60a9f5 189decl_simple_lock_data(,scc_stomp)
1c79356b
A
190
191/* This is called VERY early on in the init and therefore has to have
192 * hardcoded addresses of the serial hardware control registers. The
193 * serial line may be needed for console and debugging output before
194 * anything else takes place
195 */
196
197void
91447636 198initialize_serial( caddr_t scc_phys_base, int32_t serial_baud )
1c79356b
A
199{
200 int i, chan, bits;
201 scc_regmap_t regs;
de355530 202 DECL_FUNNEL_VARS
1c79356b
A
203
204 assert( scc_phys_base );
205
de355530
A
206 if (!SCC_FUNNEL_INITTED) {
207 FUNNEL_INIT(&SCC_FUNNEL, master_processor);
208 SCC_FUNNEL_INITTED = TRUE;
209 }
210 FUNNEL_ENTER(&SCC_FUNNEL);
211
212 if (serial_initted) {
213 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b 214 return;
de355530 215 }
1c79356b 216
3a60a9f5 217 simple_lock_init(&scc_stomp, FALSE);
1c79356b 218
91447636
A
219 if (serial_baud == -1) serial_baud = DEFAULT_SPEED;
220
1c79356b
A
221 scc_softc[0].full_modem = TRUE;
222
223 scc_std[0] = scc_phys_base;
224
225 regs = scc_softc[0].regs = (scc_regmap_t)scc_std[0];
226
227 for (chan = 0; chan < NSCC_LINE; chan++) {
228 if (chan == 1)
229 scc_init_hw[0].val = 0x80;
230
231 for (i = 0; i < scc_init_hw_count; i++) {
232 scc_write_reg(regs, chan,
233 scc_init_hw[i].reg, scc_init_hw[i].val);
234 }
235 }
236
237 /* Call probe so we are ready very early for remote gdb and for serial
238 console output if appropriate. */
91447636 239 if (scc_probe(serial_baud)) {
1c79356b
A
240 for (i = 0; i < NSCC_LINE; i++) {
241 scc_softc[0].softr[i].wr5 = SCC_WR5_DTR | SCC_WR5_RTS;
242 scc_param(scc_tty_for(i));
243 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
244 scc_write_reg(regs, i, 9, SCC_WR9_NV);
245
246 scc_read_reg_zero(regs, 0, bits);/* Clear the status */
247 }
3a60a9f5 248 scc_parm_done = 1;
1c79356b
A
249 }
250
251 serial_initted = TRUE;
de355530
A
252
253 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
254 return;
255}
256
257int
91447636 258scc_probe(int32_t serial_baud)
1c79356b
A
259{
260 scc_softc_t scc;
261 register int val, i;
262 register scc_regmap_t regs;
263 spl_t s;
de355530
A
264 DECL_FUNNEL_VARS
265
266 if (!SCC_FUNNEL_INITTED) {
267 FUNNEL_INIT(&SCC_FUNNEL, master_processor);
268 SCC_FUNNEL_INITTED = TRUE;
269 }
270 FUNNEL_ENTER(&SCC_FUNNEL);
271
272 /* Readjust the I/O address to handling
273 * new memory mappings.
274 */
275
1c79356b
A
276 regs = (scc_regmap_t)scc_std[0];
277
de355530
A
278 if (regs == (scc_regmap_t) 0) {
279 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b 280 return 0;
de355530 281 }
1c79356b
A
282
283 scc = &scc_softc[0];
284 scc->regs = regs;
285
286 s = splhigh();
287
288 for (i = 0; i < NSCC_LINE; i++) {
289 register struct scc_tty *tp;
290 tp = scc_tty_for(i);
291 tp->t_addr = (char*)(0x80000000L + (i&1));
292 /* Set default values. These will be overridden on
293 open but are needed if the port will be used
294 independently of the Mach interfaces, e.g., for
295 gdb or for a serial console. */
55e303ae
A
296 if (i == 0) {
297 tp->t_ispeed = DEFAULT_PORT0_SPEED;
298 tp->t_ospeed = DEFAULT_PORT0_SPEED;
299 } else {
91447636
A
300 tp->t_ispeed = serial_baud;
301 tp->t_ospeed = serial_baud;
55e303ae 302 }
1c79356b
A
303 tp->t_flags = DEFAULT_FLAGS;
304 scc->softr[i].speed = -1;
305
306 /* do min buffering */
307 tp->t_state |= TS_MIN;
308
309 tp->t_dev = scc_dev_no(i);
310 }
311
312 splx(s);
de355530
A
313
314 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
315 return 1;
316}
317
318/*
319 * Get a char from a specific SCC line
320 * [this is only used for console&screen purposes]
321 * must be splhigh since it may be called from another routine under spl
322 */
323
324int
325scc_getc(int unit, int line, boolean_t wait, boolean_t raw)
326{
327 register scc_regmap_t regs;
328 unsigned char c, value;
329 int rcvalue, from_line;
3a60a9f5 330 uint32_t fcrmunge;
1c79356b 331 spl_t s = splhigh();
de355530 332 DECL_FUNNEL_VARS
1c79356b 333
de355530
A
334 FUNNEL_ENTER(&SCC_FUNNEL);
335
3a60a9f5
A
336
337 simple_lock(&scc_stomp);
1c79356b
A
338 regs = scc_softc[0].regs;
339
340 /*
341 * wait till something available
de355530 342 *
1c79356b
A
343 */
344again:
345 rcvalue = 0;
346 while (1) {
347 scc_read_reg_zero(regs, line, value);
348
349 if (value & SCC_RR0_RX_AVAIL)
350 break;
351
352 if (!wait) {
3a60a9f5 353 simple_unlock(&scc_stomp);
1c79356b 354 splx(s);
de355530 355 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
356 return -1;
357 }
358 }
359
360 /*
361 * if nothing found return -1
362 */
363
364 scc_read_reg(regs, line, SCC_RR1, value);
365 scc_read_data(regs, line, c);
366
367#if MACH_KDB
368 if (console_is_serial() &&
369 c == ('_' & 0x1f)) {
370 /* Drop into the debugger */
3a60a9f5 371 simple_unlock(&scc_stomp);
1c79356b 372 Debugger("Serial Line Request");
3a60a9f5 373 simple_lock(&scc_stomp);
1c79356b
A
374 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
375 if (wait) {
376 goto again;
377 }
3a60a9f5 378 simple_unlock(&scc_stomp);
1c79356b 379 splx(s);
de355530 380 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
381 return -1;
382 }
383#endif /* MACH_KDB */
384
385 /*
386 * bad chars not ok
387 */
388 if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) {
389 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_ERROR);
390
391 if (wait) {
392 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
393 goto again;
394 }
395 }
de355530 396
1c79356b
A
397 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
398
3a60a9f5 399 simple_unlock(&scc_stomp);
1c79356b 400 splx(s);
de355530
A
401
402 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
403 return c;
404}
405
89b3af67
A
406
407/*
408 * This front-ends scc_getc to make some intel changes easier
409 */
410
411int _serial_getc(int unit, int line, boolean_t wait, boolean_t raw) {
412
413 return(scc_getc(unit, line, wait, raw));
414
415}
416
1c79356b
A
417/*
418 * Put a char on a specific SCC line
419 * use splhigh since we might be doing a printf in high spl'd code
420 */
421
422int
423scc_putc(int unit, int line, int c)
424{
425 scc_regmap_t regs;
d7e50217 426 spl_t s;
1c79356b 427 unsigned char value;
3a60a9f5 428 uint32_t fcrmunge;
de355530 429 DECL_FUNNEL_VARS
1c79356b 430
3a60a9f5 431
d7e50217
A
432 if (disableSerialOuput)
433 return 0;
434
435 s = splhigh();
de355530 436 FUNNEL_ENTER(&SCC_FUNNEL);
3a60a9f5 437 simple_lock(&scc_stomp);
1c79356b
A
438
439 regs = scc_softc[0].regs;
440
441 do {
442 scc_read_reg(regs, line, SCC_RR0, value);
443 if (value & SCC_RR0_TX_EMPTY)
444 break;
445 delay(1);
446 } while (1);
447
448 scc_write_data(regs, line, c);
449/* wait for it to swallow the char ? */
450
451 do {
452 scc_read_reg(regs, line, SCC_RR0, value);
453 if (value & SCC_RR0_TX_EMPTY)
454 break;
455 } while (1);
456 scc_write_reg(regs, line, SCC_RR0, SCC_RESET_HIGHEST_IUS);
3a60a9f5 457 simple_unlock(&scc_stomp);
1c79356b
A
458
459 splx(s);
de355530
A
460
461 FUNNEL_EXIT(&SCC_FUNNEL);
1c79356b
A
462 return 0;
463}
464
465
466void
467powermac_scc_set_datum(scc_regmap_t regs, unsigned int offset, unsigned char value)
468{
469 volatile unsigned char *address = (unsigned char *) regs + offset;
470
de355530
A
471 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
472
1c79356b
A
473 *address = value;
474 eieio();
de355530
A
475
476 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
477}
478
479unsigned char
480powermac_scc_get_datum(scc_regmap_t regs, unsigned int offset)
481{
482 volatile unsigned char *address = (unsigned char *) regs + offset;
483 unsigned char value;
484
de355530
A
485 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
486
487 value = *address; eieio();
1c79356b 488 return value;
de355530
A
489
490 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
491}
492
493int
494scc_param(struct scc_tty *tp)
495{
496 scc_regmap_t regs;
497 unsigned char value;
498 unsigned short speed_value;
499 int bits, chan;
500 spl_t s;
501 struct scc_softreg *sr;
502 scc_softc_t scc;
503
de355530
A
504 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
505
1c79356b 506 s = splhigh();
3a60a9f5 507 simple_lock(&scc_stomp);
1c79356b
A
508
509 chan = scc_chan(tp->t_dev);
510 scc = &scc_softc[0];
511 regs = scc->regs;
512
513 sr = &scc->softr[chan];
514
515 /* Do a quick check to see if the hardware needs to change */
516 if ((sr->flags & (TF_ODDP|TF_EVENP)) == (tp->t_flags & (TF_ODDP|TF_EVENP))
517 && sr->speed == tp->t_ispeed) {
de355530 518 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
3a60a9f5
A
519 simple_unlock(&scc_stomp);
520 splx(s);
521 return 0;
1c79356b
A
522 }
523
524 if(scc_parm_done) {
525
3a60a9f5
A
526 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE);
527 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
528 scc_write_reg(regs, chan, 1, sr->wr1);
529 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC);
530 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO);
531 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
532 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
533 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
534 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV);
535 scc_read_reg_zero(regs, 0, bits);
536 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
537 scc_write_reg(regs, chan, 1, sr->wr1);
538 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
539 simple_unlock(&scc_stomp);
540 splx(s);
541 return 0;
1c79356b
A
542 }
543
544 sr->flags = tp->t_flags;
545 sr->speed = tp->t_ispeed;
546
547
548 if (tp->t_ispeed == 0) {
549 sr->wr5 &= ~SCC_WR5_DTR;
550 scc_write_reg(regs, chan, 5, sr->wr5);
3a60a9f5 551 simple_unlock(&scc_stomp);
1c79356b 552 splx(s);
de355530
A
553
554 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
1c79356b
A
555 return 0;
556 }
557
558
559#if SCC_DMA_TRANSFERS
560 if (scc->dma_initted & (1<<chan))
561 scc->dma_ops->scc_dma_reset_rx(chan);
562#endif
563
564 value = SCC_WR4_1_STOP;
565
566 /*
567 * For 115K the clocking divide changes to 64.. to 230K will
568 * start at the normal clock divide 16.
569 *
570 * However, both speeds will pull from a different clocking
571 * source
572 */
573
574 if (tp->t_ispeed == 115200)
575 value |= SCC_WR4_CLK_x32;
576 else
577 value |= SCC_WR4_CLK_x16 ;
578
579 /* .. and parity */
580 if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_EVENP)
581 value |= (SCC_WR4_EVEN_PARITY | SCC_WR4_PARITY_ENABLE);
582 else if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP)
583 value |= SCC_WR4_PARITY_ENABLE;
584
585 /* set it now, remember it must be first after reset */
586 sr->wr4 = value;
587
588 /* Program Parity, and Stop bits */
589 scc_write_reg(regs, chan, 4, sr->wr4);
590
591 /* Setup for 8 bits */
592 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS);
593
594 // Set DTR, RTS, and transmitter bits/character.
595 sr->wr5 = SCC_WR5_TX_8_BITS | SCC_WR5_RTS | SCC_WR5_DTR;
596
597 scc_write_reg(regs, chan, 5, sr->wr5);
598
599 scc_write_reg(regs, chan, 14, 0); /* Disable baud rate */
600
601 /* Setup baud rate 57.6Kbps, 115K, 230K should all yeild
602 * a converted baud rate of zero
603 */
604 speed_value = convert_baud_rate(tp->t_ispeed);
605
606 if (speed_value == 0xffff)
607 speed_value = 0;
608
609 scc_set_timing_base(regs, chan, speed_value);
610
611 if (tp->t_ispeed == 115200 || tp->t_ispeed == 230400) {
612 /* Special case here.. change the clock source*/
613 scc_write_reg(regs, chan, 11, 0);
614 /* Baud rate generator is disabled.. */
615 } else {
616 scc_write_reg(regs, chan, 11, SCC_WR11_RCLK_BAUDR|SCC_WR11_XTLK_BAUDR);
617 /* Enable the baud rate generator */
618 scc_write_reg(regs, chan, 14, SCC_WR14_BAUDR_ENABLE);
619 }
620
621
622 scc_write_reg(regs, chan, 3, SCC_WR3_RX_8_BITS|SCC_WR3_RX_ENABLE);
623
624
625 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
626 scc_write_reg(regs, chan, 1, sr->wr1);
627 scc_write_reg(regs, chan, 15, SCC_WR15_ENABLE_ESCC);
628 scc_write_reg(regs, chan, 7, SCC_WR7P_RX_FIFO);
629 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
630
631
632 /* Clear out any pending external or status interrupts */
633 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
634 scc_write_reg(regs, chan, 0, SCC_RESET_EXT_IP);
635 //scc_write_reg(regs, chan, 0, SCC_RESET_ERROR);
636
637 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
638 scc_write_reg(regs, chan, 9, SCC_WR9_MASTER_IE|SCC_WR9_NV);
639
640 scc_read_reg_zero(regs, 0, bits);/* Clear the status */
641
642#if SCC_DMA_TRANSFERS
643 if (scc->dma_initted & (1<<chan)) {
644 scc->dma_ops->scc_dma_start_rx(chan);
645 scc->dma_ops->scc_dma_setup_8530(chan);
646 } else
647#endif
648 {
649 sr->wr1 = SCC_WR1_RXI_FIRST_CHAR | SCC_WR1_EXT_IE;
650 scc_write_reg(regs, chan, 1, sr->wr1);
651 scc_write_reg(regs, chan, 0, SCC_IE_NEXT_CHAR);
652 }
653
654 sr->wr5 |= SCC_WR5_TX_ENABLE;
655 scc_write_reg(regs, chan, 5, sr->wr5);
656
3a60a9f5 657 simple_unlock(&scc_stomp);
1c79356b 658 splx(s);
1c79356b 659
de355530
A
660 assert(FUNNEL_IN_USE(&SCC_FUNNEL));
661 return 0;
d7e50217 662
d7e50217
A
663}
664
55e303ae 665
1c79356b 666#endif /* NSCC > 0 */