2 * Copyright (c) 2000-2005 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 <kern/thread.h>
73 #include <ppc/misc_protos.h>
74 #include <ppc/proc_reg.h>
75 #include <ppc/exception.h>
76 #include <ppc/Firmware.h>
77 #include <ppc/serial_io.h>
78 #include <ppc/scc_8530.h>
81 #include <machine/db_machdep.h>
84 #define kdebug_state() (1)
85 #define delay(x) { volatile int _d_; for (_d_ = 0; _d_ < (10000*x); _d_++) ; }
87 #define NSCC_LINE 2 /* 2 ttys per chip */
89 #define SCC_DMA_TRANSFERS 0
91 struct scc_tty scc_tty
[NSCC_LINE
];
93 #define scc_tty_for(chan) (&scc_tty[chan])
94 /* #define scc_unit(dev_no) (dev_no) */
96 #define scc_dev_no(chan) ((chan)^0x01)
97 #define scc_chan(dev_no) ((dev_no)^0x01)
99 extern unsigned int disableSerialOuput
;
101 int serial_initted
= 0;
102 unsigned int scc_parm_done
= 0;
104 extern unsigned int serialmode
;
106 static struct scc_byte
{
127 1, 0x12, /* int or Rx, Tx int enable */
129 1, 0x10, /* int or Rx, no Tx int enable */
134 static int scc_init_hw_count
= sizeof(scc_init_hw
)/sizeof(scc_init_hw
[0]);
136 enum scc_error
{SCC_ERR_NONE
, SCC_ERR_PARITY
, SCC_ERR_BREAK
, SCC_ERR_OVERRUN
};
141 * ClockFrequency (115200 for Power Mac)
142 * BRGconstant = --------------------------- - 2
146 #define SERIAL_CLOCK_FREQUENCY (115200*2) /* Power Mac value */
147 #define convert_baud_rate(rate) ((((SERIAL_CLOCK_FREQUENCY) + (rate)) / (2 * (rate))) - 2)
149 #define DEFAULT_SPEED 57600
150 #define DEFAULT_PORT0_SPEED 1200
151 #define DEFAULT_FLAGS (TF_LITOUT|TF_ECHO)
153 int scc_param(struct scc_tty
*tp
);
156 struct scc_softc scc_softc
[NSCC
];
157 caddr_t scc_std
[NSCC
] = { (caddr_t
) 0};
160 #define SCC_RR1_ERRS (SCC_RR1_FRAME_ERR|SCC_RR1_RX_OVERRUN|SCC_RR1_PARITY_ERR)
161 #define SCC_RR3_ALL (SCC_RR3_RX_IP_A|SCC_RR3_TX_IP_A|SCC_RR3_EXT_IP_A|\
162 SCC_RR3_RX_IP_B|SCC_RR3_TX_IP_B|SCC_RR3_EXT_IP_B)
168 static int total_chars
, total_ints
, total_overruns
, total_errors
, num_ints
, max_chars
;
169 static int chars_received
[8];
170 static int __SCC_STATS
= 0;
171 static int max_in_q
= 0;
172 static int max_out_q
= 0;
175 DECL_FUNNEL(, scc_funnel
) /* funnel to serialize the SCC driver */
176 boolean_t scc_funnel_initted
= FALSE
;
177 #define SCC_FUNNEL scc_funnel
178 #define SCC_FUNNEL_INITTED scc_funnel_initted
182 * Adapt/Probe/Attach functions
184 boolean_t scc_uses_modem_control
= FALSE
;/* patch this with adb */
185 decl_simple_lock_data(,scc_stomp
)
187 /* This is called VERY early on in the init and therefore has to have
188 * hardcoded addresses of the serial hardware control registers. The
189 * serial line may be needed for console and debugging output before
190 * anything else takes place
194 initialize_serial( caddr_t scc_phys_base
, int32_t serial_baud
)
200 assert( scc_phys_base
);
202 if (!SCC_FUNNEL_INITTED
) {
203 FUNNEL_INIT(&SCC_FUNNEL
, master_processor
);
204 SCC_FUNNEL_INITTED
= TRUE
;
206 FUNNEL_ENTER(&SCC_FUNNEL
);
208 if (serial_initted
) {
209 FUNNEL_EXIT(&SCC_FUNNEL
);
213 simple_lock_init(&scc_stomp
, FALSE
);
215 if (serial_baud
== -1) serial_baud
= DEFAULT_SPEED
;
217 scc_softc
[0].full_modem
= TRUE
;
219 scc_std
[0] = scc_phys_base
;
221 regs
= scc_softc
[0].regs
= (scc_regmap_t
)scc_std
[0];
223 for (chan
= 0; chan
< NSCC_LINE
; chan
++) {
225 scc_init_hw
[0].val
= 0x80;
227 for (i
= 0; i
< scc_init_hw_count
; i
++) {
228 scc_write_reg(regs
, chan
,
229 scc_init_hw
[i
].reg
, scc_init_hw
[i
].val
);
233 /* Call probe so we are ready very early for remote gdb and for serial
234 console output if appropriate. */
235 if (scc_probe(serial_baud
)) {
236 for (i
= 0; i
< NSCC_LINE
; i
++) {
237 scc_softc
[0].softr
[i
].wr5
= SCC_WR5_DTR
| SCC_WR5_RTS
;
238 scc_param(scc_tty_for(i
));
239 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
240 scc_write_reg(regs
, i
, 9, SCC_WR9_NV
);
242 scc_read_reg_zero(regs
, 0, bits
);/* Clear the status */
247 serial_initted
= TRUE
;
249 FUNNEL_EXIT(&SCC_FUNNEL
);
254 scc_probe(int32_t serial_baud
)
258 register scc_regmap_t regs
;
262 if (!SCC_FUNNEL_INITTED
) {
263 FUNNEL_INIT(&SCC_FUNNEL
, master_processor
);
264 SCC_FUNNEL_INITTED
= TRUE
;
266 FUNNEL_ENTER(&SCC_FUNNEL
);
268 /* Readjust the I/O address to handling
269 * new memory mappings.
272 regs
= (scc_regmap_t
)scc_std
[0];
274 if (regs
== (scc_regmap_t
) 0) {
275 FUNNEL_EXIT(&SCC_FUNNEL
);
284 for (i
= 0; i
< NSCC_LINE
; i
++) {
285 register struct scc_tty
*tp
;
287 tp
->t_addr
= (char*)(0x80000000L
+ (i
&1));
288 /* Set default values. These will be overridden on
289 open but are needed if the port will be used
290 independently of the Mach interfaces, e.g., for
291 gdb or for a serial console. */
293 tp
->t_ispeed
= DEFAULT_PORT0_SPEED
;
294 tp
->t_ospeed
= DEFAULT_PORT0_SPEED
;
296 tp
->t_ispeed
= serial_baud
;
297 tp
->t_ospeed
= serial_baud
;
299 tp
->t_flags
= DEFAULT_FLAGS
;
300 scc
->softr
[i
].speed
= -1;
302 /* do min buffering */
303 tp
->t_state
|= TS_MIN
;
305 tp
->t_dev
= scc_dev_no(i
);
310 FUNNEL_EXIT(&SCC_FUNNEL
);
315 * Get a char from a specific SCC line
316 * [this is only used for console&screen purposes]
317 * must be splhigh since it may be called from another routine under spl
321 scc_getc(int unit
, int line
, boolean_t wait
, boolean_t raw
)
323 register scc_regmap_t regs
;
324 unsigned char c
, value
;
325 int rcvalue
, from_line
;
330 FUNNEL_ENTER(&SCC_FUNNEL
);
333 simple_lock(&scc_stomp
);
334 regs
= scc_softc
[0].regs
;
337 * wait till something available
343 scc_read_reg_zero(regs
, line
, value
);
345 if (value
& SCC_RR0_RX_AVAIL
)
349 simple_unlock(&scc_stomp
);
351 FUNNEL_EXIT(&SCC_FUNNEL
);
357 * if nothing found return -1
360 scc_read_reg(regs
, line
, SCC_RR1
, value
);
361 scc_read_data(regs
, line
, c
);
364 if (console_is_serial() &&
366 /* Drop into the debugger */
367 simple_unlock(&scc_stomp
);
368 Debugger("Serial Line Request");
369 simple_lock(&scc_stomp
);
370 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
374 simple_unlock(&scc_stomp
);
376 FUNNEL_EXIT(&SCC_FUNNEL
);
379 #endif /* MACH_KDB */
384 if (value
&(SCC_RR1_PARITY_ERR
| SCC_RR1_RX_OVERRUN
| SCC_RR1_FRAME_ERR
)) {
385 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_ERROR
);
388 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
393 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
395 simple_unlock(&scc_stomp
);
398 FUNNEL_EXIT(&SCC_FUNNEL
);
403 * Put a char on a specific SCC line
404 * use splhigh since we might be doing a printf in high spl'd code
408 scc_putc(int unit
, int line
, int c
)
417 if (disableSerialOuput
)
421 FUNNEL_ENTER(&SCC_FUNNEL
);
422 simple_lock(&scc_stomp
);
424 regs
= scc_softc
[0].regs
;
427 scc_read_reg(regs
, line
, SCC_RR0
, value
);
428 if (value
& SCC_RR0_TX_EMPTY
)
433 scc_write_data(regs
, line
, c
);
434 /* wait for it to swallow the char ? */
437 scc_read_reg(regs
, line
, SCC_RR0
, value
);
438 if (value
& SCC_RR0_TX_EMPTY
)
441 scc_write_reg(regs
, line
, SCC_RR0
, SCC_RESET_HIGHEST_IUS
);
442 simple_unlock(&scc_stomp
);
446 FUNNEL_EXIT(&SCC_FUNNEL
);
452 powermac_scc_set_datum(scc_regmap_t regs
, unsigned int offset
, unsigned char value
)
454 volatile unsigned char *address
= (unsigned char *) regs
+ offset
;
456 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
461 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
465 powermac_scc_get_datum(scc_regmap_t regs
, unsigned int offset
)
467 volatile unsigned char *address
= (unsigned char *) regs
+ offset
;
470 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
472 value
= *address
; eieio();
475 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
479 scc_param(struct scc_tty
*tp
)
483 unsigned short speed_value
;
486 struct scc_softreg
*sr
;
489 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
492 simple_lock(&scc_stomp
);
494 chan
= scc_chan(tp
->t_dev
);
498 sr
= &scc
->softr
[chan
];
500 /* Do a quick check to see if the hardware needs to change */
501 if ((sr
->flags
& (TF_ODDP
|TF_EVENP
)) == (tp
->t_flags
& (TF_ODDP
|TF_EVENP
))
502 && sr
->speed
== tp
->t_ispeed
) {
503 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
504 simple_unlock(&scc_stomp
);
511 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
|SCC_WR3_RX_ENABLE
);
512 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
513 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
514 scc_write_reg(regs
, chan
, 15, SCC_WR15_ENABLE_ESCC
);
515 scc_write_reg(regs
, chan
, 7, SCC_WR7P_RX_FIFO
);
516 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
517 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
518 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
519 scc_write_reg(regs
, chan
, 9, SCC_WR9_MASTER_IE
|SCC_WR9_NV
);
520 scc_read_reg_zero(regs
, 0, bits
);
521 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
522 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
523 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
524 simple_unlock(&scc_stomp
);
529 sr
->flags
= tp
->t_flags
;
530 sr
->speed
= tp
->t_ispeed
;
533 if (tp
->t_ispeed
== 0) {
534 sr
->wr5
&= ~SCC_WR5_DTR
;
535 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
536 simple_unlock(&scc_stomp
);
539 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
544 #if SCC_DMA_TRANSFERS
545 if (scc
->dma_initted
& (1<<chan
))
546 scc
->dma_ops
->scc_dma_reset_rx(chan
);
549 value
= SCC_WR4_1_STOP
;
552 * For 115K the clocking divide changes to 64.. to 230K will
553 * start at the normal clock divide 16.
555 * However, both speeds will pull from a different clocking
559 if (tp
->t_ispeed
== 115200)
560 value
|= SCC_WR4_CLK_x32
;
562 value
|= SCC_WR4_CLK_x16
;
565 if ((tp
->t_flags
& (TF_ODDP
| TF_EVENP
)) == TF_EVENP
)
566 value
|= (SCC_WR4_EVEN_PARITY
| SCC_WR4_PARITY_ENABLE
);
567 else if ((tp
->t_flags
& (TF_ODDP
| TF_EVENP
)) == TF_ODDP
)
568 value
|= SCC_WR4_PARITY_ENABLE
;
570 /* set it now, remember it must be first after reset */
573 /* Program Parity, and Stop bits */
574 scc_write_reg(regs
, chan
, 4, sr
->wr4
);
576 /* Setup for 8 bits */
577 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
);
579 // Set DTR, RTS, and transmitter bits/character.
580 sr
->wr5
= SCC_WR5_TX_8_BITS
| SCC_WR5_RTS
| SCC_WR5_DTR
;
582 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
584 scc_write_reg(regs
, chan
, 14, 0); /* Disable baud rate */
586 /* Setup baud rate 57.6Kbps, 115K, 230K should all yeild
587 * a converted baud rate of zero
589 speed_value
= convert_baud_rate(tp
->t_ispeed
);
591 if (speed_value
== 0xffff)
594 scc_set_timing_base(regs
, chan
, speed_value
);
596 if (tp
->t_ispeed
== 115200 || tp
->t_ispeed
== 230400) {
597 /* Special case here.. change the clock source*/
598 scc_write_reg(regs
, chan
, 11, 0);
599 /* Baud rate generator is disabled.. */
601 scc_write_reg(regs
, chan
, 11, SCC_WR11_RCLK_BAUDR
|SCC_WR11_XTLK_BAUDR
);
602 /* Enable the baud rate generator */
603 scc_write_reg(regs
, chan
, 14, SCC_WR14_BAUDR_ENABLE
);
607 scc_write_reg(regs
, chan
, 3, SCC_WR3_RX_8_BITS
|SCC_WR3_RX_ENABLE
);
610 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
611 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
612 scc_write_reg(regs
, chan
, 15, SCC_WR15_ENABLE_ESCC
);
613 scc_write_reg(regs
, chan
, 7, SCC_WR7P_RX_FIFO
);
614 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
617 /* Clear out any pending external or status interrupts */
618 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
619 scc_write_reg(regs
, chan
, 0, SCC_RESET_EXT_IP
);
620 //scc_write_reg(regs, chan, 0, SCC_RESET_ERROR);
622 /* Enable SCC interrupts (how many interrupts are to this thing?!?) */
623 scc_write_reg(regs
, chan
, 9, SCC_WR9_MASTER_IE
|SCC_WR9_NV
);
625 scc_read_reg_zero(regs
, 0, bits
);/* Clear the status */
627 #if SCC_DMA_TRANSFERS
628 if (scc
->dma_initted
& (1<<chan
)) {
629 scc
->dma_ops
->scc_dma_start_rx(chan
);
630 scc
->dma_ops
->scc_dma_setup_8530(chan
);
634 sr
->wr1
= SCC_WR1_RXI_FIRST_CHAR
| SCC_WR1_EXT_IE
;
635 scc_write_reg(regs
, chan
, 1, sr
->wr1
);
636 scc_write_reg(regs
, chan
, 0, SCC_IE_NEXT_CHAR
);
639 sr
->wr5
|= SCC_WR5_TX_ENABLE
;
640 scc_write_reg(regs
, chan
, 5, sr
->wr5
);
642 simple_unlock(&scc_stomp
);
645 assert(FUNNEL_IN_USE(&SCC_FUNNEL
));
651 * This routine will start a thread that polls the serial port, listening for
652 * characters that have been typed.
656 serial_keyboard_init(void)
658 kern_return_t result
;
661 if(!(serialmode
& 2)) return; /* Leave if we do not want a serial console */
663 kprintf("Serial keyboard started\n");
664 result
= kernel_thread_start_priority((thread_continue_t
)serial_keyboard_start
, NULL
, MAXPRI_KERNEL
, &thread
);
665 if (result
!= KERN_SUCCESS
)
666 panic("serial_keyboard_init");
668 thread_deallocate(thread
);
672 serial_keyboard_start(void)
674 serial_keyboard_poll(); /* Go see if there are any characters pending now */
675 panic("serial_keyboard_start: we can't get back here\n");
678 static int ptestxxx
= 0;
681 serial_keyboard_poll(void)
685 extern void cons_cinput(char ch
); /* The BSD routine that gets characters */
688 while(1) { /* Do this for a while */
689 chr
= scc_getc(0, 1, 0, 1); /* Get a character if there is one */
690 if(chr
< 0) break; /* The serial buffer is empty */
691 cons_cinput((char)chr
); /* Buffer up the character */
694 clock_interval_to_deadline(16, 1000000, &next
); /* Get time of pop */
696 assert_wait_deadline((event_t
)serial_keyboard_poll
, THREAD_UNINT
, next
); /* Show we are "waiting" */
697 thread_block((thread_continue_t
)serial_keyboard_poll
); /* Wait for it */
698 panic("serial_keyboard_poll: Shouldn't never ever get here...\n");
701 #endif /* NSCC > 0 */