2 * arch/ppc/boot/simple/mv64x60_tty.c
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).
7 * Author: Mark A. Greer <mgreer@mvista.com>
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
15 /* This code assumes that the data cache has been disabled (L1, L2, L3). */
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>
24 extern void udelay(long);
25 static void stop_dma(int chan);
27 static u32 mv64x60_base = CONFIG_MV64X60_NEW_BASE;
30 mv64x60_in_le32(volatile unsigned *addr)
34 __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
35 "r" (addr), "m" (*addr));
40 mv64x60_out_le32(volatile unsigned *addr, int val)
42 __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
43 "r" (val), "r" (addr));
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)))
63 static struct sdma_regs sdma_regs[2];
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; \
76 static u32 mpsc_base[2] = { MV64x60_MPSC_0_OFFSET, MV64x60_MPSC_1_OFFSET };
78 struct mv64x60_rx_desc {
86 struct mv64x60_tx_desc {
94 #define MAX_RESET_WAIT 10000
95 #define MAX_TX_WAIT 10000
100 #define RX_BUF_SIZE 32
101 #define TX_BUF_SIZE 32
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)));
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)));
109 static int cur_rd[2] = { 0, 0 };
110 static int cur_td[2] = { 0, 0 };
112 static char chan_initialized[2] = { 0, 0 };
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; \
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 }
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 }
137 static u32 dram_selects[MV64x60_CPU2MEM_WINDOWS] = { 0xe, 0xd, 0xb, 0x7 };
141 serial_init(int chan, void *ignored)
143 u32 mpsc_routing_base, sdma_base, brg_bcr, cdv;
145 extern long mv64x60_console_baud;
146 extern long mv64x60_mpsc_clk_src;
147 extern long mv64x60_mpsc_clk_freq;
149 chan = (chan == 1); /* default to chan 0 if anything but 1 */
151 if (chan_initialized[chan])
154 chan_initialized[chan] = 1;
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);
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);
167 mpsc_routing_base = MV64x60_MPSC_ROUTING_OFFSET;
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];
177 rd[chan][RX_NUM_DESC - 1].next_desc_ptr = (u32)&rd[chan][0];
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];
186 td[chan][TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[chan][0];
188 /* Set MPSC Routing */
189 MV64x60_REG_WRITE(mpsc_routing_base + MPSC_MRR, 0x3ffffe38);
191 #ifdef CONFIG_GT64260
192 MV64x60_REG_WRITE(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
193 #else /* Must be MV64360 or MV64460 */
195 u32 enables, prot_bits, v;
197 /* Set up comm unit to memory mapping windows */
198 /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
200 enables = MV64x60_REG_READ(MV64360_CPU_BAR_ENABLE) & 0xf;
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);
209 v = MV64x60_REG_READ(cpu2mem_tab[i][1]);
210 v = (v & 0xffff) << 16;
211 MV64x60_REG_WRITE(com2mem_tab[i][1], v);
213 prot_bits |= (0x3 << (i << 1)); /* r/w access */
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);
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);
229 /* clear pending interrupts */
230 MV64x60_REG_WRITE(MV64x60_SDMA_INTR_OFFSET + SDMA_INTR_MASK, 0);
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]);
236 MV64x60_REG_WRITE(SDMA_SDC + sdma_base,
237 SDMA_SDC_RFT | SDMA_SDC_SFM | SDMA_SDC_BLMR | SDMA_SDC_BLMT |
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));
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);
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);
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);
273 /* Abort MPSC Rx (aborting Tx messes things up) */
274 MV64x60_REG_WRITE(MPSC_CHR_2 + mpsc_base[chan], MPSC_CHR_2_RA);
276 /* Abort SDMA Rx, Tx */
277 MV64x60_REG_WRITE(sdma_regs[chan].sdcm, SDMA_SDCM_AR | SDMA_SDCM_STD);
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)
291 wait_for_ownership(int chan)
295 for (i=0; i<MAX_TX_WAIT; i++) {
296 if ((MV64x60_REG_READ(sdma_regs[chan].sdcm) &
303 return (i < MAX_TX_WAIT);
307 serial_putc(unsigned long com_port, unsigned char c)
309 struct mv64x60_tx_desc *tdp;
311 if (wait_for_ownership(com_port) == 0)
314 tdp = &td[com_port][cur_td[com_port]];
315 if (++cur_td[com_port] >= TX_NUM_DESC)
316 cur_td[com_port] = 0;
318 *(unchar *)(tdp->buffer ^ 7) = c;
321 tdp->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F |
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);
333 serial_getc(unsigned long com_port)
335 struct mv64x60_rx_desc *rdp;
338 rdp = &rd[com_port][cur_rd[com_port]];
340 if ((rdp->cmd_stat & (SDMA_DESC_CMDSTAT_O|SDMA_DESC_CMDSTAT_ES)) == 0) {
341 c = *(unchar *)(rdp->buffer ^ 7);
343 if (++cur_rd[com_port] >= RX_NUM_DESC)
344 cur_rd[com_port] = 0;
351 serial_tstc(unsigned long com_port)
353 struct mv64x60_rx_desc *rdp;
357 rdp = &rd[com_port][cur_rd[com_port]];
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)) {
363 /* If there was an error, reinit the desc & continue */
364 if ((rdp->cmd_stat & SDMA_DESC_CMDSTAT_ES) != 0) {
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;
380 serial_close(unsigned long com_port)