vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / boot / simple / mv64x60_tty.c
1 /*
2  * arch/ppc/boot/simple/mv64x60_tty.c
3  *
4  * Bootloader version of the embedded MPSC/UART driver for the Marvell 64x60.
5  * Note: Due to a GT64260A erratum, DMA will be used for UART input (via SDMA).
6  *
7  * Author: Mark A. Greer <mgreer@mvista.com>
8  *
9  * 2001 (c) MontaVista Software, Inc. This file is licensed under
10  * the terms of the GNU General Public License version 2. This program
11  * is licensed "as is" without any warranty of any kind, whether express
12  * or implied.
13  */
14
15 /* This code assumes that the data cache has been disabled (L1, L2, L3). */
16
17 #include <linux/config.h>
18 #include <linux/types.h>
19 #include <linux/serial_reg.h>
20 #include <asm/serial.h>
21 #include <asm/mv64x60_defs.h>
22 #include <mpsc_defs.h>
23
24 extern void udelay(long);
25 static void stop_dma(int chan);
26
27 static u32      mv64x60_base = CONFIG_MV64X60_NEW_BASE;
28
29 inline unsigned
30 mv64x60_in_le32(volatile unsigned *addr)
31 {
32         unsigned ret;
33
34         __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
35                                 "r" (addr), "m" (*addr));
36         return ret;
37 }
38
39 inline void
40 mv64x60_out_le32(volatile unsigned *addr, int val)
41 {
42         __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
43                                 "r" (val), "r" (addr));
44 }
45
46 #define MV64x60_REG_READ(offs)                                          \
47         (mv64x60_in_le32((volatile uint *)(mv64x60_base + (offs))))
48 #define MV64x60_REG_WRITE(offs, d)                                      \
49         (mv64x60_out_le32((volatile uint *)(mv64x60_base + (offs)), (int)(d)))
50
51
52 struct sdma_regs {
53         u32     sdc;
54         u32     sdcm;
55         u32     rx_desc;
56         u32     rx_buf_ptr;
57         u32     scrdp;
58         u32     tx_desc;
59         u32     sctdp;
60         u32     sftdp;
61 };
62
63 static struct sdma_regs sdma_regs[2];
64
65 #define SDMA_REGS_INIT(s, reg_base) {                   \
66         (s)->sdc        = (reg_base) + SDMA_SDC;        \
67         (s)->sdcm       = (reg_base) + SDMA_SDCM;       \
68         (s)->rx_desc    = (reg_base) + SDMA_RX_DESC;    \
69         (s)->rx_buf_ptr = (reg_base) + SDMA_RX_BUF_PTR; \
70         (s)->scrdp      = (reg_base) + SDMA_SCRDP;      \
71         (s)->tx_desc    = (reg_base) + SDMA_TX_DESC;    \
72         (s)->sctdp      = (reg_base) + SDMA_SCTDP;      \
73         (s)->sftdp      = (reg_base) + SDMA_SFTDP;      \
74 }
75
76 static u32      mpsc_base[2] = { MV64x60_MPSC_0_OFFSET, MV64x60_MPSC_1_OFFSET };
77
78 struct mv64x60_rx_desc {
79         u16     bufsize;
80         u16     bytecnt;
81         u32     cmd_stat;
82         u32     next_desc_ptr;
83         u32     buffer;
84 };
85
86 struct mv64x60_tx_desc {
87         u16     bytecnt;
88         u16     shadow;
89         u32     cmd_stat;
90         u32     next_desc_ptr;
91         u32     buffer;
92 };
93
94 #define MAX_RESET_WAIT  10000
95 #define MAX_TX_WAIT     10000
96
97 #define RX_NUM_DESC     2
98 #define TX_NUM_DESC     2
99
100 #define RX_BUF_SIZE     32
101 #define TX_BUF_SIZE     32
102
103 static struct mv64x60_rx_desc rd[2][RX_NUM_DESC] __attribute__ ((aligned(32)));
104 static struct mv64x60_tx_desc td[2][TX_NUM_DESC] __attribute__ ((aligned(32)));
105
106 static char rx_buf[2][RX_NUM_DESC * RX_BUF_SIZE] __attribute__ ((aligned(32)));
107 static char tx_buf[2][TX_NUM_DESC * TX_BUF_SIZE] __attribute__ ((aligned(32)));
108
109 static int cur_rd[2] = { 0, 0 };
110 static int cur_td[2] = { 0, 0 };
111
112 static char chan_initialized[2] = { 0, 0 };
113
114
115 #define RX_INIT_RDP(rdp) {                      \
116         (rdp)->bufsize = 2;                     \
117         (rdp)->bytecnt = 0;                     \
118         (rdp)->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |   \
119                 SDMA_DESC_CMDSTAT_O;    \
120 }
121
122 #ifdef CONFIG_MV64360
123 static u32 cpu2mem_tab[MV64x60_CPU2MEM_WINDOWS][2] = {
124                 { MV64x60_CPU2MEM_0_BASE, MV64x60_CPU2MEM_0_SIZE },
125                 { MV64x60_CPU2MEM_1_BASE, MV64x60_CPU2MEM_1_SIZE },
126                 { MV64x60_CPU2MEM_2_BASE, MV64x60_CPU2MEM_2_SIZE },
127                 { MV64x60_CPU2MEM_3_BASE, MV64x60_CPU2MEM_3_SIZE }
128 };
129
130 static u32 com2mem_tab[MV64x60_CPU2MEM_WINDOWS][2] = {
131                 { MV64360_MPSC2MEM_0_BASE, MV64360_MPSC2MEM_0_SIZE },
132                 { MV64360_MPSC2MEM_1_BASE, MV64360_MPSC2MEM_1_SIZE },
133                 { MV64360_MPSC2MEM_2_BASE, MV64360_MPSC2MEM_2_SIZE },
134                 { MV64360_MPSC2MEM_3_BASE, MV64360_MPSC2MEM_3_SIZE }
135 };
136
137 static u32 dram_selects[MV64x60_CPU2MEM_WINDOWS] = { 0xe, 0xd, 0xb, 0x7 };
138 #endif
139
140 unsigned long
141 serial_init(int chan, void *ignored)
142 {
143         u32             mpsc_routing_base, sdma_base, brg_bcr, cdv;
144         int             i;
145         extern long     mv64x60_console_baud;
146         extern long     mv64x60_mpsc_clk_src;
147         extern long     mv64x60_mpsc_clk_freq;
148
149         chan = (chan == 1); /* default to chan 0 if anything but 1 */
150
151         if (chan_initialized[chan])
152                 return chan;
153
154         chan_initialized[chan] = 1;
155
156         if (chan == 0) {
157                 sdma_base = MV64x60_SDMA_0_OFFSET;
158                 brg_bcr = MV64x60_BRG_0_OFFSET + BRG_BCR;
159                 SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_0_OFFSET);
160         }
161         else {
162                 sdma_base = MV64x60_SDMA_1_OFFSET;
163                 brg_bcr = MV64x60_BRG_1_OFFSET + BRG_BCR;
164                 SDMA_REGS_INIT(&sdma_regs[0], MV64x60_SDMA_1_OFFSET);
165         }
166
167         mpsc_routing_base = MV64x60_MPSC_ROUTING_OFFSET;
168
169         stop_dma(chan);
170
171         /* Set up ring buffers */
172         for (i=0; i<RX_NUM_DESC; i++) {
173                 RX_INIT_RDP(&rd[chan][i]);
174                 rd[chan][i].buffer = (u32)&rx_buf[chan][i * RX_BUF_SIZE];
175                 rd[chan][i].next_desc_ptr = (u32)&rd[chan][i+1];
176         }
177         rd[chan][RX_NUM_DESC - 1].next_desc_ptr = (u32)&rd[chan][0];
178
179         for (i=0; i<TX_NUM_DESC; i++) {
180                 td[chan][i].bytecnt = 0;
181                 td[chan][i].shadow = 0;
182                 td[chan][i].buffer = (u32)&tx_buf[chan][i * TX_BUF_SIZE];
183                 td[chan][i].cmd_stat = SDMA_DESC_CMDSTAT_F|SDMA_DESC_CMDSTAT_L;
184                 td[chan][i].next_desc_ptr = (u32)&td[chan][i+1];
185         }
186         td[chan][TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[chan][0];
187
188         /* Set MPSC Routing */
189         MV64x60_REG_WRITE(mpsc_routing_base + MPSC_MRR, 0x3ffffe38);
190
191 #ifdef CONFIG_GT64260
192         MV64x60_REG_WRITE(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
193 #else /* Must be MV64360 or MV64460 */
194         {
195         u32     enables, prot_bits, v;
196
197         /* Set up comm unit to memory mapping windows */
198         /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
199
200         enables = MV64x60_REG_READ(MV64360_CPU_BAR_ENABLE) & 0xf;
201         prot_bits = 0;
202
203         for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++) {
204                 if (!(enables & (1 << i))) {
205                         v = MV64x60_REG_READ(cpu2mem_tab[i][0]);
206                         v = ((v & 0xffff) << 16) | (dram_selects[i] << 8);
207                         MV64x60_REG_WRITE(com2mem_tab[i][0], v);
208
209                         v = MV64x60_REG_READ(cpu2mem_tab[i][1]);
210                         v = (v & 0xffff) << 16;
211                         MV64x60_REG_WRITE(com2mem_tab[i][1], v);
212
213                         prot_bits |= (0x3 << (i << 1)); /* r/w access */
214                 }
215         }
216
217         MV64x60_REG_WRITE(MV64360_MPSC_0_REMAP, 0);
218         MV64x60_REG_WRITE(MV64360_MPSC_1_REMAP, 0);
219         MV64x60_REG_WRITE(MV64360_MPSC2MEM_ACC_PROT_0, prot_bits);
220         MV64x60_REG_WRITE(MV64360_MPSC2MEM_ACC_PROT_1, prot_bits);
221         MV64x60_REG_WRITE(MV64360_MPSC2MEM_BAR_ENABLE, enables);
222         }
223 #endif
224
225         /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
226         MV64x60_REG_WRITE(mpsc_routing_base + MPSC_RCRR, 0x00000100);
227         MV64x60_REG_WRITE(mpsc_routing_base + MPSC_TCRR, 0x00000100);
228
229         /* clear pending interrupts */
230         MV64x60_REG_WRITE(MV64x60_SDMA_INTR_OFFSET + SDMA_INTR_MASK, 0);
231
232         MV64x60_REG_WRITE(SDMA_SCRDP + sdma_base, &rd[chan][0]);
233         MV64x60_REG_WRITE(SDMA_SCTDP + sdma_base, &td[chan][TX_NUM_DESC - 1]);
234         MV64x60_REG_WRITE(SDMA_SFTDP + sdma_base, &td[chan][TX_NUM_DESC - 1]);
235
236         MV64x60_REG_WRITE(SDMA_SDC + sdma_base,
237                 SDMA_SDC_RFT | SDMA_SDC_SFM | SDMA_SDC_BLMR | SDMA_SDC_BLMT |
238                 (3 << 12));
239
240         cdv = ((mv64x60_mpsc_clk_freq/(32*mv64x60_console_baud))-1);
241         MV64x60_REG_WRITE(brg_bcr,
242                 ((mv64x60_mpsc_clk_src << 18) | (1 << 16) | cdv));
243
244         /* Put MPSC into UART mode, no null modem, 16x clock mode */
245         MV64x60_REG_WRITE(MPSC_MMCRL + mpsc_base[chan], 0x000004c4);
246         MV64x60_REG_WRITE(MPSC_MMCRH + mpsc_base[chan], 0x04400400);
247
248         MV64x60_REG_WRITE(MPSC_CHR_1 + mpsc_base[chan], 0);
249         MV64x60_REG_WRITE(MPSC_CHR_9 + mpsc_base[chan], 0);
250         MV64x60_REG_WRITE(MPSC_CHR_10 + mpsc_base[chan], 0);
251         MV64x60_REG_WRITE(MPSC_CHR_3 + mpsc_base[chan], 4);
252         MV64x60_REG_WRITE(MPSC_CHR_4 + mpsc_base[chan], 0);
253         MV64x60_REG_WRITE(MPSC_CHR_5 + mpsc_base[chan], 0);
254         MV64x60_REG_WRITE(MPSC_CHR_6 + mpsc_base[chan], 0);
255         MV64x60_REG_WRITE(MPSC_CHR_7 + mpsc_base[chan], 0);
256         MV64x60_REG_WRITE(MPSC_CHR_8 + mpsc_base[chan], 0);
257
258         /* 8 data bits, 1 stop bit */
259         MV64x60_REG_WRITE(MPSC_MPCR + mpsc_base[chan], (3 << 12));
260         MV64x60_REG_WRITE(SDMA_SDCM + sdma_base, SDMA_SDCM_ERD);
261         MV64x60_REG_WRITE(MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_EH);
262
263         udelay(100);
264
265         return chan;
266 }
267
268 static void
269 stop_dma(int chan)
270 {
271         int     i;
272
273         /* Abort MPSC Rx (aborting Tx messes things up) */
274         MV64x60_REG_WRITE(MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_RA);
275
276         /* Abort SDMA Rx, Tx */
277         MV64x60_REG_WRITE(sdma_regs[chan].sdcm, SDMA_SDCM_AR | SDMA_SDCM_STD);
278
279         for (i=0; i<MAX_RESET_WAIT; i++) {
280                 if ((MV64x60_REG_READ(sdma_regs[chan].sdcm) &
281                                 (SDMA_SDCM_AR | SDMA_SDCM_AT)) == 0)
282                         break;
283
284                 udelay(100);
285         }
286
287         return;
288 }
289
290 static int
291 wait_for_ownership(int chan)
292 {
293         int     i;
294
295         for (i=0; i<MAX_TX_WAIT; i++) {
296                 if ((MV64x60_REG_READ(sdma_regs[chan].sdcm) &
297                                 SDMA_SDCM_TXD) == 0)
298                         break;
299
300                 udelay(1000);
301         }
302
303         return (i < MAX_TX_WAIT);
304 }
305
306 void
307 serial_putc(unsigned long com_port, unsigned char c)
308 {
309         struct mv64x60_tx_desc  *tdp;
310
311         if (wait_for_ownership(com_port) == 0)
312                 return;
313
314         tdp = &td[com_port][cur_td[com_port]];
315         if (++cur_td[com_port] >= TX_NUM_DESC)
316                 cur_td[com_port] = 0;
317
318         *(unchar *)(tdp->buffer ^ 7) = c;
319         tdp->bytecnt = 1;
320         tdp->shadow = 1;
321         tdp->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |
322                 SDMA_DESC_CMDSTAT_O;
323
324         MV64x60_REG_WRITE(sdma_regs[com_port].sctdp, tdp);
325         MV64x60_REG_WRITE(sdma_regs[com_port].sftdp, tdp);
326         MV64x60_REG_WRITE(sdma_regs[com_port].sdcm,
327                 MV64x60_REG_READ(sdma_regs[com_port].sdcm) | SDMA_SDCM_TXD);
328
329         return;
330 }
331
332 unsigned char
333 serial_getc(unsigned long com_port)
334 {
335         struct mv64x60_rx_desc  *rdp;
336         unchar                  c = '\0';
337
338         rdp = &rd[com_port][cur_rd[com_port]];
339
340         if ((rdp->cmd_stat & (SDMA_DESC_CMDSTAT_O|SDMA_DESC_CMDSTAT_ES)) == 0) {
341                 c = *(unchar *)(rdp->buffer ^ 7);
342                 RX_INIT_RDP(rdp);
343                 if (++cur_rd[com_port] >= RX_NUM_DESC)
344                         cur_rd[com_port] = 0;
345         }
346
347         return c;
348 }
349
350 int
351 serial_tstc(unsigned long com_port)
352 {
353         struct mv64x60_rx_desc  *rdp;
354         int                     loop_count = 0;
355         int                     rc = 0;
356
357         rdp = &rd[com_port][cur_rd[com_port]];
358
359         /* Go thru rcv desc's until empty looking for one with data (no error)*/
360         while (((rdp->cmd_stat & SDMA_DESC_CMDSTAT_O) == 0) &&
361                 (loop_count++ < RX_NUM_DESC)) {
362
363                 /* If there was an error, reinit the desc & continue */
364                 if ((rdp->cmd_stat & SDMA_DESC_CMDSTAT_ES) != 0) {
365                         RX_INIT_RDP(rdp);
366                         if (++cur_rd[com_port] >= RX_NUM_DESC)
367                                 cur_rd[com_port] = 0;
368                         rdp = (struct mv64x60_rx_desc *)rdp->next_desc_ptr;
369                 }
370                 else {
371                         rc = 1;
372                         break;
373                 }
374         }
375
376         return rc;
377 }
378
379 void
380 serial_close(unsigned long com_port)
381 {
382         stop_dma(com_port);
383         return;
384 }