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