ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / boot / simple / m8260_tty.c
1 /* Minimal serial functions needed to send messages out the serial
2  * port on SMC1.
3  */
4 #include <linux/types.h>
5 #include <asm/mpc8260.h>
6 #include <asm/cpm_8260.h>
7
8 uint    no_print;
9 extern char     *params[];
10 extern int      nparams;
11 static          u_char  cons_hold[128], *sgptr;
12 static          int     cons_hold_cnt;
13
14 /* If defined, enables serial console.  The value (1 through 4)
15  * should designate which SCC is used, but this isn't complete.  Only
16  * SCC1 is known to work at this time.
17  */
18 #ifdef CONFIG_SCC_CONSOLE
19 #define SCC_CONSOLE 1
20 #endif
21
22 unsigned long
23 serial_init(int ignored, bd_t *bd)
24 {
25         volatile smc_t          *sp;
26         volatile smc_uart_t     *up;
27 #ifdef SCC_CONSOLE
28         volatile scc_t          *sccp;
29         volatile scc_uart_t     *sup;
30 #endif
31         volatile cbd_t  *tbdf, *rbdf;
32         volatile immap_t        *ip;
33         volatile iop8260_t      *io;
34         volatile cpm8260_t      *cp;
35         uint    dpaddr, memaddr;
36
37         ip = (immap_t *)IMAP_ADDR;
38         cp = &ip->im_cpm;
39         io = &ip->im_ioport;
40
41         /* Perform a reset.
42         */
43         cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
44
45         /* Wait for it.
46         */
47         while (cp->cp_cpcr & CPM_CR_FLG);
48
49 #ifdef CONFIG_ADS8260
50         /* Enable the RS-232 transceivers.
51         */
52         *(volatile uint *)(BCSR_ADDR + 4) &=
53                                         ~(BCSR1_RS232_EN1 | BCSR1_RS232_EN2);
54 #endif
55
56 #ifdef SCC_CONSOLE
57         sccp = (scc_t *)&(ip->im_scc[SCC_CONSOLE-1]);
58         sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
59         sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
60         sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
61
62         /* Use Port D for SCC1 instead of other functions.
63         */
64         io->iop_ppard |= 0x00000003;
65         io->iop_psord &= ~0x00000001;   /* Rx */
66         io->iop_psord |= 0x00000002;    /* Tx */
67         io->iop_pdird &= ~0x00000001;   /* Rx */
68         io->iop_pdird |= 0x00000002;    /* Tx */
69
70 #else
71         sp = (smc_t*)&(ip->im_smc[0]);
72         *(ushort *)(&ip->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
73         up = (smc_uart_t *)&ip->im_dprambase[PROFF_SMC1];
74
75         /* Disable transmitter/receiver.
76         */
77         sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
78
79         /* Use Port D for SMC1 instead of other functions.
80         */
81         io->iop_ppard |= 0x00c00000;
82         io->iop_pdird |= 0x00400000;
83         io->iop_pdird &= ~0x00800000;
84         io->iop_psord &= ~0x00c00000;
85 #endif
86
87         /* Allocate space for two buffer descriptors in the DP ram.
88          * For now, this address seems OK, but it may have to
89          * change with newer versions of the firmware.
90          */
91         dpaddr = 0x0800;
92
93         /* Grab a few bytes from the top of memory.
94          */
95         memaddr = (bd->bi_memsize - 256) & ~15;
96
97         /* Set the physical address of the host memory buffers in
98          * the buffer descriptors.
99          */
100         rbdf = (cbd_t *)&ip->im_dprambase[dpaddr];
101         rbdf->cbd_bufaddr = memaddr;
102         rbdf->cbd_sc = 0;
103         tbdf = rbdf + 1;
104         tbdf->cbd_bufaddr = memaddr+128;
105         tbdf->cbd_sc = 0;
106
107         /* Set up the uart parameters in the parameter ram.
108         */
109 #ifdef SCC_CONSOLE
110         sup->scc_genscc.scc_rbase = dpaddr;
111         sup->scc_genscc.scc_tbase = dpaddr + sizeof(cbd_t);
112
113         /* Set up the uart parameters in the
114          * parameter ram.
115          */
116         sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
117         sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
118
119         sup->scc_genscc.scc_mrblr = 128;
120         sup->scc_maxidl = 8;
121         sup->scc_brkcr = 1;
122         sup->scc_parec = 0;
123         sup->scc_frmec = 0;
124         sup->scc_nosec = 0;
125         sup->scc_brkec = 0;
126         sup->scc_uaddr1 = 0;
127         sup->scc_uaddr2 = 0;
128         sup->scc_toseq = 0;
129         sup->scc_char1 = 0x8000;
130         sup->scc_char2 = 0x8000;
131         sup->scc_char3 = 0x8000;
132         sup->scc_char4 = 0x8000;
133         sup->scc_char5 = 0x8000;
134         sup->scc_char6 = 0x8000;
135         sup->scc_char7 = 0x8000;
136         sup->scc_char8 = 0x8000;
137         sup->scc_rccm = 0xc0ff;
138
139         /* Send the CPM an initialize command.
140         */
141         cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC1_PAGE, CPM_CR_SCC1_SBLOCK, 0,
142                         CPM_CR_INIT_TRX) | CPM_CR_FLG;
143         while (cp->cp_cpcr & CPM_CR_FLG);
144
145         /* Set UART mode, 8 bit, no parity, one stop.
146          * Enable receive and transmit.
147          */
148         sccp->scc_gsmrh = 0;
149         sccp->scc_gsmrl =
150                 (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
151
152         /* Disable all interrupts and clear all pending
153          * events.
154          */
155         sccp->scc_sccm = 0;
156         sccp->scc_scce = 0xffff;
157         sccp->scc_dsr = 0x7e7e;
158         sccp->scc_pmsr = 0x3000;
159
160         /* Wire BRG1 to SCC1.  The console driver will take care of
161          * others.
162          */
163         ip->im_cpmux.cmx_scr = 0;
164 #else
165         up->smc_rbase = dpaddr;
166         up->smc_tbase = dpaddr+sizeof(cbd_t);
167         up->smc_rfcr = CPMFCR_EB;
168         up->smc_tfcr = CPMFCR_EB;
169         up->smc_brklen = 0;
170         up->smc_brkec = 0;
171         up->smc_brkcr = 0;
172         up->smc_mrblr = 128;
173         up->smc_maxidl = 8;
174
175         /* Set UART mode, 8 bit, no parity, one stop.
176          * Enable receive and transmit.
177          */
178         sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
179
180         /* Mask all interrupts and remove anything pending.
181         */
182         sp->smc_smcm = 0;
183         sp->smc_smce = 0xff;
184
185         /* Set up the baud rate generator.
186          */
187         ip->im_cpmux.cmx_smr = 0;
188 #endif
189
190         /* The baud rate divisor needs to be coordinated with clk_8260().
191         */
192         ip->im_brgc1 =
193                 (((bd->bi_brgfreq/16) / bd->bi_baudrate) << 1) |
194                                                                 CPM_BRG_EN;
195
196         /* Make the first buffer the only buffer.
197         */
198         tbdf->cbd_sc |= BD_SC_WRAP;
199         rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
200
201         /* Initialize Tx/Rx parameters.
202         */
203 #ifdef SCC_CONSOLE
204         sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
205 #else
206         cp->cp_cpcr = mk_cr_cmd(CPM_CR_SMC1_PAGE, CPM_CR_SMC1_SBLOCK, 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
207         while (cp->cp_cpcr & CPM_CR_FLG);
208
209         /* Enable transmitter/receiver.
210         */
211         sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
212 #endif
213
214         /* This is ignored.
215         */
216         return 0;
217 }
218
219 int
220 serial_readbuf(u_char *cbuf)
221 {
222         volatile cbd_t          *rbdf;
223         volatile char           *buf;
224         volatile smc_uart_t     *up;
225         volatile scc_uart_t     *sup;
226         volatile immap_t        *ip;
227         int     i, nc;
228
229         ip = (immap_t *)IMAP_ADDR;
230
231 #ifdef SCC_CONSOLE
232         sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
233         rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase];
234 #else
235         up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
236         rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
237 #endif
238
239         /* Wait for character to show up.
240         */
241         buf = (char *)rbdf->cbd_bufaddr;
242         while (rbdf->cbd_sc & BD_SC_EMPTY);
243         nc = rbdf->cbd_datlen;
244         for (i=0; i<nc; i++)
245                 *cbuf++ = *buf++;
246         rbdf->cbd_sc |= BD_SC_EMPTY;
247
248         return(nc);
249 }
250
251 void
252 serial_putc(void *ignored, const char c)
253 {
254         volatile cbd_t          *tbdf;
255         volatile char           *buf;
256         volatile smc_uart_t     *up;
257         volatile scc_uart_t     *sup;
258         volatile immap_t        *ip;
259         extern bd_t             *board_info;
260
261         ip = (immap_t *)IMAP_ADDR;
262 #ifdef SCC_CONSOLE
263         sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
264         tbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_tbase];
265 #else
266         up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
267         tbdf = (cbd_t *)&ip->im_dprambase[up->smc_tbase];
268 #endif
269
270         /* Wait for last character to go.
271         */
272         buf = (char *)tbdf->cbd_bufaddr;
273         while (tbdf->cbd_sc & BD_SC_READY);
274
275         *buf = c;
276         tbdf->cbd_datlen = 1;
277         tbdf->cbd_sc |= BD_SC_READY;
278 }
279
280 char
281 serial_getc(void *ignored)
282 {
283         char    c;
284
285         if (cons_hold_cnt <= 0) {
286                 cons_hold_cnt = serial_readbuf(cons_hold);
287                 sgptr = cons_hold;
288         }
289         c = *sgptr++;
290         cons_hold_cnt--;
291
292         return(c);
293 }
294
295 int
296 serial_tstc(void *ignored)
297 {
298         volatile cbd_t          *rbdf;
299         volatile smc_uart_t     *up;
300         volatile scc_uart_t     *sup;
301         volatile immap_t        *ip;
302
303         ip = (immap_t *)IMAP_ADDR;
304 #ifdef SCC_CONSOLE
305         sup = (scc_uart_t *)&ip->im_dprambase[PROFF_SCC1 + ((SCC_CONSOLE-1) << 8)];
306         rbdf = (cbd_t *)&ip->im_dprambase[sup->scc_genscc.scc_rbase];
307 #else
308         up = (smc_uart_t *)&(ip->im_dprambase[PROFF_SMC1]);
309         rbdf = (cbd_t *)&ip->im_dprambase[up->smc_rbase];
310 #endif
311
312         return(!(rbdf->cbd_sc & BD_SC_EMPTY));
313 }