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