2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
26 * @APPLE_FREE_COPYRIGHT@
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
56 * File: scc_8530_hdw.c
57 * Author: Alessandro Forin, Carnegie Mellon University
60 * Hardware-level operations for the SCC Serial Line Driver
63 #define NSCC 1 /* Number of serial chips, two ports per chip. */
67 #include <platforms.h>
69 #include <mach/std_types.h>
71 #include <sys/syslog.h>
72 #include <ppc/misc_protos.h>
73 #include <ppc/proc_reg.h>
74 #include <ppc/exception.h>
75 #include <ppc/Firmware.h>
76 #include <ppc/serial_io.h>
77 #include <ppc/scc_8530.h>
80 #include <machine/db_machdep.h>
83 #define kdebug_state() (1)
84 #define delay(x) { volatile int _d_; for (_d_ = 0; _d_ < (10000*x); _d_++) ; }
86 #define NSCC_LINE 2 /* 2 ttys per chip */
88 #define SCC_DMA_TRANSFERS 0
90 struct scc_tty scc_tty
[NSCC_LINE
];
92 #define scc_tty_for(chan) (&scc_tty[chan])
93 /* #define scc_unit(dev_no) (dev_no) */
95 #define scc_dev_no(chan) ((chan)^0x01)
96 #define scc_chan(dev_no) ((dev_no)^0x01)
98 extern unsigned int disableSerialOuput
;
100 int serial_initted
= 0;
101 unsigned int scc_parm_done
= 0; /* (TEST/DEBUG) */
103 extern unsigned int serialmode
;
105 static struct scc_byte
{
126 1, 0x12, /* int or Rx, Tx int enable */
128 1, 0x10, /* int or Rx, no Tx int enable */
133 static int scc_init_hw_count
= sizeof(scc_init_hw
)/sizeof(scc_init_hw
[0]);
135 enum scc_error
{SCC_ERR_NONE
, SCC_ERR_PARITY
, SCC_ERR_BREAK
, SCC_ERR_OVERRUN
};
140 * ClockFrequency (115200 for Power Mac)
141 * BRGconstant = --------------------------- - 2
145 #define SERIAL_CLOCK_FREQUENCY (115200*2) /* Power Mac value */
146 #define convert_baud_rate(rate) ((((SERIAL_CLOCK_FREQUENCY) + (rate)) / (2 * (rate))) - 2)
148 #define DEFAULT_SPEED 57600
149 #define DEFAULT_PORT0_SPEED 1200
150 #define DEFAULT_FLAGS (TF_LITOUT|TF_ECHO)
152 int scc_param(struct scc_tty
*tp
);
155 struct scc_softc scc_softc
[NSCC
];
156 caddr_t scc_std
[NSCC
] = { (caddr_t
) 0};
159 #define SCC_RR1_ERRS (SCC_RR1_FRAME_ERR|SCC_RR1_RX_OVERRUN|SCC_RR1_PARITY_ERR)
160 #define SCC_RR3_ALL (SCC_RR3_RX_IP_A|SCC_RR3_TX_IP_A|SCC_RR3_EXT_IP_A|\
161 SCC_RR3_RX_IP_B|SCC_RR3_TX_IP_B|SCC_RR3_EXT_IP_B)
167 static int total_chars
, total_ints
, total_overruns
, total_errors
, num_ints
, max_chars
;
168 static int chars_received
[8];
169 static int __SCC_STATS
= 0;
170 static int max_in_q
= 0;
171 static int max_out_q
= 0;
174 DECL_FUNNEL(, scc_funnel
) /* funnel to serialize the SCC driver */
175 boolean_t scc_funnel_initted
= FALSE
;
176 #define SCC_FUNNEL scc_funnel
177 #define SCC_FUNNEL_INITTED scc_funnel_initted
181 * Adapt/Probe/Attach functions
183 boolean_t scc_uses_modem_control
= FALSE
;/* patch this with adb */
184 decl_simple_lock_data(,scc_stomp
) /* (TEST/DEBUG) */
186 /* This is called VERY early on in the init and therefore has to have
187 * hardcoded addresses of the serial hardware control registers. The
188 * serial line may be needed for console and debugging output before
189 * anything else takes place
193 initialize_serial( caddr_t scc_phys_base
)
199 assert( scc_phys_base
);
201 if (!SCC_FUNNEL_INITTED
) {
202 FUNNEL_INIT(&SCC_FUNNEL
, master_processor
);
203 SCC_FUNNEL_INITTED
= TRUE
;
205 FUNNEL_ENTER(&SCC_FUNNEL
);
207 if (serial_initted
) {
208 FUNNEL_EXIT(&SCC_FUNNEL
);
212 simple_lock_init(&scc_stomp
, FALSE
); /* (TEST/DEBUG) */
214 scc_softc
[0].full_modem
= TRUE
;
216 scc_std
[0] = scc_phys_base
;
218 regs
= scc_softc
[0].regs
= (scc_regmap_t
)scc_std
[0];
220 for (chan
= 0; chan
< NSCC_LINE
; chan
++) {
222 scc_init_hw
[0].val
= 0x80;
224 for (i
= 0; i
< scc_init_hw_count
; i
++) {
225 scc_write_reg(regs
, chan
,
226 scc_init_hw
[i
].reg
, scc_init_hw
[i
].val
);
230 /* Call probe so we are ready very early for remote gdb and for serial
231 console output if appropriate. */
233 for (i
= 0; i
< NSCC_LINE
; i
++) {
234 scc_softc
[0].softr
[i
].wr5
= SCC_WR5_DTR
| SCC_WR5_RTS
;
235 scc_param(scc_tty_for(i
));
236 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
237 scc_write_reg(regs
, i
, 9, SCC_WR9_NV
);
239 scc_read_reg_zero(regs
, 0, bits
);/* Clear the status */
241 scc_parm_done
= 1; /* (TEST/DEBUG) */
244 serial_initted
= TRUE
;
246 FUNNEL_EXIT(&SCC_FUNNEL
);
255 register scc_regmap_t regs
;
259 if (!SCC_FUNNEL_INITTED
) {
260 FUNNEL_INIT(&SCC_FUNNEL
, master_processor
);
261 SCC_FUNNEL_INITTED
= TRUE
;
263 FUNNEL_ENTER(&SCC_FUNNEL
);
265 /* Readjust the I/O address to handling
266 * new memory mappings.
269 regs
= (scc_regmap_t
)scc_std
[0];
271 if (regs
== (scc_regmap_t
) 0) {
272 FUNNEL_EXIT(&SCC_FUNNEL
);
281 for (i
= 0; i
< NSCC_LINE
; i
++) {
282 register struct scc_tty
*tp
;
284 tp
->t_addr
= (char*)(0x80000000L
+ (i
&1));
285 /* Set default values. These will be overridden on
286 open but are needed if the port will be used
287 independently of the Mach interfaces, e.g., for
288 gdb or for a serial console. */
290 tp
->t_ispeed
= DEFAULT_PORT0_SPEED
;
291 tp
->t_ospeed
= DEFAULT_PORT0_SPEED
;
293 tp
->t_ispeed
= DEFAULT_SPEED
;
294 tp
->t_ospeed
= DEFAULT_SPEED
;
296 tp
->t_flags
= DEFAULT_FLAGS
;
297 scc
->softr
[i
].speed
= -1;
299 /* do min buffering */
300 tp
->t_state
|= TS_MIN
;
302 tp
->t_dev
= scc_dev_no(i
);
307 FUNNEL_EXIT(&SCC_FUNNEL
);
312 * Get a char from a specific SCC line
313 * [this is only used for console&screen purposes]
314 * must be splhigh since it may be called from another routine under spl
318 scc_getc(int unit
, int line
, boolean_t wait
, boolean_t raw
)
320 register scc_regmap_t regs
;
321 unsigned char c
, value
;
322 int rcvalue
, from_line
;
326 FUNNEL_ENTER(&SCC_FUNNEL
);
328 simple_lock(&scc_stomp
); /* (TEST/DEBUG) */
329 regs
= scc_softc
[0].regs
;
332 * wait till something available
338 scc_read_reg_zero(regs
, line
, value
);
340 if (value
& SCC_RR0_RX_AVAIL
)
344 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
346 FUNNEL_EXIT(&SCC_FUNNEL
);
352 * if nothing found return -1
355 scc_read_reg(regs
, line
, SCC_RR1
, value
);
356 scc_read_data(regs
, line
, c
);
359 if (console_is_serial() &&
361 /* Drop into the debugger */
362 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
363 Debugger("Serial Line Request");
364 simple_lock(&scc_stomp
); /* (TEST/DEBUG) */
365 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
369 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
371 FUNNEL_EXIT(&SCC_FUNNEL
);
374 #endif /* MACH_KDB */
379 if (value
&(SCC_RR1_PARITY_ERR
| SCC_RR1_RX_OVERRUN
| SCC_RR1_FRAME_ERR
)) {
380 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_ERROR
);
383 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
388 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
390 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
393 FUNNEL_EXIT(&SCC_FUNNEL
);
398 * Put a char on a specific SCC line
399 * use splhigh since we might be doing a printf in high spl'd code
403 scc_putc(int unit
, int line
, int c
)
410 if (disableSerialOuput
)
414 FUNNEL_ENTER(&SCC_FUNNEL
);
415 simple_lock(&scc_stomp
); /* (TEST/DEBUG) */
417 regs
= scc_softc
[0].regs
;
420 scc_read_reg(regs
, line
, SCC_RR0
, value
);
421 if (value
& SCC_RR0_TX_EMPTY
)
426 scc_write_data(regs
, line
, c
);
427 /* wait for it to swallow the char ? */
430 scc_read_reg(regs
, line
, SCC_RR0
, value
);
431 if (value
& SCC_RR0_TX_EMPTY
)
434 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
435 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
439 FUNNEL_EXIT(&SCC_FUNNEL
);
445 powermac_scc_set_datum(scc_regmap_t regs
, unsigned int offset
, unsigned char value
)
447 volatile unsigned char *address
= (unsigned char *) regs
+ offset
;
449 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
454 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
458 powermac_scc_get_datum(scc_regmap_t regs
, unsigned int offset
)
460 volatile unsigned char *address
= (unsigned char *) regs
+ offset
;
463 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
465 value
= *address
; eieio();
468 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
472 scc_param(struct scc_tty
*tp
)
476 unsigned short speed_value
;
479 struct scc_softreg
*sr
;
482 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
485 simple_lock(&scc_stomp
); /* (TEST/DEBUG) */
487 chan
= scc_chan(tp
->t_dev
);
491 sr
= &scc
->softr
[chan
];
493 /* Do a quick check to see if the hardware needs to change */
494 if ((sr
->flags
& (TF_ODDP
|TF_EVENP
)) == (tp
->t_flags
& (TF_ODDP
|TF_EVENP
))
495 && sr
->speed
== tp
->t_ispeed
) {
496 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
497 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
498 splx(s
); /* (TEST/DEBUG) */
499 return 0; /* (TEST/DEBUG) */
504 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
|SCC_WR3_RX_ENABLE
); /* (TEST/DEBUG) */
505 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
; /* (TEST/DEBUG) */
506 scc_write_reg(regs
, chan
, 1, sr
->wr1
); /* (TEST/DEBUG) */
507 scc_write_reg(regs
, chan
, 15, SCC_WR15_ENABLE_ESCC
); /* (TEST/DEBUG) */
508 scc_write_reg(regs
, chan
, 7, SCC_WR7P_RX_FIFO
); /* (TEST/DEBUG) */
509 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
); /* (TEST/DEBUG) */
510 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
); /* (TEST/DEBUG) */
511 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
); /* (TEST/DEBUG) */
512 scc_write_reg(regs
, chan
, 9, SCC_WR9_MASTER_IE
|SCC_WR9_NV
); /* (TEST/DEBUG) */
513 scc_read_reg_zero(regs
, 0, bits
); /* (TEST/DEBUG) */
514 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
; /* (TEST/DEBUG) */
515 scc_write_reg(regs
, chan
, 1, sr
->wr1
); /* (TEST/DEBUG) */
516 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
); /* (TEST/DEBUG) */
517 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
518 splx(s
); /* (TEST/DEBUG) */
519 return 0; /* (TEST/DEBUG) */
522 sr
->flags
= tp
->t_flags
;
523 sr
->speed
= tp
->t_ispeed
;
526 if (tp
->t_ispeed
== 0) {
527 sr
->wr5
&= ~SCC_WR5_DTR
;
528 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
529 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
532 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
537 #if SCC_DMA_TRANSFERS
538 if (scc
->dma_initted
& (1<<chan
))
539 scc
->dma_ops
->scc_dma_reset_rx(chan
);
542 value
= SCC_WR4_1_STOP
;
545 * For 115K the clocking divide changes to 64.. to 230K will
546 * start at the normal clock divide 16.
548 * However, both speeds will pull from a different clocking
552 if (tp
->t_ispeed
== 115200)
553 value
|= SCC_WR4_CLK_x32
;
555 value
|= SCC_WR4_CLK_x16
;
558 if ((tp
->t_flags
& (TF_ODDP
| TF_EVENP
)) == TF_EVENP
)
559 value
|= (SCC_WR4_EVEN_PARITY
| SCC_WR4_PARITY_ENABLE
);
560 else if ((tp
->t_flags
& (TF_ODDP
| TF_EVENP
)) == TF_ODDP
)
561 value
|= SCC_WR4_PARITY_ENABLE
;
563 /* set it now, remember it must be first after reset */
566 /* Program Parity, and Stop bits */
567 scc_write_reg(regs
, chan
, 4, sr
->wr4
);
569 /* Setup for 8 bits */
570 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
);
572 // Set DTR, RTS, and transmitter bits/character.
573 sr
->wr5
= SCC_WR5_TX_8_BITS
| SCC_WR5_RTS
| SCC_WR5_DTR
;
575 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
577 scc_write_reg(regs
, chan
, 14, 0); /* Disable baud rate */
579 /* Setup baud rate 57.6Kbps, 115K, 230K should all yeild
580 * a converted baud rate of zero
582 speed_value
= convert_baud_rate(tp
->t_ispeed
);
584 if (speed_value
== 0xffff)
587 scc_set_timing_base(regs
, chan
, speed_value
);
589 if (tp
->t_ispeed
== 115200 || tp
->t_ispeed
== 230400) {
590 /* Special case here.. change the clock source*/
591 scc_write_reg(regs
, chan
, 11, 0);
592 /* Baud rate generator is disabled.. */
594 scc_write_reg(regs
, chan
, 11, SCC_WR11_RCLK_BAUDR
|SCC_WR11_XTLK_BAUDR
);
595 /* Enable the baud rate generator */
596 scc_write_reg(regs
, chan
, 14, SCC_WR14_BAUDR_ENABLE
);
600 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
|SCC_WR3_RX_ENABLE
);
603 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
604 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
605 scc_write_reg(regs
, chan
, 15, SCC_WR15_ENABLE_ESCC
);
606 scc_write_reg(regs
, chan
, 7, SCC_WR7P_RX_FIFO
);
607 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
610 /* Clear out any pending external or status interrupts */
611 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
612 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
613 //scc_write_reg(regs, chan, 0, SCC_RESET_ERROR);
615 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
616 scc_write_reg(regs
, chan
, 9, SCC_WR9_MASTER_IE
|SCC_WR9_NV
);
618 scc_read_reg_zero(regs
, 0, bits
);/* Clear the status */
620 #if SCC_DMA_TRANSFERS
621 if (scc
->dma_initted
& (1<<chan
)) {
622 scc
->dma_ops
->scc_dma_start_rx(chan
);
623 scc
->dma_ops
->scc_dma_setup_8530(chan
);
627 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
628 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
629 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
632 sr
->wr5
|= SCC_WR5_TX_ENABLE
;
633 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
635 simple_unlock(&scc_stomp
); /* (TEST/DEBUG) */
638 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
644 * This routine will start a thread that polls the serial port, listening for
645 * characters that have been typed.
649 serial_keyboard_init(void)
652 if(!(serialmode
& 2)) return; /* Leave if we do not want a serial console */
654 kprintf("Serial keyboard started\n");
655 kernel_thread_with_priority(serial_keyboard_start
, MAXPRI_STANDARD
);
660 serial_keyboard_start(void)
664 cthread
= current_thread(); /* Just who the heck are we anyway? */
665 stack_privilege(cthread
); /* Make sure we don't lose our stack */
666 serial_keyboard_poll(); /* Go see if there are any characters pending now */
667 panic("serial_keyboard_start: we can't get back here\n");
671 serial_keyboard_poll(void)
675 extern void cons_cinput(char ch
); /* The BSD routine that gets characters */
677 while(1) { /* Do this for a while */
678 chr
= scc_getc(0, 1, 0, 1); /* Get a character if there is one */
679 if(chr
< 0) break; /* The serial buffer is empty */
680 cons_cinput((char)chr
); /* Buffer up the character */
683 clock_interval_to_deadline(16, 1000000, &next
); /* Get time of pop */
685 assert_wait((event_t
)serial_keyboard_poll
, THREAD_INTERRUPTIBLE
); /* Show we are "waiting" */
686 thread_set_timer_deadline(next
); /* Set the next time to check */
687 thread_block(serial_keyboard_poll
); /* Wait for it */
688 panic("serial_keyboard_poll: Shouldn't never ever get here...\n");
691 #endif /* NSCC > 0 */