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>
22 #include <asm/mv64x60_defs.h>
23 #include <mpsc_defs.h>
25 u32 mv64x60_console_baud
= 9600;
26 u32 mv64x60_mpsc_clk_src
= 8; /* TCLK */
27 u32 mv64x60_mpsc_clk_freq
= 100000000;
29 extern void udelay(long);
30 static void stop_dma(int chan
);
32 static void __iomem
*mv64x60_base
= (void __iomem
*)CONFIG_MV64X60_NEW_BASE
;
45 static struct sdma_regs sdma_regs
[2];
47 #define SDMA_REGS_INIT(s, reg_base) { \
48 (s)->sdc = (reg_base) + SDMA_SDC; \
49 (s)->sdcm = (reg_base) + SDMA_SDCM; \
50 (s)->rx_desc = (reg_base) + SDMA_RX_DESC; \
51 (s)->rx_buf_ptr = (reg_base) + SDMA_RX_BUF_PTR; \
52 (s)->scrdp = (reg_base) + SDMA_SCRDP; \
53 (s)->tx_desc = (reg_base) + SDMA_TX_DESC; \
54 (s)->sctdp = (reg_base) + SDMA_SCTDP; \
55 (s)->sftdp = (reg_base) + SDMA_SFTDP; \
58 static u32 mpsc_base
[2] = { MV64x60_MPSC_0_OFFSET
, MV64x60_MPSC_1_OFFSET
};
60 struct mv64x60_rx_desc
{
68 struct mv64x60_tx_desc
{
76 #define MAX_RESET_WAIT 10000
77 #define MAX_TX_WAIT 10000
82 #define RX_BUF_SIZE 32
83 #define TX_BUF_SIZE 32
85 static struct mv64x60_rx_desc rd
[2][RX_NUM_DESC
] __attribute__ ((aligned(32)));
86 static struct mv64x60_tx_desc td
[2][TX_NUM_DESC
] __attribute__ ((aligned(32)));
88 static char rx_buf
[2][RX_NUM_DESC
* RX_BUF_SIZE
] __attribute__ ((aligned(32)));
89 static char tx_buf
[2][TX_NUM_DESC
* TX_BUF_SIZE
] __attribute__ ((aligned(32)));
91 static int cur_rd
[2] = { 0, 0 };
92 static int cur_td
[2] = { 0, 0 };
94 static char chan_initialized
[2] = { 0, 0 };
97 #define RX_INIT_RDP(rdp) { \
100 (rdp)->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F | \
101 SDMA_DESC_CMDSTAT_O; \
104 #ifdef CONFIG_MV64360
105 static u32 cpu2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
106 { MV64x60_CPU2MEM_0_BASE
, MV64x60_CPU2MEM_0_SIZE
},
107 { MV64x60_CPU2MEM_1_BASE
, MV64x60_CPU2MEM_1_SIZE
},
108 { MV64x60_CPU2MEM_2_BASE
, MV64x60_CPU2MEM_2_SIZE
},
109 { MV64x60_CPU2MEM_3_BASE
, MV64x60_CPU2MEM_3_SIZE
}
112 static u32 com2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
113 { MV64360_MPSC2MEM_0_BASE
, MV64360_MPSC2MEM_0_SIZE
},
114 { MV64360_MPSC2MEM_1_BASE
, MV64360_MPSC2MEM_1_SIZE
},
115 { MV64360_MPSC2MEM_2_BASE
, MV64360_MPSC2MEM_2_SIZE
},
116 { MV64360_MPSC2MEM_3_BASE
, MV64360_MPSC2MEM_3_SIZE
}
119 static u32 dram_selects
[MV64x60_CPU2MEM_WINDOWS
] = { 0xe, 0xd, 0xb, 0x7 };
123 serial_init(int chan
, void *ignored
)
125 u32 mpsc_routing_base
, sdma_base
, brg_bcr
, cdv
;
128 chan
= (chan
== 1); /* default to chan 0 if anything but 1 */
130 if (chan_initialized
[chan
])
133 chan_initialized
[chan
] = 1;
136 sdma_base
= MV64x60_SDMA_0_OFFSET
;
137 brg_bcr
= MV64x60_BRG_0_OFFSET
+ BRG_BCR
;
138 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_0_OFFSET
);
140 sdma_base
= MV64x60_SDMA_1_OFFSET
;
141 brg_bcr
= MV64x60_BRG_1_OFFSET
+ BRG_BCR
;
142 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_1_OFFSET
);
145 mpsc_routing_base
= MV64x60_MPSC_ROUTING_OFFSET
;
149 /* Set up ring buffers */
150 for (i
=0; i
<RX_NUM_DESC
; i
++) {
151 RX_INIT_RDP(&rd
[chan
][i
]);
152 rd
[chan
][i
].buffer
= (u32
)&rx_buf
[chan
][i
* RX_BUF_SIZE
];
153 rd
[chan
][i
].next_desc_ptr
= (u32
)&rd
[chan
][i
+1];
155 rd
[chan
][RX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&rd
[chan
][0];
157 for (i
=0; i
<TX_NUM_DESC
; i
++) {
158 td
[chan
][i
].bytecnt
= 0;
159 td
[chan
][i
].shadow
= 0;
160 td
[chan
][i
].buffer
= (u32
)&tx_buf
[chan
][i
* TX_BUF_SIZE
];
161 td
[chan
][i
].cmd_stat
= SDMA_DESC_CMDSTAT_F
|SDMA_DESC_CMDSTAT_L
;
162 td
[chan
][i
].next_desc_ptr
= (u32
)&td
[chan
][i
+1];
164 td
[chan
][TX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&td
[chan
][0];
166 /* Set MPSC Routing */
167 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_MRR
, 0x3ffffe38);
169 #ifdef CONFIG_GT64260
170 out_le32(mv64x60_base
+ GT64260_MPP_SERIAL_PORTS_MULTIPLEX
, 0x00001102);
171 #else /* Must be MV64360 or MV64460 */
173 u32 enables
, prot_bits
, v
;
175 /* Set up comm unit to memory mapping windows */
176 /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
178 enables
= in_le32(mv64x60_base
+ MV64360_CPU_BAR_ENABLE
) & 0xf;
181 for (i
=0; i
<MV64x60_CPU2MEM_WINDOWS
; i
++) {
182 if (!(enables
& (1 << i
))) {
183 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][0]);
184 v
= ((v
& 0xffff) << 16) | (dram_selects
[i
] << 8);
185 out_le32(mv64x60_base
+ com2mem_tab
[i
][0], v
);
187 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][1]);
188 v
= (v
& 0xffff) << 16;
189 out_le32(mv64x60_base
+ com2mem_tab
[i
][1], v
);
191 prot_bits
|= (0x3 << (i
<< 1)); /* r/w access */
195 out_le32(mv64x60_base
+ MV64360_MPSC_0_REMAP
, 0);
196 out_le32(mv64x60_base
+ MV64360_MPSC_1_REMAP
, 0);
197 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_0
, prot_bits
);
198 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_1
, prot_bits
);
199 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_BAR_ENABLE
, enables
);
203 /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
204 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_RCRR
, 0x00000100);
205 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_TCRR
, 0x00000100);
207 /* clear pending interrupts */
208 out_le32(mv64x60_base
+ MV64x60_SDMA_INTR_OFFSET
+ SDMA_INTR_MASK
, 0);
210 out_le32(mv64x60_base
+ SDMA_SCRDP
+ sdma_base
, (int)&rd
[chan
][0]);
211 out_le32(mv64x60_base
+ SDMA_SCTDP
+ sdma_base
,
212 (int)&td
[chan
][TX_NUM_DESC
- 1]);
213 out_le32(mv64x60_base
+ SDMA_SFTDP
+ sdma_base
,
214 (int)&td
[chan
][TX_NUM_DESC
- 1]);
216 out_le32(mv64x60_base
+ SDMA_SDC
+ sdma_base
,
217 SDMA_SDC_RFT
| SDMA_SDC_SFM
| SDMA_SDC_BLMR
| SDMA_SDC_BLMT
|
220 cdv
= ((mv64x60_mpsc_clk_freq
/(32*mv64x60_console_baud
))-1);
221 out_le32(mv64x60_base
+ brg_bcr
,
222 ((mv64x60_mpsc_clk_src
<< 18) | (1 << 16) | cdv
));
224 /* Put MPSC into UART mode, no null modem, 16x clock mode */
225 out_le32(mv64x60_base
+ MPSC_MMCRL
+ mpsc_base
[chan
], 0x000004c4);
226 out_le32(mv64x60_base
+ MPSC_MMCRH
+ mpsc_base
[chan
], 0x04400400);
228 out_le32(mv64x60_base
+ MPSC_CHR_1
+ mpsc_base
[chan
], 0);
229 out_le32(mv64x60_base
+ MPSC_CHR_9
+ mpsc_base
[chan
], 0);
230 out_le32(mv64x60_base
+ MPSC_CHR_10
+ mpsc_base
[chan
], 0);
231 out_le32(mv64x60_base
+ MPSC_CHR_3
+ mpsc_base
[chan
], 4);
232 out_le32(mv64x60_base
+ MPSC_CHR_4
+ mpsc_base
[chan
], 0);
233 out_le32(mv64x60_base
+ MPSC_CHR_5
+ mpsc_base
[chan
], 0);
234 out_le32(mv64x60_base
+ MPSC_CHR_6
+ mpsc_base
[chan
], 0);
235 out_le32(mv64x60_base
+ MPSC_CHR_7
+ mpsc_base
[chan
], 0);
236 out_le32(mv64x60_base
+ MPSC_CHR_8
+ mpsc_base
[chan
], 0);
238 /* 8 data bits, 1 stop bit */
239 out_le32(mv64x60_base
+ MPSC_MPCR
+ mpsc_base
[chan
], (3 << 12));
240 out_le32(mv64x60_base
+ SDMA_SDCM
+ sdma_base
, SDMA_SDCM_ERD
);
241 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_EH
);
253 /* Abort MPSC Rx (aborting Tx messes things up) */
254 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_RA
);
256 /* Abort SDMA Rx, Tx */
257 out_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
,
258 SDMA_SDCM_AR
| SDMA_SDCM_STD
);
260 for (i
=0; i
<MAX_RESET_WAIT
; i
++) {
261 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
262 (SDMA_SDCM_AR
| SDMA_SDCM_AT
)) == 0)
270 wait_for_ownership(int chan
)
274 for (i
=0; i
<MAX_TX_WAIT
; i
++) {
275 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
282 return (i
< MAX_TX_WAIT
);
286 serial_putc(unsigned long com_port
, unsigned char c
)
288 struct mv64x60_tx_desc
*tdp
;
290 if (wait_for_ownership(com_port
) == 0)
293 tdp
= &td
[com_port
][cur_td
[com_port
]];
294 if (++cur_td
[com_port
] >= TX_NUM_DESC
)
295 cur_td
[com_port
] = 0;
297 *(unchar
*)(tdp
->buffer
^ 7) = c
;
300 tdp
->cmd_stat
= SDMA_DESC_CMDSTAT_L
| SDMA_DESC_CMDSTAT_F
|
303 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sctdp
, (int)tdp
);
304 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sftdp
, (int)tdp
);
305 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
,
306 in_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
) |
311 serial_getc(unsigned long com_port
)
313 struct mv64x60_rx_desc
*rdp
;
316 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
318 if ((rdp
->cmd_stat
& (SDMA_DESC_CMDSTAT_O
|SDMA_DESC_CMDSTAT_ES
)) == 0) {
319 c
= *(unchar
*)(rdp
->buffer
^ 7);
321 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
322 cur_rd
[com_port
] = 0;
329 serial_tstc(unsigned long com_port
)
331 struct mv64x60_rx_desc
*rdp
;
335 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
337 /* Go thru rcv desc's until empty looking for one with data (no error)*/
338 while (((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_O
) == 0) &&
339 (loop_count
++ < RX_NUM_DESC
)) {
341 /* If there was an error, reinit the desc & continue */
342 if ((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_ES
) != 0) {
344 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
345 cur_rd
[com_port
] = 0;
346 rdp
= (struct mv64x60_rx_desc
*)rdp
->next_desc_ptr
;
357 serial_close(unsigned long com_port
)