3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * SPDX-License-Identifier: GPL-2.0+
13 #include <linux/compiler.h>
15 DECLARE_GLOBAL_DATA_PTR
;
17 #if !defined(CONFIG_8xx_CONS_NONE) /* No Console at all */
19 #if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */
21 #define PROFF_SMC PROFF_SMC1
22 #define CPM_CR_CH_SMC CPM_CR_CH_SMC1
24 #elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */
26 #define PROFF_SMC PROFF_SMC2
27 #define CPM_CR_CH_SMC CPM_CR_CH_SMC2
29 #endif /* CONFIG_8xx_CONS_SMCx */
31 #if !defined(CONFIG_SYS_SMC_RXBUFLEN)
32 #define CONFIG_SYS_SMC_RXBUFLEN 1
33 #define CONFIG_SYS_MAXIDLE 0
35 #if !defined(CONFIG_SYS_MAXIDLE)
36 #error "you must define CONFIG_SYS_MAXIDLE"
40 typedef volatile struct serialbuffer
{
41 cbd_t rxbd
; /* Rx BD */
42 cbd_t txbd
; /* Tx BD */
43 uint rxindex
; /* index for next character to read */
44 volatile uchar rxbuf
[CONFIG_SYS_SMC_RXBUFLEN
];/* rx buffers */
45 volatile uchar txbuf
; /* tx buffers */
48 static void serial_setdivisor(volatile cpm8xx_t
*cp
)
50 int divisor
=(gd
->cpu_clk
+ 8*gd
->baudrate
)/16/gd
->baudrate
;
52 if(divisor
/16>0x1000) {
53 /* bad divisor, assume 50MHz clock and 9600 baud */
54 divisor
=(50*1000*1000 + 8*9600)/16/9600;
57 #ifdef CONFIG_SYS_BRGCLK_PRESCALE
58 divisor
/= CONFIG_SYS_BRGCLK_PRESCALE
;
62 cp
->cp_brgc1
=((divisor
-1)<<1) | CPM_BRG_EN
;
64 cp
->cp_brgc1
=((divisor
/16-1)<<1) | CPM_BRG_EN
| CPM_BRG_DIV16
;
69 * Minimal serial functions needed to use one of the SMC ports
70 * as serial console interface.
73 static void smc_setbrg (void)
75 volatile immap_t
*im
= (immap_t
*)CONFIG_SYS_IMMR
;
76 volatile cpm8xx_t
*cp
= &(im
->im_cpm
);
78 /* Set up the baud rate generator.
79 * See 8xx_io/commproc.c for details.
84 cp
->cp_simode
= 0x00000000;
86 serial_setdivisor(cp
);
89 static int smc_init (void)
91 volatile immap_t
*im
= (immap_t
*)CONFIG_SYS_IMMR
;
93 volatile smc_uart_t
*up
;
94 volatile cpm8xx_t
*cp
= &(im
->im_cpm
);
96 volatile serialbuffer_t
*rtx
;
98 /* initialize pointers to SMC */
100 sp
= (smc_t
*) &(cp
->cp_smc
[SMC_INDEX
]);
101 up
= (smc_uart_t
*) &cp
->cp_dparam
[PROFF_SMC
];
102 /* Disable relocation */
105 /* Disable transmitter/receiver. */
106 sp
->smc_smcmr
&= ~(SMCMR_REN
| SMCMR_TEN
);
109 im
->im_siu_conf
.sc_sdcr
= 1;
111 /* clear error conditions */
112 #ifdef CONFIG_SYS_SDSR
113 im
->im_sdma
.sdma_sdsr
= CONFIG_SYS_SDSR
;
115 im
->im_sdma
.sdma_sdsr
= 0x83;
118 /* clear SDMA interrupt mask */
119 #ifdef CONFIG_SYS_SDMR
120 im
->im_sdma
.sdma_sdmr
= CONFIG_SYS_SDMR
;
122 im
->im_sdma
.sdma_sdmr
= 0x00;
125 #if defined(CONFIG_8xx_CONS_SMC1)
126 /* Use Port B for SMC1 instead of other functions. */
127 cp
->cp_pbpar
|= 0x000000c0;
128 cp
->cp_pbdir
&= ~0x000000c0;
129 cp
->cp_pbodr
&= ~0x000000c0;
130 #else /* CONFIG_8xx_CONS_SMC2 */
131 /* Use Port B for SMC2 instead of other functions.
133 cp
->cp_pbpar
|= 0x00000c00;
134 cp
->cp_pbdir
&= ~0x00000c00;
135 cp
->cp_pbodr
&= ~0x00000c00;
138 /* Set the physical address of the host memory buffers in
139 * the buffer descriptors.
141 dpaddr
= CPM_SERIAL_BASE
;
143 rtx
= (serialbuffer_t
*)&cp
->cp_dpmem
[dpaddr
];
144 /* Allocate space for two buffer descriptors in the DP ram.
145 * For now, this address seems OK, but it may have to
146 * change with newer versions of the firmware.
147 * damm: allocating space after the two buffers for rx/tx data
150 rtx
->rxbd
.cbd_bufaddr
= (uint
) &rtx
->rxbuf
;
151 rtx
->rxbd
.cbd_sc
= 0;
153 rtx
->txbd
.cbd_bufaddr
= (uint
) &rtx
->txbuf
;
154 rtx
->txbd
.cbd_sc
= 0;
156 /* Set up the uart parameters in the parameter ram. */
157 up
->smc_rbase
= dpaddr
;
158 up
->smc_tbase
= dpaddr
+sizeof(cbd_t
);
159 up
->smc_rfcr
= SMC_EB
;
160 up
->smc_tfcr
= SMC_EB
;
162 /* Set UART mode, 8 bit, no parity, one stop.
163 * Enable receive and transmit.
165 sp
->smc_smcmr
= smcr_mk_clen(9) | SMCMR_SM_UART
;
167 /* Mask all interrupts and remove anything pending.
172 /* Set up the baud rate generator */
175 /* Make the first buffer the only buffer. */
176 rtx
->txbd
.cbd_sc
|= BD_SC_WRAP
;
177 rtx
->rxbd
.cbd_sc
|= BD_SC_EMPTY
| BD_SC_WRAP
;
179 /* single/multi character receive. */
180 up
->smc_mrblr
= CONFIG_SYS_SMC_RXBUFLEN
;
181 up
->smc_maxidl
= CONFIG_SYS_MAXIDLE
;
184 /* Initialize Tx/Rx parameters. */
185 while (cp
->cp_cpcr
& CPM_CR_FLG
) /* wait if cp is busy */
188 cp
->cp_cpcr
= mk_cr_cmd(CPM_CR_CH_SMC
, CPM_CR_INIT_TRX
) | CPM_CR_FLG
;
190 while (cp
->cp_cpcr
& CPM_CR_FLG
) /* wait if cp is busy */
193 /* Enable transmitter/receiver. */
194 sp
->smc_smcmr
|= SMCMR_REN
| SMCMR_TEN
;
200 smc_putc(const char c
)
202 volatile smc_uart_t
*up
;
203 volatile immap_t
*im
= (immap_t
*)CONFIG_SYS_IMMR
;
204 volatile cpm8xx_t
*cpmp
= &(im
->im_cpm
);
205 volatile serialbuffer_t
*rtx
;
210 up
= (smc_uart_t
*)&cpmp
->cp_dparam
[PROFF_SMC
];
212 rtx
= (serialbuffer_t
*)&cpmp
->cp_dpmem
[up
->smc_rbase
];
214 /* Wait for last character to go. */
216 rtx
->txbd
.cbd_datlen
= 1;
217 rtx
->txbd
.cbd_sc
|= BD_SC_READY
;
220 while (rtx
->txbd
.cbd_sc
& BD_SC_READY
) {
227 smc_puts (const char *s
)
237 volatile smc_uart_t
*up
;
238 volatile immap_t
*im
= (immap_t
*)CONFIG_SYS_IMMR
;
239 volatile cpm8xx_t
*cpmp
= &(im
->im_cpm
);
240 volatile serialbuffer_t
*rtx
;
243 up
= (smc_uart_t
*)&cpmp
->cp_dparam
[PROFF_SMC
];
244 rtx
= (serialbuffer_t
*)&cpmp
->cp_dpmem
[up
->smc_rbase
];
246 /* Wait for character to show up. */
247 while (rtx
->rxbd
.cbd_sc
& BD_SC_EMPTY
)
250 /* the characters are read one by one,
251 * use the rxindex to know the next char to deliver
253 c
= *(unsigned char *) (rtx
->rxbd
.cbd_bufaddr
+rtx
->rxindex
);
256 /* check if all char are readout, then make prepare for next receive */
257 if (rtx
->rxindex
>= rtx
->rxbd
.cbd_datlen
) {
259 rtx
->rxbd
.cbd_sc
|= BD_SC_EMPTY
;
267 volatile smc_uart_t
*up
;
268 volatile immap_t
*im
= (immap_t
*)CONFIG_SYS_IMMR
;
269 volatile cpm8xx_t
*cpmp
= &(im
->im_cpm
);
270 volatile serialbuffer_t
*rtx
;
272 up
= (smc_uart_t
*)&cpmp
->cp_dparam
[PROFF_SMC
];
274 rtx
= (serialbuffer_t
*)&cpmp
->cp_dpmem
[up
->smc_rbase
];
276 return !(rtx
->rxbd
.cbd_sc
& BD_SC_EMPTY
);
279 struct serial_device serial_smc_device
=
281 .name
= "serial_smc",
284 .setbrg
= smc_setbrg
,
291 __weak
struct serial_device
*default_serial_console(void)
293 return &serial_smc_device
;
296 void mpc8xx_serial_initialize(void)
298 serial_register(&serial_smc_device
);
301 #endif /* CONFIG_8xx_CONS_NONE */