vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / boot / simple / mpc52xx_tty.c
1 /*
2  * arch/ppc/boot/simple/mpc52xx_tty.c
3  *
4  * Minimal serial functions needed to send messages out a MPC52xx
5  * Programmable Serial Controller (PSC).
6  *
7  * Author: Dale Farnsworth <dfarnsworth@mvista.com>
8  *
9  * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under the
10  * terms of the GNU General Public License version 2.  This program is licensed
11  * "as is" without any warranty of any kind, whether express or implied.
12  */
13
14 #include <linux/config.h>
15 #include <linux/types.h>
16 #include <asm/uaccess.h>
17 #include <asm/mpc52xx.h>
18 #include <asm/mpc52xx_psc.h>
19 #include <asm/serial.h>
20 #include <asm/io.h>
21 #include <asm/time.h>
22
23 #if MPC52xx_PF_CONSOLE_PORT == 0
24 #define MPC52xx_CONSOLE         MPC52xx_PSC1
25 #define MPC52xx_PSC_CONFIG_SHIFT        0
26 #elif MPC52xx_PF_CONSOLE_PORT == 1
27 #define MPC52xx_CONSOLE         MPC52xx_PSC2
28 #define MPC52xx_PSC_CONFIG_SHIFT        4
29 #elif MPC52xx_PF_CONSOLE_PORT == 2
30 #define MPC52xx_CONSOLE         MPC52xx_PSC3
31 #define MPC52xx_PSC_CONFIG_SHIFT        8
32 #else
33 #error "MPC52xx_PF_CONSOLE_PORT not defined"
34 #endif
35
36 static struct mpc52xx_psc *psc = (struct mpc52xx_psc *)MPC52xx_CONSOLE;
37
38 /* The decrementer counts at the system bus clock frequency
39  * divided by four.  The most accurate time base is connected to the
40  * rtc.  We read the decrementer change during one rtc tick (one second)
41  * and multiply by 4 to get the system bus clock frequency.
42  */
43 int
44 mpc52xx_ipbfreq(void)
45 {
46         struct mpc52xx_rtc *rtc = (struct mpc52xx_rtc*)MPC52xx_RTC;
47         struct mpc52xx_cdm *cdm = (struct mpc52xx_cdm*)MPC52xx_CDM;
48         int current_time, previous_time;
49         int tbl_start, tbl_end;
50         int xlbfreq, ipbfreq;
51
52         out_be32(&rtc->dividers, 0x8f1f0000);   /* Set RTC 64x faster */
53         previous_time = in_be32(&rtc->time);
54         while ((current_time = in_be32(&rtc->time)) == previous_time) ;
55         tbl_start = get_tbl();
56         previous_time = current_time;
57         while ((current_time = in_be32(&rtc->time)) == previous_time) ;
58         tbl_end = get_tbl();
59         out_be32(&rtc->dividers, 0xffff0000);   /* Restore RTC */
60
61         xlbfreq = (tbl_end - tbl_start) << 8;
62         ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ? xlbfreq / 2 : xlbfreq;
63
64         return ipbfreq;
65 }
66
67 unsigned long
68 serial_init(int ignored, void *ignored2)
69 {
70         struct mpc52xx_gpio *gpio = (struct mpc52xx_gpio *)MPC52xx_GPIO;
71         int divisor;
72         int mode1;
73         int mode2;
74         u32 val32;
75
76         static int been_here = 0;
77
78         if (been_here)
79                 return 0;
80
81         been_here = 1;
82
83         val32 = in_be32(&gpio->port_config);
84         val32 &= ~(0x7 << MPC52xx_PSC_CONFIG_SHIFT);
85         val32 |= MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD
86                                 << MPC52xx_PSC_CONFIG_SHIFT;
87         out_be32(&gpio->port_config, val32);
88
89         out_8(&psc->command, MPC52xx_PSC_RST_TX
90                         | MPC52xx_PSC_RX_DISABLE | MPC52xx_PSC_TX_ENABLE);
91         out_8(&psc->command, MPC52xx_PSC_RST_RX);
92
93         out_be32(&psc->sicr, 0x0);
94         out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
95         out_be16(&psc->tfalarm, 0xf8);
96
97         out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1
98                         | MPC52xx_PSC_RX_ENABLE
99                         | MPC52xx_PSC_TX_ENABLE);
100
101         divisor = ((mpc52xx_ipbfreq()
102                         / (CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD * 16)) + 1) >> 1;
103
104         mode1 = MPC52xx_PSC_MODE_8_BITS | MPC52xx_PSC_MODE_PARNONE
105                         | MPC52xx_PSC_MODE_ERR;
106         mode2 = MPC52xx_PSC_MODE_ONE_STOP;
107
108         out_8(&psc->ctur, divisor>>8);
109         out_8(&psc->ctlr, divisor);
110         out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
111         out_8(&psc->mode, mode1);
112         out_8(&psc->mode, mode2);
113
114         return 0;       /* ignored */
115 }
116
117 void
118 serial_putc(void *ignored, const char c)
119 {
120         serial_init(0, 0);
121
122         while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
123         out_8(&psc->mpc52xx_psc_buffer_8, c);
124         while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP)) ;
125 }
126
127 char
128 serial_getc(void *ignored)
129 {
130         while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY)) ;
131
132         return in_8(&psc->mpc52xx_psc_buffer_8);
133 }
134
135 int
136 serial_tstc(void *ignored)
137 {
138         return (in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY) != 0;
139 }