Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / arch / ppc / boot / simple / m8xx_tty.c
1 /* Minimal serial functions needed to send messages out the serial
2  * port on the MBX console.
3  *
4  * The MBX uxes SMC1 for the serial port.  We reset the port and use
5  * only the first BD that EPPC-Bug set up as a character FIFO.
6  *
7  * Later versions (at least 1.4, maybe earlier) of the MBX EPPC-Bug
8  * use COM1 instead of SMC1 as the console port.  This kinda sucks
9  * for the rest of the kernel, so here we force the use of SMC1 again.
10  */
11 #include <linux/config.h>
12 #include <linux/types.h>
13 #include <asm/uaccess.h>
14 #include <asm/mpc8xx.h>
15 #include <asm/commproc.h>
16
17 #ifdef CONFIG_MBX
18 #define MBX_CSR1        ((volatile u_char *)0xfa100000)
19 #define CSR1_COMEN      (u_char)0x02
20 #endif
21
22 #ifdef TQM_SMC2_CONSOLE
23 #define PROFF_CONS      PROFF_SMC2
24 #define CPM_CR_CH_CONS  CPM_CR_CH_SMC2
25 #define SMC_INDEX       1
26 static volatile iop8xx_t *iopp = (iop8xx_t *)&(((immap_t *)IMAP_ADDR)->im_ioport);
27 #else
28 #define PROFF_CONS      PROFF_SMC1
29 #define CPM_CR_CH_CONS  CPM_CR_CH_SMC1
30 #define SMC_INDEX       0
31 #endif
32
33 static cpm8xx_t *cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
34
35 unsigned long
36 serial_init(int ignored, bd_t *bd)
37 {
38         volatile smc_t          *sp;
39         volatile smc_uart_t     *up;
40         volatile cbd_t  *tbdf, *rbdf;
41         volatile cpm8xx_t       *cp;
42         uint    dpaddr, memaddr;
43 #ifndef CONFIG_MBX
44         uint    ui;
45 #endif
46
47         cp = cpmp;
48         sp = (smc_t*)&(cp->cp_smc[SMC_INDEX]);
49         up = (smc_uart_t *)&cp->cp_dparam[PROFF_CONS];
50
51         /* Disable transmitter/receiver.
52         */
53         sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
54
55 #ifdef CONFIG_FADS
56         /* Enable SMC1/2 transceivers.
57         */
58         *((volatile uint *)BCSR1) &= ~(BCSR1_RS232EN_1|BCSR1_RS232EN_2);
59 #endif
60
61 #ifndef CONFIG_MBX
62         {
63         /* Initialize SMCx and use it for the console port.
64          */
65
66         /* Enable SDMA.
67         */
68         ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1;
69
70 #ifdef TQM_SMC2_CONSOLE
71         /* Use Port A for SMC2 instead of other functions.
72         */
73         iopp->iop_papar |=  0x00c0;
74         iopp->iop_padir &= ~0x00c0;
75         iopp->iop_paodr &= ~0x00c0;
76 #else
77         /* Use Port B for SMCs instead of other functions.
78         */
79         cp->cp_pbpar |= 0x00000cc0;
80         cp->cp_pbdir &= ~0x00000cc0;
81         cp->cp_pbodr &= ~0x00000cc0;
82 #endif
83
84         /* Allocate space for two buffer descriptors in the DP ram.
85          * For now, this address seems OK, but it may have to
86          * change with newer versions of the firmware.
87          */
88         dpaddr = 0x0800;
89
90         /* Grab a few bytes from the top of memory for SMC FIFOs.
91          */
92         memaddr = (bd->bi_memsize - 32) & ~15;
93
94         /* Set the physical address of the host memory buffers in
95          * the buffer descriptors.
96          */
97         rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
98         rbdf->cbd_bufaddr = memaddr;
99         rbdf->cbd_sc = 0;
100         tbdf = rbdf + 1;
101         tbdf->cbd_bufaddr = memaddr+4;
102         tbdf->cbd_sc = 0;
103
104         /* Set up the uart parameters in the parameter ram.
105         */
106         up->smc_rbase = dpaddr;
107         up->smc_tbase = dpaddr+sizeof(cbd_t);
108         up->smc_rfcr = SMC_EB;
109         up->smc_tfcr = SMC_EB;
110
111         /* Set UART mode, 8 bit, no parity, one stop.
112          * Enable receive and transmit.
113          */
114         sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
115
116         /* Mask all interrupts and remove anything pending.
117         */
118         sp->smc_smcm = 0;
119         sp->smc_smce = 0xff;
120
121         /* Set up the baud rate generator.
122          * See 8xx_io/commproc.c for details.
123          * This wires BRG1 to SMC1 and BRG2 to SMC2;
124          */
125         cp->cp_simode = 0x10000000;
126         ui = bd->bi_intfreq / 16 / bd->bi_baudrate;
127 #ifdef TQM_SMC2_CONSOLE
128         cp->cp_brgc2 =
129 #else
130         cp->cp_brgc1 =
131 #endif
132                 ((ui - 1) < 4096)
133                 ? (((ui - 1) << 1) | CPM_BRG_EN)
134                 : ((((ui / 16) - 1) << 1) | CPM_BRG_EN | CPM_BRG_DIV16);
135
136 #else /* CONFIG_MBX */
137         if (*MBX_CSR1 & CSR1_COMEN) {
138                 /* COM1 is enabled.  Initialize SMC1 and use it for
139                  * the console port.
140                  */
141
142                 /* Enable SDMA.
143                 */
144                 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sdcr = 1;
145
146                 /* Use Port B for SMCs instead of other functions.
147                 */
148                 cp->cp_pbpar |= 0x00000cc0;
149                 cp->cp_pbdir &= ~0x00000cc0;
150                 cp->cp_pbodr &= ~0x00000cc0;
151
152                 /* Allocate space for two buffer descriptors in the DP ram.
153                  * For now, this address seems OK, but it may have to
154                  * change with newer versions of the firmware.
155                  */
156                 dpaddr = 0x0800;
157
158                 /* Grab a few bytes from the top of memory.  EPPC-Bug isn't
159                  * running any more, so we can do this.
160                  */
161                 memaddr = (bd->bi_memsize - 32) & ~15;
162
163                 /* Set the physical address of the host memory buffers in
164                  * the buffer descriptors.
165                  */
166                 rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
167                 rbdf->cbd_bufaddr = memaddr;
168                 rbdf->cbd_sc = 0;
169                 tbdf = rbdf + 1;
170                 tbdf->cbd_bufaddr = memaddr+4;
171                 tbdf->cbd_sc = 0;
172
173                 /* Set up the uart parameters in the parameter ram.
174                 */
175                 up->smc_rbase = dpaddr;
176                 up->smc_tbase = dpaddr+sizeof(cbd_t);
177                 up->smc_rfcr = SMC_EB;
178                 up->smc_tfcr = SMC_EB;
179
180                 /* Set UART mode, 8 bit, no parity, one stop.
181                  * Enable receive and transmit.
182                  */
183                 sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
184
185                 /* Mask all interrupts and remove anything pending.
186                 */
187                 sp->smc_smcm = 0;
188                 sp->smc_smce = 0xff;
189
190                 /* Set up the baud rate generator.
191                  * See 8xx_io/commproc.c for details.
192                  */
193                 cp->cp_simode = 0x10000000;
194                 cp->cp_brgc1 =
195                         (((bd->bi_intfreq/16) / 9600) << 1) | CPM_BRG_EN;
196
197                 /* Enable SMC1 for console output.
198                 */
199                 *MBX_CSR1 &= ~CSR1_COMEN;
200         }
201         else {
202 #endif /* ndef CONFIG_MBX */
203                 /* SMCx is used as console port.
204                 */
205                 tbdf = (cbd_t *)&cp->cp_dpmem[up->smc_tbase];
206                 rbdf = (cbd_t *)&cp->cp_dpmem[up->smc_rbase];
207
208                 /* Issue a stop transmit, and wait for it.
209                 */
210                 cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS,
211                                         CPM_CR_STOP_TX) | CPM_CR_FLG;
212                 while (cp->cp_cpcr & CPM_CR_FLG);
213         }
214
215         /* Make the first buffer the only buffer.
216         */
217         tbdf->cbd_sc |= BD_SC_WRAP;
218         rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
219
220         /* Single character receive.
221         */
222         up->smc_mrblr = 1;
223         up->smc_maxidl = 0;
224
225         /* Initialize Tx/Rx parameters.
226         */
227         cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_CONS, CPM_CR_INIT_TRX) | CPM_CR_FLG;
228         while (cp->cp_cpcr & CPM_CR_FLG);
229
230         /* Enable transmitter/receiver.
231         */
232         sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
233
234         /* This is ignored.
235         */
236         return 0;
237 }
238
239 void
240 serial_putc(void *ignored, const char c)
241 {
242         volatile cbd_t          *tbdf;
243         volatile char           *buf;
244         volatile smc_uart_t     *up;
245
246         up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
247         tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
248
249         /* Wait for last character to go.
250         */
251         buf = (char *)tbdf->cbd_bufaddr;
252         while (tbdf->cbd_sc & BD_SC_READY);
253
254         *buf = c;
255         tbdf->cbd_datlen = 1;
256         tbdf->cbd_sc |= BD_SC_READY;
257 }
258
259 char
260 serial_getc(void *ignored)
261 {
262         volatile cbd_t          *rbdf;
263         volatile char           *buf;
264         volatile smc_uart_t     *up;
265         char                    c;
266
267         up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
268         rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
269
270         /* Wait for character to show up.
271         */
272         buf = (char *)rbdf->cbd_bufaddr;
273         while (rbdf->cbd_sc & BD_SC_EMPTY);
274         c = *buf;
275         rbdf->cbd_sc |= BD_SC_EMPTY;
276
277         return(c);
278 }
279
280 int
281 serial_tstc(void *ignored)
282 {
283         volatile cbd_t          *rbdf;
284         volatile smc_uart_t     *up;
285
286         up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_CONS];
287         rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
288
289         return(!(rbdf->cbd_sc & BD_SC_EMPTY));
290 }