3 #include "lib_malloc.h"
4 #include "lib_printf.h"
6 #include "cfe_device.h"
12 #define XTALFREQ 25000000
14 #define WRITEREG(csr,val) *((volatile uint32_t *)(csr)) = (val)
15 #define READREG(csr) (*((volatile uint32_t *)(csr)))
17 #define UARTCTLREG_OFFSET 0x00000020
18 #define BAUDWRDREG_OFFSET 0x00000004
19 #define UARTMSCREG_OFFSET 0x00000008
20 #define UARTSTATUS_OFFSET 0x00000010
21 #define UARTDATAREG_OFFSET 0x00000014
22 #define UARTINTREG_OFFSET 0x0000000C
25 #define INTMASKREG 0xfffe000C
26 #define INT_UART0 0x00000004
27 #define INT_UART1 0x00000002
28 #define INT_TIMER 0x00000001
30 #define DEFAULTBAUD 115200
32 /* Control register */
33 #define BRGEN 0x00800000
34 #define TXEN 0x00400000
35 #define RXEN 0x00200000
37 #define BITS8SYM 0x00003000
38 #define ONESTOP 0x00000700
40 /* Miscellaneous register */
41 #define TX4 0x00004000
42 #define RX4 0x00000400
43 #define DTREN 0x00000001
44 #define RTSEN 0x00000002
46 /* Interrupt Mask / Status register */
47 #define RXBRK 0x40000000
48 #define RXPARERR 0x20000000
49 #define RXFRAMERR 0x10000000
50 #define RXOVFERR 0x00800000
51 #define RXFIFONE 0x00000800
52 #define RESETTXFIFO 0x00000080
53 #define RESETRXFIFO 0x00000040
54 #define TXFIFOEMT 0x00000020
55 #define TXUNDERR 0x00000002
56 #define TXOVFERR 0x00000004
59 static void bcm63xx_uart_probe(cfe_driver_t
*drv
,
60 unsigned long probe_a
, unsigned long probe_b
,
63 static int bcm63xx_uart_open(cfe_devctx_t
*ctx
);
64 static int bcm63xx_uart_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
65 static int bcm63xx_uart_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
);
66 static int bcm63xx_uart_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
67 static int bcm63xx_uart_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
);
68 static int bcm63xx_uart_close(cfe_devctx_t
*ctx
);
70 const static cfe_devdisp_t bcm63xx_uart_dispatch
= {
82 const cfe_driver_t bcm63xx_uart
= {
86 &bcm63xx_uart_dispatch
,
91 typedef struct bcm63xx_uart_s
{
99 uint32_t uart_tx_hold
;
100 uint32_t uart_rx_hold
;
104 static void bcm63xx_set_baudrate( bcm63xx_uart_t
* softc
)
108 baudwd
= (XTALFREQ
/ softc
->baudrate
) / 8;
110 baudwd
= baudwd
/ 2 - 1;
112 WRITEREG( softc
->baudwrdreg
, baudwd
);
116 static void bcm63xx_uart_probe(cfe_driver_t
*drv
,
117 unsigned long probe_a
, unsigned long probe_b
,
120 bcm63xx_uart_t
* softc
;
123 /* enable the transmitter interrupt? */
126 * probe_a is the DUART base address.
127 * probe_b is the channel-number-within-duart (0 or 1)
128 * probe_ptr is unused.
130 softc
= (bcm63xx_uart_t
*) KMALLOC(sizeof(bcm63xx_uart_t
),0);
132 softc
->uartctlreg
= probe_a
+ probe_b
* UARTCTLREG_OFFSET
;
133 softc
->baudwrdreg
= softc
->uartctlreg
+ BAUDWRDREG_OFFSET
;
134 softc
->uartmscreg
= softc
->uartctlreg
+ UARTMSCREG_OFFSET
;
135 softc
->uartintreg
= softc
->uartctlreg
+ UARTINTREG_OFFSET
;
137 softc
->uart_status
= softc
->uartctlreg
+ UARTSTATUS_OFFSET
;
138 softc
->uart_tx_hold
= softc
->uartctlreg
+ UARTDATAREG_OFFSET
;
139 softc
->uart_rx_hold
= softc
->uartctlreg
+ UARTDATAREG_OFFSET
;
141 xsprintf( descr
, "%s at 0x%X channel %d", drv
->drv_description
, probe_a
,
143 cfe_attach( drv
, softc
, NULL
, descr
);
148 #ifdef RAW_WRITE_HACK
149 cfe_devctx_t
* myctx
;
151 int my_write( uint32_t length
, char * msg
);
152 int my_write( uint32_t length
, char * msg
) {
156 data
.buf_length
= length
;
158 return bcm63xx_uart_write( myctx
, &data
);
163 static int bcm63xx_uart_open(cfe_devctx_t
*ctx
)
166 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
168 /* Enable the UART clock */
169 tmpreg
= READREG( 0xFFFE0004 );
170 tmpreg
|= 0x00000008;
171 WRITEREG( 0xFFFE0004, tmpreg
);
174 softc
->baudrate
= DEFAULTBAUD
;
175 bcm63xx_set_baudrate( softc
);
177 WRITEREG( softc
->uartctlreg
, BRGEN
| TXEN
| RXEN
|
179 RESETTXFIFO
| RESETRXFIFO
|
182 WRITEREG( softc
->uartmscreg
, TX4
| RX4
);
183 WRITEREG( softc
->uartintreg
, 0x0 );
185 #ifdef RAW_WRITE_HACK
193 static int bcm63xx_uart_read(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
195 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
196 unsigned char * bptr
;
202 bptr
= buffer
->buf_ptr
;
203 blen
= buffer
->buf_length
;
206 status
= READREG(softc
->uart_status
);
207 if(status
& (RXOVFERR
| RXPARERR
| RXFRAMERR
| RXBRK
)) {
209 if(status
& RXOVFERR
) {
210 /* reset RX FIFO to clr interrupt */
211 /* pChan->uartChannel->fifoctl |= RSTRXFIFOS; */
212 ctrlreg
= READREG(softc
->uartctlreg
);
213 ctrlreg
&= ~RESETRXFIFO
;
214 WRITEREG( softc
->uartctlreg
, ctrlreg
);
217 /* other errors just read the bad character to clear the bit */
218 inval
= READREG( softc
->uart_rx_hold
) & 0xFF;
220 else if(status
& RXFIFONE
) {
221 *bptr
++ = READREG( softc
->uart_rx_hold
) & 0xFF;
228 buffer
->buf_retlen
= buffer
->buf_length
- blen
;
233 static int bcm63xx_uart_inpstat(cfe_devctx_t
*ctx
,iocb_inpstat_t
*inpstat
)
235 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
237 inpstat
->inp_status
= READREG(softc
->uart_status
) & RXFIFONE
;
243 static int bcm63xx_uart_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
245 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
246 unsigned char * bptr
;
251 bptr
= buffer
->buf_ptr
;
252 blen
= buffer
->buf_length
;
255 while( (blen
> 0) && !status
) {
256 /* Wait for the buffer to empty before we write the next character */
257 /* character at a time. Why doesn't it work though? */
259 status
= READREG( softc
->uart_status
) & TXFIFOEMT
;
261 WRITEREG( softc
->uart_tx_hold
, *bptr
);
265 status
= READREG( softc
->uart_status
) & (TXOVFERR
|TXUNDERR
);
270 control
= READREG( softc
->uartctlreg
);
271 control
|= RESETTXFIFO
;
272 WRITEREG( softc
->uartctlreg
, control
);
276 buffer
->buf_retlen
= buffer
->buf_length
- blen
;
281 static int bcm63xx_uart_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
284 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
285 unsigned int * info
= (unsigned int *) buffer
->buf_ptr
;
287 switch ((int)buffer
->buf_ioctlcmd
) {
288 case IOCTL_SERIAL_GETSPEED
:
289 *info
= softc
->baudrate
;
291 case IOCTL_SERIAL_SETSPEED
:
292 softc
->baudrate
= *info
;
293 bcm63xx_set_baudrate( softc
);
295 case IOCTL_SERIAL_GETFLOW
:
296 tmpreg
= READREG( softc
->uartmscreg
);
297 if( tmpreg
& (DTREN
| RTSEN
) ) {
298 *info
= SERIAL_FLOW_HARDWARE
;
300 *info
= SERIAL_FLOW_SOFTWARE
;
303 case IOCTL_SERIAL_SETFLOW
:
304 tmpreg
= READREG( softc
->uartmscreg
);
306 case SERIAL_FLOW_NONE
:
307 case SERIAL_FLOW_SOFTWARE
:
308 tmpreg
&= ~(DTREN
| RTSEN
);
310 case SERIAL_FLOW_HARDWARE
:
311 tmpreg
|= DTREN
| RTSEN
;
314 WRITEREG( softc
->uartmscreg
, tmpreg
);
324 static int bcm63xx_uart_close(cfe_devctx_t
*ctx
)
327 bcm63xx_uart_t
* softc
= ctx
->dev_softc
;
330 /* Turn off the UART clock. */
331 tmpreg
= READREG( 0xFFFE0004 );
332 tmpreg
&= ~( 0x00000008 );
333 WRITEREG( 0xFFFE0004, tmpreg
);
335 /* Restore the Interrupt Status Register to its default state. */
336 tmpreg
= READREG( INTMASKREG
);
337 tmpreg
|= ( INT_UART1
| INT_UART0
);
338 WRITEREG( INTMASKREG
, tmpreg
);
340 /*****************************/
342 /* Restore the baudword register */
343 WRITEREG( softc
->baudwrdreg
, 0x0 );
345 /* Restore the UART control register */
346 WRITEREG( softc
->uartctlreg
, 0x00003704 );
348 /* Restore the UART Miscellaneous Control Register */
349 WRITEREG( softc
->uartmscreg
, 0x00008800 );
351 /* Restore the UART Interrupt Mask / Status Register */
352 WRITEREG( softc
->uartintreg
, 0x0 );