2 * Copyright (c) 2003 Marcel Moolenaar
3 * Copyright (c) 2007-2009 Andrew Turner
4 * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
39 #include <machine/bus.h>
40 #include <machine/intr.h>
42 #include <dev/uart/uart.h>
43 #include <dev/uart/uart_cpu.h>
44 #include <dev/uart/uart_bus.h>
46 #include <arm/samsung/exynos/uart.h>
50 #define DEF_CLK 100000000
52 static int sscomspeed(long, long);
53 static int s3c24x0_uart_param(struct uart_bas *, int, int, int, int);
56 * Low-level UART interface.
58 static int s3c2410_probe(struct uart_bas *bas);
59 static void s3c2410_init(struct uart_bas *bas, int, int, int, int);
60 static void s3c2410_term(struct uart_bas *bas);
61 static void s3c2410_putc(struct uart_bas *bas, int);
62 static int s3c2410_rxready(struct uart_bas *bas);
63 static int s3c2410_getc(struct uart_bas *bas, struct mtx *mtx);
65 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
68 sscomspeed(long speed, long frequency)
72 if (speed <= 0 || frequency <= 0)
74 x = (frequency / 16) / speed;
79 s3c24x0_uart_param(struct uart_bas *bas, int baudrate, int databits,
80 int stopbits, int parity)
88 ulcon |= ULCON_LENGTH_5;
91 ulcon |= ULCON_LENGTH_6;
94 ulcon |= ULCON_LENGTH_7;
97 ulcon |= ULCON_LENGTH_8;
104 case UART_PARITY_NONE:
105 ulcon |= ULCON_PARITY_NONE;
107 case UART_PARITY_ODD:
108 ulcon |= ULCON_PARITY_ODD;
110 case UART_PARITY_EVEN:
111 ulcon |= ULCON_PARITY_EVEN;
113 case UART_PARITY_MARK:
114 case UART_PARITY_SPACE:
122 uart_setreg(bas, SSCOM_ULCON, ulcon);
124 brd = sscomspeed(baudrate, bas->rclk);
125 uart_setreg(bas, SSCOM_UBRDIV, brd);
130 struct uart_ops uart_s3c2410_ops = {
131 .probe = s3c2410_probe,
132 .init = s3c2410_init,
133 .term = s3c2410_term,
134 .putc = s3c2410_putc,
135 .rxready = s3c2410_rxready,
136 .getc = s3c2410_getc,
140 s3c2410_probe(struct uart_bas *bas)
147 s3c2410_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
154 KASSERT(bas->rclk != 0, ("s3c2410_init: Invalid rclk"));
156 uart_setreg(bas, SSCOM_UCON, 0);
157 uart_setreg(bas, SSCOM_UFCON,
158 UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
159 UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
161 s3c24x0_uart_param(bas, baudrate, databits, stopbits, parity);
164 uart_setreg(bas, SSCOM_UCON, UCON_TXMODE_INT | UCON_RXMODE_INT |
166 uart_setreg(bas, SSCOM_UMCON, UMCON_RTS);
170 s3c2410_term(struct uart_bas *bas)
176 s3c2410_putc(struct uart_bas *bas, int c)
179 while ((bus_space_read_4(bas->bst, bas->bsh, SSCOM_UFSTAT) &
180 UFSTAT_TXFULL) == UFSTAT_TXFULL)
183 uart_setreg(bas, SSCOM_UTXH, c);
187 s3c2410_rxready(struct uart_bas *bas)
190 return ((uart_getreg(bas, SSCOM_UTRSTAT) & UTRSTAT_RXREADY) ==
195 s3c2410_getc(struct uart_bas *bas, struct mtx *mtx)
199 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT);
200 while (!(utrstat & UTRSTAT_RXREADY)) {
201 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT);
205 return (bus_space_read_1(bas->bst, bas->bsh, SSCOM_URXH));
208 static int s3c2410_bus_probe(struct uart_softc *sc);
209 static int s3c2410_bus_attach(struct uart_softc *sc);
210 static int s3c2410_bus_flush(struct uart_softc *, int);
211 static int s3c2410_bus_getsig(struct uart_softc *);
212 static int s3c2410_bus_ioctl(struct uart_softc *, int, intptr_t);
213 static int s3c2410_bus_ipend(struct uart_softc *);
214 static int s3c2410_bus_param(struct uart_softc *, int, int, int, int);
215 static int s3c2410_bus_receive(struct uart_softc *);
216 static int s3c2410_bus_setsig(struct uart_softc *, int);
217 static int s3c2410_bus_transmit(struct uart_softc *);
219 static kobj_method_t s3c2410_methods[] = {
220 KOBJMETHOD(uart_probe, s3c2410_bus_probe),
221 KOBJMETHOD(uart_attach, s3c2410_bus_attach),
222 KOBJMETHOD(uart_flush, s3c2410_bus_flush),
223 KOBJMETHOD(uart_getsig, s3c2410_bus_getsig),
224 KOBJMETHOD(uart_ioctl, s3c2410_bus_ioctl),
225 KOBJMETHOD(uart_ipend, s3c2410_bus_ipend),
226 KOBJMETHOD(uart_param, s3c2410_bus_param),
227 KOBJMETHOD(uart_receive, s3c2410_bus_receive),
228 KOBJMETHOD(uart_setsig, s3c2410_bus_setsig),
229 KOBJMETHOD(uart_transmit, s3c2410_bus_transmit),
235 s3c2410_bus_probe(struct uart_softc *sc)
238 sc->sc_txfifosz = 16;
239 sc->sc_rxfifosz = 16;
245 s3c2410_bus_attach(struct uart_softc *sc)
255 s3c2410_bus_transmit(struct uart_softc *sc)
260 uart_lock(sc->sc_hwmtx);
262 for (i = 0; i < sc->sc_txdatasz; i++) {
263 s3c2410_putc(&sc->sc_bas, sc->sc_txbuf[i]);
264 uart_barrier(&sc->sc_bas);
269 uart_unlock(sc->sc_hwmtx);
271 /* unmask TX interrupt */
272 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM);
274 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM, reg);
280 s3c2410_bus_setsig(struct uart_softc *sc, int sig)
287 s3c2410_bus_receive(struct uart_softc *sc)
290 uart_rx_put(sc, uart_getreg(&sc->sc_bas, SSCOM_URXH));
295 s3c2410_bus_param(struct uart_softc *sc, int baudrate, int databits,
296 int stopbits, int parity)
300 if (sc->sc_bas.rclk == 0)
301 sc->sc_bas.rclk = DEF_CLK;
303 KASSERT(sc->sc_bas.rclk != 0, ("s3c2410_init: Invalid rclk"));
305 uart_lock(sc->sc_hwmtx);
306 error = s3c24x0_uart_param(&sc->sc_bas, baudrate, databits, stopbits,
308 uart_unlock(sc->sc_hwmtx);
314 s3c2410_bus_ipend(struct uart_softc *sc)
317 uint32_t txempty, rxready;
321 uart_lock(sc->sc_hwmtx);
322 ints = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP);
323 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP, ints);
329 if ((ints & txempty) > 0) {
330 if (sc->sc_txbusy != 0)
331 ipend |= SER_INT_TXIDLE;
333 /* mask TX interrupt */
334 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh,
337 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh,
341 if ((ints & rxready) > 0) {
342 ipend |= SER_INT_RXREADY;
345 uart_unlock(sc->sc_hwmtx);
350 s3c2410_bus_flush(struct uart_softc *sc, int what)
357 s3c2410_bus_getsig(struct uart_softc *sc)
364 s3c2410_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
370 struct uart_class uart_s3c2410_class = {
374 .uc_ops = &uart_s3c2410_ops,