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