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/config.h>
16 #include <linux/types.h>
17 #include <linux/serial_reg.h>
18 #include <asm/serial.h>
20 #include <asm/mv64x60_defs.h>
21 #include <mpsc_defs.h>
24 #include <platforms/ev64360.h>
25 u32 mv64x60_console_baud
= EV64360_DEFAULT_BAUD
;
26 u32 mv64x60_mpsc_clk_src
= EV64360_MPSC_CLK_SRC
; /* TCLK */
27 u32 mv64x60_mpsc_clk_freq
= EV64360_MPSC_CLK_FREQ
;
29 u32 mv64x60_console_baud
= 9600;
30 u32 mv64x60_mpsc_clk_src
= 8; /* TCLK */
31 u32 mv64x60_mpsc_clk_freq
= 100000000;
34 extern void udelay(long);
35 static void stop_dma(int chan
);
37 static void __iomem
*mv64x60_base
= (void __iomem
*)CONFIG_MV64X60_NEW_BASE
;
50 static struct sdma_regs sdma_regs
[2];
52 #define SDMA_REGS_INIT(s, reg_base) { \
53 (s)->sdc = (reg_base) + SDMA_SDC; \
54 (s)->sdcm = (reg_base) + SDMA_SDCM; \
55 (s)->rx_desc = (reg_base) + SDMA_RX_DESC; \
56 (s)->rx_buf_ptr = (reg_base) + SDMA_RX_BUF_PTR; \
57 (s)->scrdp = (reg_base) + SDMA_SCRDP; \
58 (s)->tx_desc = (reg_base) + SDMA_TX_DESC; \
59 (s)->sctdp = (reg_base) + SDMA_SCTDP; \
60 (s)->sftdp = (reg_base) + SDMA_SFTDP; \
63 static u32 mpsc_base
[2] = { MV64x60_MPSC_0_OFFSET
, MV64x60_MPSC_1_OFFSET
};
65 struct mv64x60_rx_desc
{
73 struct mv64x60_tx_desc
{
81 #define MAX_RESET_WAIT 10000
82 #define MAX_TX_WAIT 10000
87 #define RX_BUF_SIZE 32
88 #define TX_BUF_SIZE 32
90 static struct mv64x60_rx_desc rd
[2][RX_NUM_DESC
] __attribute__ ((aligned(32)));
91 static struct mv64x60_tx_desc td
[2][TX_NUM_DESC
] __attribute__ ((aligned(32)));
93 static char rx_buf
[2][RX_NUM_DESC
* RX_BUF_SIZE
] __attribute__ ((aligned(32)));
94 static char tx_buf
[2][TX_NUM_DESC
* TX_BUF_SIZE
] __attribute__ ((aligned(32)));
96 static int cur_rd
[2] = { 0, 0 };
97 static int cur_td
[2] = { 0, 0 };
99 static char chan_initialized
[2] = { 0, 0 };
102 #define RX_INIT_RDP(rdp) { \
103 (rdp)->bufsize = 2; \
104 (rdp)->bytecnt = 0; \
105 (rdp)->cmd_stat = SDMA_DESC_CMDSTAT_L | SDMA_DESC_CMDSTAT_F | \
106 SDMA_DESC_CMDSTAT_O; \
109 #ifdef CONFIG_MV64360
110 static u32 cpu2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
111 { MV64x60_CPU2MEM_0_BASE
, MV64x60_CPU2MEM_0_SIZE
},
112 { MV64x60_CPU2MEM_1_BASE
, MV64x60_CPU2MEM_1_SIZE
},
113 { MV64x60_CPU2MEM_2_BASE
, MV64x60_CPU2MEM_2_SIZE
},
114 { MV64x60_CPU2MEM_3_BASE
, MV64x60_CPU2MEM_3_SIZE
}
117 static u32 com2mem_tab
[MV64x60_CPU2MEM_WINDOWS
][2] = {
118 { MV64360_MPSC2MEM_0_BASE
, MV64360_MPSC2MEM_0_SIZE
},
119 { MV64360_MPSC2MEM_1_BASE
, MV64360_MPSC2MEM_1_SIZE
},
120 { MV64360_MPSC2MEM_2_BASE
, MV64360_MPSC2MEM_2_SIZE
},
121 { MV64360_MPSC2MEM_3_BASE
, MV64360_MPSC2MEM_3_SIZE
}
124 static u32 dram_selects
[MV64x60_CPU2MEM_WINDOWS
] = { 0xe, 0xd, 0xb, 0x7 };
128 serial_init(int chan
, void *ignored
)
130 u32 mpsc_routing_base
, sdma_base
, brg_bcr
, cdv
;
133 chan
= (chan
== 1); /* default to chan 0 if anything but 1 */
135 if (chan_initialized
[chan
])
138 chan_initialized
[chan
] = 1;
141 sdma_base
= MV64x60_SDMA_0_OFFSET
;
142 brg_bcr
= MV64x60_BRG_0_OFFSET
+ BRG_BCR
;
143 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_0_OFFSET
);
145 sdma_base
= MV64x60_SDMA_1_OFFSET
;
146 brg_bcr
= MV64x60_BRG_1_OFFSET
+ BRG_BCR
;
147 SDMA_REGS_INIT(&sdma_regs
[0], MV64x60_SDMA_1_OFFSET
);
150 mpsc_routing_base
= MV64x60_MPSC_ROUTING_OFFSET
;
154 /* Set up ring buffers */
155 for (i
=0; i
<RX_NUM_DESC
; i
++) {
156 RX_INIT_RDP(&rd
[chan
][i
]);
157 rd
[chan
][i
].buffer
= (u32
)&rx_buf
[chan
][i
* RX_BUF_SIZE
];
158 rd
[chan
][i
].next_desc_ptr
= (u32
)&rd
[chan
][i
+1];
160 rd
[chan
][RX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&rd
[chan
][0];
162 for (i
=0; i
<TX_NUM_DESC
; i
++) {
163 td
[chan
][i
].bytecnt
= 0;
164 td
[chan
][i
].shadow
= 0;
165 td
[chan
][i
].buffer
= (u32
)&tx_buf
[chan
][i
* TX_BUF_SIZE
];
166 td
[chan
][i
].cmd_stat
= SDMA_DESC_CMDSTAT_F
|SDMA_DESC_CMDSTAT_L
;
167 td
[chan
][i
].next_desc_ptr
= (u32
)&td
[chan
][i
+1];
169 td
[chan
][TX_NUM_DESC
- 1].next_desc_ptr
= (u32
)&td
[chan
][0];
171 /* Set MPSC Routing */
172 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_MRR
, 0x3ffffe38);
174 #ifdef CONFIG_GT64260
175 out_le32(mv64x60_base
+ GT64260_MPP_SERIAL_PORTS_MULTIPLEX
, 0x00001102);
176 #else /* Must be MV64360 or MV64460 */
178 u32 enables
, prot_bits
, v
;
180 /* Set up comm unit to memory mapping windows */
181 /* Note: Assumes MV64x60_CPU2MEM_WINDOWS == 4 */
183 enables
= in_le32(mv64x60_base
+ MV64360_CPU_BAR_ENABLE
) & 0xf;
186 for (i
=0; i
<MV64x60_CPU2MEM_WINDOWS
; i
++) {
187 if (!(enables
& (1 << i
))) {
188 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][0]);
189 v
= ((v
& 0xffff) << 16) | (dram_selects
[i
] << 8);
190 out_le32(mv64x60_base
+ com2mem_tab
[i
][0], v
);
192 v
= in_le32(mv64x60_base
+ cpu2mem_tab
[i
][1]);
193 v
= (v
& 0xffff) << 16;
194 out_le32(mv64x60_base
+ com2mem_tab
[i
][1], v
);
196 prot_bits
|= (0x3 << (i
<< 1)); /* r/w access */
200 out_le32(mv64x60_base
+ MV64360_MPSC_0_REMAP
, 0);
201 out_le32(mv64x60_base
+ MV64360_MPSC_1_REMAP
, 0);
202 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_0
, prot_bits
);
203 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_ACC_PROT_1
, prot_bits
);
204 out_le32(mv64x60_base
+ MV64360_MPSC2MEM_BAR_ENABLE
, enables
);
208 /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
209 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_RCRR
, 0x00000100);
210 out_le32(mv64x60_base
+ mpsc_routing_base
+ MPSC_TCRR
, 0x00000100);
212 /* clear pending interrupts */
213 out_le32(mv64x60_base
+ MV64x60_SDMA_INTR_OFFSET
+ SDMA_INTR_MASK
, 0);
215 out_le32(mv64x60_base
+ SDMA_SCRDP
+ sdma_base
, (int)&rd
[chan
][0]);
216 out_le32(mv64x60_base
+ SDMA_SCTDP
+ sdma_base
,
217 (int)&td
[chan
][TX_NUM_DESC
- 1]);
218 out_le32(mv64x60_base
+ SDMA_SFTDP
+ sdma_base
,
219 (int)&td
[chan
][TX_NUM_DESC
- 1]);
221 out_le32(mv64x60_base
+ SDMA_SDC
+ sdma_base
,
222 SDMA_SDC_RFT
| SDMA_SDC_SFM
| SDMA_SDC_BLMR
| SDMA_SDC_BLMT
|
225 cdv
= ((mv64x60_mpsc_clk_freq
/(32*mv64x60_console_baud
))-1);
226 out_le32(mv64x60_base
+ brg_bcr
,
227 ((mv64x60_mpsc_clk_src
<< 18) | (1 << 16) | cdv
));
229 /* Put MPSC into UART mode, no null modem, 16x clock mode */
230 out_le32(mv64x60_base
+ MPSC_MMCRL
+ mpsc_base
[chan
], 0x000004c4);
231 out_le32(mv64x60_base
+ MPSC_MMCRH
+ mpsc_base
[chan
], 0x04400400);
233 out_le32(mv64x60_base
+ MPSC_CHR_1
+ mpsc_base
[chan
], 0);
234 out_le32(mv64x60_base
+ MPSC_CHR_9
+ mpsc_base
[chan
], 0);
235 out_le32(mv64x60_base
+ MPSC_CHR_10
+ mpsc_base
[chan
], 0);
236 out_le32(mv64x60_base
+ MPSC_CHR_3
+ mpsc_base
[chan
], 4);
237 out_le32(mv64x60_base
+ MPSC_CHR_4
+ mpsc_base
[chan
], 0);
238 out_le32(mv64x60_base
+ MPSC_CHR_5
+ mpsc_base
[chan
], 0);
239 out_le32(mv64x60_base
+ MPSC_CHR_6
+ mpsc_base
[chan
], 0);
240 out_le32(mv64x60_base
+ MPSC_CHR_7
+ mpsc_base
[chan
], 0);
241 out_le32(mv64x60_base
+ MPSC_CHR_8
+ mpsc_base
[chan
], 0);
243 /* 8 data bits, 1 stop bit */
244 out_le32(mv64x60_base
+ MPSC_MPCR
+ mpsc_base
[chan
], (3 << 12));
245 out_le32(mv64x60_base
+ SDMA_SDCM
+ sdma_base
, SDMA_SDCM_ERD
);
246 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_EH
);
258 /* Abort MPSC Rx (aborting Tx messes things up) */
259 out_le32(mv64x60_base
+ MPSC_CHR_2
+ mpsc_base
[chan
], MPSC_CHR_2_RA
);
261 /* Abort SDMA Rx, Tx */
262 out_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
,
263 SDMA_SDCM_AR
| SDMA_SDCM_STD
);
265 for (i
=0; i
<MAX_RESET_WAIT
; i
++) {
266 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
267 (SDMA_SDCM_AR
| SDMA_SDCM_AT
)) == 0)
275 wait_for_ownership(int chan
)
279 for (i
=0; i
<MAX_TX_WAIT
; i
++) {
280 if ((in_le32(mv64x60_base
+ sdma_regs
[chan
].sdcm
) &
287 return (i
< MAX_TX_WAIT
);
291 serial_putc(unsigned long com_port
, unsigned char c
)
293 struct mv64x60_tx_desc
*tdp
;
295 if (wait_for_ownership(com_port
) == 0)
298 tdp
= &td
[com_port
][cur_td
[com_port
]];
299 if (++cur_td
[com_port
] >= TX_NUM_DESC
)
300 cur_td
[com_port
] = 0;
302 *(unchar
*)(tdp
->buffer
^ 7) = c
;
305 tdp
->cmd_stat
= SDMA_DESC_CMDSTAT_L
| SDMA_DESC_CMDSTAT_F
|
308 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sctdp
, (int)tdp
);
309 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sftdp
, (int)tdp
);
310 out_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
,
311 in_le32(mv64x60_base
+ sdma_regs
[com_port
].sdcm
) |
316 serial_getc(unsigned long com_port
)
318 struct mv64x60_rx_desc
*rdp
;
321 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
323 if ((rdp
->cmd_stat
& (SDMA_DESC_CMDSTAT_O
|SDMA_DESC_CMDSTAT_ES
)) == 0) {
324 c
= *(unchar
*)(rdp
->buffer
^ 7);
326 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
327 cur_rd
[com_port
] = 0;
334 serial_tstc(unsigned long com_port
)
336 struct mv64x60_rx_desc
*rdp
;
340 rdp
= &rd
[com_port
][cur_rd
[com_port
]];
342 /* Go thru rcv desc's until empty looking for one with data (no error)*/
343 while (((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_O
) == 0) &&
344 (loop_count
++ < RX_NUM_DESC
)) {
346 /* If there was an error, reinit the desc & continue */
347 if ((rdp
->cmd_stat
& SDMA_DESC_CMDSTAT_ES
) != 0) {
349 if (++cur_rd
[com_port
] >= RX_NUM_DESC
)
350 cur_rd
[com_port
] = 0;
351 rdp
= (struct mv64x60_rx_desc
*)rdp
->next_desc_ptr
;
362 serial_close(unsigned long com_port
)