1 /* $NetBSD: uart.c,v 1.5 2008/06/11 23:55:20 cegger Exp $ */
4 * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * 3. The names of the authors may not be used to endorse or promote
17 * products derived from this software without specific prior
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: uart.c,v 1.5 2008/06/11 23:55:20 cegger Exp $");
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
42 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/kauth.h>
51 #include <sys/vnode.h>
53 #include <machine/intr.h>
54 #include <machine/bus.h>
56 #include <mips/adm5120/include/adm5120var.h>
57 #include <mips/adm5120/include/adm5120_obiovar.h>
59 #include <mips/adm5120/dev/uart.h>
61 #define REG_READ(o) bus_space_read_4(sc->sc_st, sc->sc_ioh, (o))
62 #define REG_WRITE(o,v) bus_space_write_4(sc->sc_st, sc->sc_ioh, (o),(v))
66 extern struct consdev
*cn_tab
; /* physical console device info */
68 dev_type_open(uart_open
);
69 dev_type_open(uart_close
);
70 dev_type_read(uart_read
);
71 dev_type_write(uart_write
);
72 dev_type_ioctl(uart_ioctl
);
73 dev_type_tty(uart_tty
);
74 dev_type_poll(uart_poll
);
75 dev_type_stop(uart_stop
);
77 const struct cdevsw uart_cdevsw
= {
78 uart_open
, uart_close
, uart_read
, uart_write
, uart_ioctl
,
79 uart_stop
, uart_tty
, uart_poll
, nommap
, ttykqfilter
, D_TTY
83 struct consdev uartcons
= {
84 NULL
, NULL
, uart_cngetc
, uart_cnputc
, uart_cnpollc
, NULL
, NULL
, NULL
,
92 bus_space_tag_t sc_st
;
93 bus_space_handle_t sc_ioh
;
97 extern struct cfdriver uart_cd
;
98 static int uart_consattached
;
100 static int uart_probe (struct device
*, struct cfdata
*, void *);
101 static void uart_attach (struct device
*, struct device
*, void *);
103 void uart_start(struct tty
*);
104 int uart_param(struct tty
*, struct termios
*);
105 int uart_intr(void *);
107 CFATTACH_DECL(uart
, sizeof(struct uart_softc
),
108 uart_probe
, uart_attach
, NULL
, NULL
);
111 uart_probe(struct device
*parent
, struct cfdata
*cf
, void *aux
)
113 struct obio_attach_args
*aa
= aux
;
115 if (strcmp(aa
->oba_name
, cf
->cf_name
) == 0)
122 uart_attach(struct device
*parent
, struct device
*self
, void *aux
)
124 struct obio_attach_args
*oba
= aux
;
125 struct uart_softc
*sc
= (struct uart_softc
*)self
;
129 sc
->sc_st
= oba
->oba_st
;
130 if (bus_space_map(oba
->oba_st
, oba
->oba_addr
, 256, 0,
132 printf("%s: unable to map device\n", sc
->sc_dev
.dv_xname
);
136 /* Establish the interrupt. */
137 sc
->sc_ih
= adm5120_intr_establish(oba
->oba_irq
, INTR_FIQ
, uart_intr
, sc
);
138 if (sc
->sc_ih
== NULL
) {
139 printf("%s: unable to establish interrupt\n",
140 sc
->sc_dev
.dv_xname
);
143 REG_WRITE(UART_CR_REG
,UART_CR_PORT_EN
|UART_CR_RX_INT_EN
|UART_CR_RX_TIMEOUT_INT_EN
);
145 maj
= cdevsw_lookup_major(&uart_cdevsw
);
146 minor
= sc
->sc_dev
.dv_unit
;
149 tp
->t_oproc
= uart_start
;
150 tp
->t_param
= uart_param
;
152 tp
->t_dev
= makedev(maj
, minor
);
154 if (minor
== 0 && uart_consattached
) {
155 /* attach as console*/
156 cn_tab
->cn_dev
= tp
->t_dev
;
166 uart_consattached
= 1;
171 uart_cnputc(dev_t dev
, int c
)
175 while ((*((volatile unsigned long *)0xb2600018)) & 0x20) ;
176 (*((volatile unsigned long *)0xb2600000)) = c
;
180 uart_cngetc(dev_t dev
)
182 while ((*((volatile unsigned long *)0xb2600018)) & 0x10) ;
183 return (*((volatile unsigned long *)0xb2600000)) & 0xff;
187 uart_cnpollc(dev_t dev
, int on
)
198 uart_open(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
200 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
201 struct tty
*tp
= sc
->sc_tty
;
207 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
208 tp
->t_state
|= TS_CARR_ON
;
210 tp
->t_iflag
= TTYDEF_IFLAG
;
211 tp
->t_oflag
= TTYDEF_OFLAG
;
212 tp
->t_cflag
= TTYDEF_CFLAG
| CLOCAL
;
213 tp
->t_lflag
= TTYDEF_LFLAG
;
214 tp
->t_ispeed
= tp
->t_ospeed
= 115200;
216 } else if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
,
224 error
= (*tp
->t_linesw
->l_open
)(dev
, tp
);
230 uart_close(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
232 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
233 struct tty
*tp
= sc
->sc_tty
;
235 (*tp
->t_linesw
->l_close
)(tp
, flag
);
242 uart_read(dev_t dev
, struct uio
*uio
, int flag
)
244 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
245 struct tty
*tp
= sc
->sc_tty
;
247 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
251 uart_write(dev_t dev
, struct uio
*uio
, int flag
)
253 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
254 struct tty
*tp
= sc
->sc_tty
;
256 return ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
260 uart_poll(dev_t dev
, int events
, struct lwp
*l
)
262 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
263 struct tty
*tp
= sc
->sc_tty
;
265 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
269 uart_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
271 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
272 struct tty
*tp
= sc
->sc_tty
;
275 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
276 if (error
!= EPASSTHROUGH
)
278 return (ttioctl(tp
, cmd
, data
, flag
, l
));
282 uart_param(struct tty
*tp
, struct termios
*t
)
291 struct uart_softc
*sc
= device_lookup_private(&uart_cd
, minor(dev
));
298 uart_start(struct tty
*tp
)
303 if (tp
->t_state
& (TS_TTSTOP
| TS_BUSY
))
306 tp
->t_state
|= TS_BUSY
;
307 while (tp
->t_outq
.c_cc
!= 0) {
308 cnt
= ndqb(&tp
->t_outq
, 0);
309 for (i
=0; i
<cnt
; i
++)
310 uart_cnputc(0,tp
->t_outq
.c_cf
[i
]);
311 ndflush(&tp
->t_outq
, cnt
);
313 tp
->t_state
&= ~TS_BUSY
;
319 uart_stop(struct tty
*tp
, int flag
)
324 if (tp
->t_state
& TS_BUSY
)
325 if ((tp
->t_state
& TS_TTSTOP
) == 0)
326 tp
->t_state
|= TS_FLUSH
;
333 struct uart_softc
*sc
= v
;
334 struct tty
*tp
= sc
->sc_tty
;
337 if (REG_READ(UART_RSR_REG
) & UART_RSR_BE
) {
338 REG_WRITE(UART_ECR_REG
, UART_ECR_RSR
);
342 while ((REG_READ(UART_FR_REG
) & UART_FR_RX_FIFO_EMPTY
) == 0) {
343 c
= REG_READ(UART_DR_REG
) & 0xff;
344 if (tp
->t_state
& TS_ISOPEN
)
345 l_r
= (*tp
->t_linesw
->l_rint
)(c
, tp
);