2 * Bootloader version of the embedded MPSC/UART driver for the Marvell 64x60.
3 * Note: Due to a GT64260A erratum, DMA will be used for UART input (via SDMA).
5 * Author: Mark A. Greer <mgreer@mvista.com>
7 * 2001 (c) MontaVista Software, Inc. This file is licensed under
8 * the terms of the GNU General Public License version 2. This program
9 * is licensed "as is" without any warranty of any kind, whether express
13 /* This code assumes that the data cache has been disabled (L1, L2, L3). */
15 #include <linux/types.h>
16 #include <linux/serial_reg.h>
17 #include <asm/serial.h>
19 #include <asm/mv64x60_defs.h>
20 #include <mpsc_defs.h>
23 #include <platforms/ev64360.h>
24 u32 mv64x60_console_baud
= EV64360_DEFAULT_BAUD
;
25 u32 mv64x60_mpsc_clk_src
= EV64360_MPSC_CLK_SRC
; /* TCLK */
26 u32 mv64x60_mpsc_clk_freq
= EV64360_MPSC_CLK_FREQ
;
28 u32 mv64x60_console_baud
= 9600;
29 u32 mv64x60_mpsc_clk_src
= 8; /* TCLK */
30 u32 mv64x60_mpsc_clk_freq
= 100000000;
33 extern void udelay(long);
34 static void stop_dma(int chan
);
36 static void __iomem
*mv64x60_base
= (void __iomem
*)CONFIG_MV64X60_NEW_BASE
;
49 static struct sdma_regs sdma_regs
[2];
51 #define SDMA_REGS_INIT(s, reg_base) { \
52 (s)->sdc = (reg_base) + SDMA_SDC; \
53 (s)->sdcm = (reg_base) + SDMA_SDCM; \
54 (s)->rx_desc = (reg_base) + SDMA_RX_DESC; \
55 (s)->rx_buf_ptr = (reg_base) + SDMA_RX_BUF_PTR; \
56 (s)->scrdp = (reg_base) + SDMA_SCRDP; \
57 (s)->tx_desc = (reg_base) + SDMA_TX_DESC; \
58 (s)->sctdp = (reg_base) + SDMA_SCTDP; \
59 (s)->sftdp = (reg_base) + SDMA_SFTDP; \
62 static u32 mpsc_base
[2] = { MV64x60_MPSC_0_OFFSET
, MV64x60_MPSC_1_OFFSET
};
64 struct mv64x60_rx_desc
{
72 struct mv64x60_tx_desc
{
80 #define MAX_RESET_WAIT 10000
81 #define MAX_TX_WAIT 10000
86 #define RX_BUF_SIZE 32
87 #define TX_BUF_SIZE 32
89 static struct mv64x60_rx_desc rd
[2][RX_NUM_DESC
] __attribute__ ((aligned(32)));
90 static struct mv64x60_tx_desc td
[2][TX_NUM_DESC
] __attribute__ ((aligned(32)));
92 static char rx_buf
[2][RX_NUM_DESC
* RX_BUF_SIZE
] __attribute__ ((aligned(32)));
93 static char tx_buf
[2][TX_NUM_DESC
* TX_BUF_SIZE
] __attribute__ ((aligned(32)));
95 static int cur_rd
[2] = { 0, 0 };
96 static int cur_td
[2] = { 0, 0 };
98 static char chan_initialized
[2] = { 0, 0 };
101 #define RX_INIT_RDP(rdp) { \
102 (rdp)->bufsize = 2; \
103 (rdp)->bytecnt = 0; \
104 (rdp)->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F | \
105 SDMA_DESC_CMDSTAT_O; \
108 #ifdef CONFIG_MV64360
109 static u32 cpu2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
110 { MV64x60_CPU2MEM_0_BASE
, MV64x60_CPU2MEM_0_SIZE
},
111 { MV64x60_CPU2MEM_1_BASE
, MV64x60_CPU2MEM_1_SIZE
},
112 { MV64x60_CPU2MEM_2_BASE
, MV64x60_CPU2MEM_2_SIZE
},
113 { MV64x60_CPU2MEM_3_BASE
, MV64x60_CPU2MEM_3_SIZE
}
116 static u32 com2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
117 { MV64360_MPSC2MEM_0_BASE
, MV64360_MPSC2MEM_0_SIZE
},
118 { MV64360_MPSC2MEM_1_BASE
, MV64360_MPSC2MEM_1_SIZE
},
119 { MV64360_MPSC2MEM_2_BASE
, MV64360_MPSC2MEM_2_SIZE
},
120 { MV64360_MPSC2MEM_3_BASE
, MV64360_MPSC2MEM_3_SIZE
}
123 static u32 dram_selects
[MV64x60_CPU2MEM_WINDOWS
] = { 0xe, 0xd, 0xb, 0x7 };
127 serial_init(int chan
, void *ignored
)
129 u32 mpsc_routing_base
, sdma_base
, brg_bcr
, cdv
;
132 chan
= (chan
== 1); /* default to chan 0 if anything but 1 */
134 if (chan_initialized
[chan
])
137 chan_initialized
[chan
] = 1;
140 sdma_base
= MV64x60_SDMA_0_OFFSET
;
141 brg_bcr
= MV64x60_BRG_0_OFFSET
+ BRG_BCR
;
142 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_0_OFFSET
);
144 sdma_base
= MV64x60_SDMA_1_OFFSET
;
145 brg_bcr
= MV64x60_BRG_1_OFFSET
+ BRG_BCR
;
146 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_1_OFFSET
);
149 mpsc_routing_base
= MV64x60_MPSC_ROUTING_OFFSET
;
153 /* Set up ring buffers */
154 for (i
=0; i
<RX_NUM_DESC
; i
++) {
155 RX_INIT_RDP(&rd
[chan
][i
]);
156 rd
[chan
][i
].buffer
= (u32
)&rx_buf
[chan
][i
* RX_BUF_SIZE
];
157 rd
[chan
][i
].next_desc_ptr
= (u32
)&rd
[chan
][i
+1];
159 rd
[chan
][RX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&rd
[chan
][0];
161 for (i
=0; i
<TX_NUM_DESC
; i
++) {
162 td
[chan
][i
].bytecnt
= 0;
163 td
[chan
][i
].shadow
= 0;
164 td
[chan
][i
].buffer
= (u32
)&tx_buf
[chan
][i
* TX_BUF_SIZE
];
165 td
[chan
][i
].cmd_stat
= SDMA_DESC_CMDSTAT_F
|SDMA_DESC_CMDSTAT_L
;
166 td
[chan
][i
].next_desc_ptr
= (u32
)&td
[chan
][i
+1];
168 td
[chan
][TX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&td
[chan
][0];
170 /* Set MPSC Routing */
171 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_MRR
, 0x3ffffe38);
173 #ifdef CONFIG_GT64260
174 out_le32(mv64x60_base
+ GT64260_MPP_SERIAL_PORTS_MULTIPLEX
, 0x00001102);
175 #else /* Must be MV64360 or MV64460 */
177 u32 enables
, prot_bits
, v
;
179 /* Set up comm unit to memory mapping windows */
180 /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
182 enables
= in_le32(mv64x60_base
+ MV64360_CPU_BAR_ENABLE
) & 0xf;
185 for (i
=0; i
<MV64x60_CPU2MEM_WINDOWS
; i
++) {
186 if (!(enables
& (1 << i
))) {
187 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][0]);
188 v
= ((v
& 0xffff) << 16) | (dram_selects
[i
] << 8);
189 out_le32(mv64x60_base
+ com2mem_tab
[i
][0], v
);
191 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][1]);
192 v
= (v
& 0xffff) << 16;
193 out_le32(mv64x60_base
+ com2mem_tab
[i
][1], v
);
195 prot_bits
|= (0x3 << (i
<< 1)); /* r/w access */
199 out_le32(mv64x60_base
+ MV64360_MPSC_0_REMAP
, 0);
200 out_le32(mv64x60_base
+ MV64360_MPSC_1_REMAP
, 0);
201 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_0
, prot_bits
);
202 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_1
, prot_bits
);
203 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_BAR_ENABLE
, enables
);
207 /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
208 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_RCRR
, 0x00000100);
209 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_TCRR
, 0x00000100);
211 /* clear pending interrupts */
212 out_le32(mv64x60_base
+ MV64x60_SDMA_INTR_OFFSET
+ SDMA_INTR_MASK
, 0);
214 out_le32(mv64x60_base
+ SDMA_SCRDP
+ sdma_base
, (int)&rd
[chan
][0]);
215 out_le32(mv64x60_base
+ SDMA_SCTDP
+ sdma_base
,
216 (int)&td
[chan
][TX_NUM_DESC
- 1]);
217 out_le32(mv64x60_base
+ SDMA_SFTDP
+ sdma_base
,
218 (int)&td
[chan
][TX_NUM_DESC
- 1]);
220 out_le32(mv64x60_base
+ SDMA_SDC
+ sdma_base
,
221 SDMA_SDC_RFT
| SDMA_SDC_SFM
| SDMA_SDC_BLMR
| SDMA_SDC_BLMT
|
224 cdv
= ((mv64x60_mpsc_clk_freq
/(32*mv64x60_console_baud
))-1);
225 out_le32(mv64x60_base
+ brg_bcr
,
226 ((mv64x60_mpsc_clk_src
<< 18) | (1 << 16) | cdv
));
228 /* Put MPSC into UART mode, no null modem, 16x clock mode */
229 out_le32(mv64x60_base
+ MPSC_MMCRL
+ mpsc_base
[chan
], 0x000004c4);
230 out_le32(mv64x60_base
+ MPSC_MMCRH
+ mpsc_base
[chan
], 0x04400400);
232 out_le32(mv64x60_base
+ MPSC_CHR_1
+ mpsc_base
[chan
], 0);
233 out_le32(mv64x60_base
+ MPSC_CHR_9
+ mpsc_base
[chan
], 0);
234 out_le32(mv64x60_base
+ MPSC_CHR_10
+ mpsc_base
[chan
], 0);
235 out_le32(mv64x60_base
+ MPSC_CHR_3
+ mpsc_base
[chan
], 4);
236 out_le32(mv64x60_base
+ MPSC_CHR_4
+ mpsc_base
[chan
], 0);
237 out_le32(mv64x60_base
+ MPSC_CHR_5
+ mpsc_base
[chan
], 0);
238 out_le32(mv64x60_base
+ MPSC_CHR_6
+ mpsc_base
[chan
], 0);
239 out_le32(mv64x60_base
+ MPSC_CHR_7
+ mpsc_base
[chan
], 0);
240 out_le32(mv64x60_base
+ MPSC_CHR_8
+ mpsc_base
[chan
], 0);
242 /* 8 data bits, 1 stop bit */
243 out_le32(mv64x60_base
+ MPSC_MPCR
+ mpsc_base
[chan
], (3 << 12));
244 out_le32(mv64x60_base
+ SDMA_SDCM
+ sdma_base
, SDMA_SDCM_ERD
);
245 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_EH
);
257 /* Abort MPSC Rx (aborting Tx messes things up) */
258 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_RA
);
260 /* Abort SDMA Rx, Tx */
261 out_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
,
262 SDMA_SDCM_AR
| SDMA_SDCM_STD
);
264 for (i
=0; i
<MAX_RESET_WAIT
; i
++) {
265 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
266 (SDMA_SDCM_AR
| SDMA_SDCM_AT
)) == 0)
274 wait_for_ownership(int chan
)
278 for (i
=0; i
<MAX_TX_WAIT
; i
++) {
279 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
286 return (i
< MAX_TX_WAIT
);
290 serial_putc(unsigned long com_port
, unsigned char c
)
292 struct mv64x60_tx_desc
*tdp
;
294 if (wait_for_ownership(com_port
) == 0)
297 tdp
= &td
[com_port
][cur_td
[com_port
]];
298 if (++cur_td
[com_port
] >= TX_NUM_DESC
)
299 cur_td
[com_port
] = 0;
301 *(unchar
*)(tdp
->buffer
^ 7) = c
;
304 tdp
->cmd_stat
= SDMA_DESC_CMDSTAT_L
| SDMA_DESC_CMDSTAT_F
|
307 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sctdp
, (int)tdp
);
308 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sftdp
, (int)tdp
);
309 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
,
310 in_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
) |
315 serial_getc(unsigned long com_port
)
317 struct mv64x60_rx_desc
*rdp
;
320 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
322 if ((rdp
->cmd_stat
& (SDMA_DESC_CMDSTAT_O
|SDMA_DESC_CMDSTAT_ES
)) == 0) {
323 c
= *(unchar
*)(rdp
->buffer
^ 7);
325 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
326 cur_rd
[com_port
] = 0;
333 serial_tstc(unsigned long com_port
)
335 struct mv64x60_rx_desc
*rdp
;
339 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
341 /* Go through rcv descs until empty looking for one with data (no error)*/
342 while (((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_O
) == 0) &&
343 (loop_count
++ < RX_NUM_DESC
)) {
345 /* If there was an error, reinit the desc & continue */
346 if ((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_ES
) != 0) {
348 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
349 cur_rd
[com_port
] = 0;
350 rdp
= (struct mv64x60_rx_desc
*)rdp
->next_desc_ptr
;
361 serial_close(unsigned long com_port
)