31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/conf.h> 36#include <sys/cons.h> 37#include <sys/tty.h> 38#include <sys/rman.h> 39#include <machine/bus.h> 40#include <machine/intr.h> 41 42#include <dev/uart/uart.h> 43#include <dev/uart/uart_cpu.h> 44#include <dev/uart/uart_cpu_fdt.h> 45#include <dev/uart/uart_bus.h> 46 47#include <arm/samsung/exynos/exynos_uart.h> 48 49#include "uart_if.h" 50 51#define DEF_CLK 100000000 52 53static int sscomspeed(long, long); 54static int exynos4210_uart_param(struct uart_bas *, int, int, int, int); 55 56/* 57 * Low-level UART interface. 58 */ 59static int exynos4210_probe(struct uart_bas *bas); 60static void exynos4210_init(struct uart_bas *bas, int, int, int, int); 61static void exynos4210_term(struct uart_bas *bas); 62static void exynos4210_putc(struct uart_bas *bas, int); 63static int exynos4210_rxready(struct uart_bas *bas); 64static int exynos4210_getc(struct uart_bas *bas, struct mtx *mtx); 65 66extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; 67 68static int 69sscomspeed(long speed, long frequency) 70{ 71 int x; 72 73 if (speed <= 0 || frequency <= 0) 74 return (-1); 75 x = (frequency / 16) / speed; 76 return (x-1); 77} 78 79static int 80exynos4210_uart_param(struct uart_bas *bas, int baudrate, int databits, 81 int stopbits, int parity) 82{ 83 int brd, ulcon; 84 85 ulcon = 0; 86 87 switch(databits) { 88 case 5: 89 ulcon |= ULCON_LENGTH_5; 90 break; 91 case 6: 92 ulcon |= ULCON_LENGTH_6; 93 break; 94 case 7: 95 ulcon |= ULCON_LENGTH_7; 96 break; 97 case 8: 98 ulcon |= ULCON_LENGTH_8; 99 break; 100 default: 101 return (EINVAL); 102 } 103 104 switch (parity) { 105 case UART_PARITY_NONE: 106 ulcon |= ULCON_PARITY_NONE; 107 break; 108 case UART_PARITY_ODD: 109 ulcon |= ULCON_PARITY_ODD; 110 break; 111 case UART_PARITY_EVEN: 112 ulcon |= ULCON_PARITY_EVEN; 113 break; 114 case UART_PARITY_MARK: 115 case UART_PARITY_SPACE: 116 default: 117 return (EINVAL); 118 } 119 120 if (stopbits == 2) 121 ulcon |= ULCON_STOP; 122 123 uart_setreg(bas, SSCOM_ULCON, ulcon); 124 125 brd = sscomspeed(baudrate, bas->rclk); 126 uart_setreg(bas, SSCOM_UBRDIV, brd); 127 128 return (0); 129} 130 131struct uart_ops uart_exynos4210_ops = { 132 .probe = exynos4210_probe, 133 .init = exynos4210_init, 134 .term = exynos4210_term, 135 .putc = exynos4210_putc, 136 .rxready = exynos4210_rxready, 137 .getc = exynos4210_getc, 138}; 139 140static int 141exynos4210_probe(struct uart_bas *bas) 142{ 143 144 return (0); 145} 146 147static void 148exynos4210_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 149 int parity) 150{ 151 152 if (bas->rclk == 0) 153 bas->rclk = DEF_CLK; 154 155 KASSERT(bas->rclk != 0, ("exynos4210_init: Invalid rclk")); 156 157 uart_setreg(bas, SSCOM_UCON, 0); 158 uart_setreg(bas, SSCOM_UFCON, 159 UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 | 160 UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET | 161 UFCON_FIFO_ENABLE); 162 exynos4210_uart_param(bas, baudrate, databits, stopbits, parity); 163 164 /* Enable UART. */ 165 uart_setreg(bas, SSCOM_UCON, UCON_TXMODE_INT | UCON_RXMODE_INT | 166 UCON_TOINT); 167 uart_setreg(bas, SSCOM_UMCON, UMCON_RTS); 168} 169 170static void 171exynos4210_term(struct uart_bas *bas) 172{ 173 /* XXX */ 174} 175 176static void 177exynos4210_putc(struct uart_bas *bas, int c) 178{ 179 180 while ((bus_space_read_4(bas->bst, bas->bsh, SSCOM_UFSTAT) & 181 UFSTAT_TXFULL) == UFSTAT_TXFULL) 182 continue; 183 184 uart_setreg(bas, SSCOM_UTXH, c); 185} 186 187static int 188exynos4210_rxready(struct uart_bas *bas) 189{ 190 191 return ((uart_getreg(bas, SSCOM_UTRSTAT) & UTRSTAT_RXREADY) == 192 UTRSTAT_RXREADY); 193} 194 195static int 196exynos4210_getc(struct uart_bas *bas, struct mtx *mtx) 197{ 198 int utrstat; 199 200 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT); 201 while (!(utrstat & UTRSTAT_RXREADY)) { 202 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT); 203 continue; 204 } 205 206 return (bus_space_read_1(bas->bst, bas->bsh, SSCOM_URXH)); 207} 208 209static int exynos4210_bus_probe(struct uart_softc *sc); 210static int exynos4210_bus_attach(struct uart_softc *sc); 211static int exynos4210_bus_flush(struct uart_softc *, int); 212static int exynos4210_bus_getsig(struct uart_softc *); 213static int exynos4210_bus_ioctl(struct uart_softc *, int, intptr_t); 214static int exynos4210_bus_ipend(struct uart_softc *); 215static int exynos4210_bus_param(struct uart_softc *, int, int, int, int); 216static int exynos4210_bus_receive(struct uart_softc *); 217static int exynos4210_bus_setsig(struct uart_softc *, int); 218static int exynos4210_bus_transmit(struct uart_softc *); 219 220static kobj_method_t exynos4210_methods[] = { 221 KOBJMETHOD(uart_probe, exynos4210_bus_probe), 222 KOBJMETHOD(uart_attach, exynos4210_bus_attach), 223 KOBJMETHOD(uart_flush, exynos4210_bus_flush), 224 KOBJMETHOD(uart_getsig, exynos4210_bus_getsig), 225 KOBJMETHOD(uart_ioctl, exynos4210_bus_ioctl), 226 KOBJMETHOD(uart_ipend, exynos4210_bus_ipend), 227 KOBJMETHOD(uart_param, exynos4210_bus_param), 228 KOBJMETHOD(uart_receive, exynos4210_bus_receive), 229 KOBJMETHOD(uart_setsig, exynos4210_bus_setsig), 230 KOBJMETHOD(uart_transmit, exynos4210_bus_transmit), 231 232 {0, 0 } 233}; 234 235int 236exynos4210_bus_probe(struct uart_softc *sc) 237{ 238 239 sc->sc_txfifosz = 16; 240 sc->sc_rxfifosz = 16; 241 242 return (0); 243} 244 245static int 246exynos4210_bus_attach(struct uart_softc *sc) 247{ 248 249 sc->sc_hwiflow = 0; 250 sc->sc_hwoflow = 0; 251 252 return (0); 253} 254 255static int 256exynos4210_bus_transmit(struct uart_softc *sc) 257{ 258 int i; 259 int reg; 260 261 uart_lock(sc->sc_hwmtx); 262 263 for (i = 0; i < sc->sc_txdatasz; i++) { 264 exynos4210_putc(&sc->sc_bas, sc->sc_txbuf[i]); 265 uart_barrier(&sc->sc_bas); 266 } 267 268 sc->sc_txbusy = 1; 269 270 uart_unlock(sc->sc_hwmtx); 271 272 /* unmask TX interrupt */ 273 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM); 274 reg &= ~(1 << 2); 275 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM, reg); 276 277 return (0); 278} 279 280static int 281exynos4210_bus_setsig(struct uart_softc *sc, int sig) 282{ 283 284 return (0); 285} 286 287static int 288exynos4210_bus_receive(struct uart_softc *sc) 289{ 290 struct uart_bas *bas; 291 292 bas = &sc->sc_bas; 293 while (bus_space_read_4(bas->bst, bas->bsh, 294 SSCOM_UFSTAT) & UFSTAT_RXCOUNT) 295 uart_rx_put(sc, uart_getreg(&sc->sc_bas, SSCOM_URXH)); 296 297 return (0); 298} 299 300static int 301exynos4210_bus_param(struct uart_softc *sc, int baudrate, int databits, 302 int stopbits, int parity) 303{ 304 int error; 305 306 if (sc->sc_bas.rclk == 0) 307 sc->sc_bas.rclk = DEF_CLK; 308 309 KASSERT(sc->sc_bas.rclk != 0, ("exynos4210_init: Invalid rclk")); 310 311 uart_lock(sc->sc_hwmtx); 312 error = exynos4210_uart_param(&sc->sc_bas, baudrate, databits, stopbits, 313 parity); 314 uart_unlock(sc->sc_hwmtx); 315 316 return (error); 317} 318 319static int 320exynos4210_bus_ipend(struct uart_softc *sc) 321{ 322 uint32_t ints; 323 uint32_t txempty, rxready; 324 int reg; 325 int ipend; 326 327 uart_lock(sc->sc_hwmtx); 328 ints = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP); 329 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP, ints); 330 331 txempty = (1 << 2); 332 rxready = (1 << 0); 333 334 ipend = 0; 335 if ((ints & txempty) > 0) { 336 if (sc->sc_txbusy != 0) 337 ipend |= SER_INT_TXIDLE; 338 339 /* mask TX interrupt */ 340 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, 341 SSCOM_UINTM); 342 reg |= (1 << 2); 343 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, 344 SSCOM_UINTM, reg); 345 } 346 347 if ((ints & rxready) > 0) { 348 ipend |= SER_INT_RXREADY; 349 } 350 351 uart_unlock(sc->sc_hwmtx); 352 return (ipend); 353} 354 355static int 356exynos4210_bus_flush(struct uart_softc *sc, int what) 357{ 358 359 return (0); 360} 361 362static int 363exynos4210_bus_getsig(struct uart_softc *sc) 364{ 365 366 return (0); 367} 368 369static int 370exynos4210_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 371{ 372 373 return (EINVAL); 374} 375 376static struct uart_class uart_exynos4210_class = { 377 "exynos4210 class", 378 exynos4210_methods, 379 1, 380 .uc_ops = &uart_exynos4210_ops, 381 .uc_range = 8, 382 .uc_rclk = 0,
| 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/conf.h> 36#include <sys/cons.h> 37#include <sys/tty.h> 38#include <sys/rman.h> 39#include <machine/bus.h> 40#include <machine/intr.h> 41 42#include <dev/uart/uart.h> 43#include <dev/uart/uart_cpu.h> 44#include <dev/uart/uart_cpu_fdt.h> 45#include <dev/uart/uart_bus.h> 46 47#include <arm/samsung/exynos/exynos_uart.h> 48 49#include "uart_if.h" 50 51#define DEF_CLK 100000000 52 53static int sscomspeed(long, long); 54static int exynos4210_uart_param(struct uart_bas *, int, int, int, int); 55 56/* 57 * Low-level UART interface. 58 */ 59static int exynos4210_probe(struct uart_bas *bas); 60static void exynos4210_init(struct uart_bas *bas, int, int, int, int); 61static void exynos4210_term(struct uart_bas *bas); 62static void exynos4210_putc(struct uart_bas *bas, int); 63static int exynos4210_rxready(struct uart_bas *bas); 64static int exynos4210_getc(struct uart_bas *bas, struct mtx *mtx); 65 66extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; 67 68static int 69sscomspeed(long speed, long frequency) 70{ 71 int x; 72 73 if (speed <= 0 || frequency <= 0) 74 return (-1); 75 x = (frequency / 16) / speed; 76 return (x-1); 77} 78 79static int 80exynos4210_uart_param(struct uart_bas *bas, int baudrate, int databits, 81 int stopbits, int parity) 82{ 83 int brd, ulcon; 84 85 ulcon = 0; 86 87 switch(databits) { 88 case 5: 89 ulcon |= ULCON_LENGTH_5; 90 break; 91 case 6: 92 ulcon |= ULCON_LENGTH_6; 93 break; 94 case 7: 95 ulcon |= ULCON_LENGTH_7; 96 break; 97 case 8: 98 ulcon |= ULCON_LENGTH_8; 99 break; 100 default: 101 return (EINVAL); 102 } 103 104 switch (parity) { 105 case UART_PARITY_NONE: 106 ulcon |= ULCON_PARITY_NONE; 107 break; 108 case UART_PARITY_ODD: 109 ulcon |= ULCON_PARITY_ODD; 110 break; 111 case UART_PARITY_EVEN: 112 ulcon |= ULCON_PARITY_EVEN; 113 break; 114 case UART_PARITY_MARK: 115 case UART_PARITY_SPACE: 116 default: 117 return (EINVAL); 118 } 119 120 if (stopbits == 2) 121 ulcon |= ULCON_STOP; 122 123 uart_setreg(bas, SSCOM_ULCON, ulcon); 124 125 brd = sscomspeed(baudrate, bas->rclk); 126 uart_setreg(bas, SSCOM_UBRDIV, brd); 127 128 return (0); 129} 130 131struct uart_ops uart_exynos4210_ops = { 132 .probe = exynos4210_probe, 133 .init = exynos4210_init, 134 .term = exynos4210_term, 135 .putc = exynos4210_putc, 136 .rxready = exynos4210_rxready, 137 .getc = exynos4210_getc, 138}; 139 140static int 141exynos4210_probe(struct uart_bas *bas) 142{ 143 144 return (0); 145} 146 147static void 148exynos4210_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, 149 int parity) 150{ 151 152 if (bas->rclk == 0) 153 bas->rclk = DEF_CLK; 154 155 KASSERT(bas->rclk != 0, ("exynos4210_init: Invalid rclk")); 156 157 uart_setreg(bas, SSCOM_UCON, 0); 158 uart_setreg(bas, SSCOM_UFCON, 159 UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 | 160 UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET | 161 UFCON_FIFO_ENABLE); 162 exynos4210_uart_param(bas, baudrate, databits, stopbits, parity); 163 164 /* Enable UART. */ 165 uart_setreg(bas, SSCOM_UCON, UCON_TXMODE_INT | UCON_RXMODE_INT | 166 UCON_TOINT); 167 uart_setreg(bas, SSCOM_UMCON, UMCON_RTS); 168} 169 170static void 171exynos4210_term(struct uart_bas *bas) 172{ 173 /* XXX */ 174} 175 176static void 177exynos4210_putc(struct uart_bas *bas, int c) 178{ 179 180 while ((bus_space_read_4(bas->bst, bas->bsh, SSCOM_UFSTAT) & 181 UFSTAT_TXFULL) == UFSTAT_TXFULL) 182 continue; 183 184 uart_setreg(bas, SSCOM_UTXH, c); 185} 186 187static int 188exynos4210_rxready(struct uart_bas *bas) 189{ 190 191 return ((uart_getreg(bas, SSCOM_UTRSTAT) & UTRSTAT_RXREADY) == 192 UTRSTAT_RXREADY); 193} 194 195static int 196exynos4210_getc(struct uart_bas *bas, struct mtx *mtx) 197{ 198 int utrstat; 199 200 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT); 201 while (!(utrstat & UTRSTAT_RXREADY)) { 202 utrstat = bus_space_read_1(bas->bst, bas->bsh, SSCOM_UTRSTAT); 203 continue; 204 } 205 206 return (bus_space_read_1(bas->bst, bas->bsh, SSCOM_URXH)); 207} 208 209static int exynos4210_bus_probe(struct uart_softc *sc); 210static int exynos4210_bus_attach(struct uart_softc *sc); 211static int exynos4210_bus_flush(struct uart_softc *, int); 212static int exynos4210_bus_getsig(struct uart_softc *); 213static int exynos4210_bus_ioctl(struct uart_softc *, int, intptr_t); 214static int exynos4210_bus_ipend(struct uart_softc *); 215static int exynos4210_bus_param(struct uart_softc *, int, int, int, int); 216static int exynos4210_bus_receive(struct uart_softc *); 217static int exynos4210_bus_setsig(struct uart_softc *, int); 218static int exynos4210_bus_transmit(struct uart_softc *); 219 220static kobj_method_t exynos4210_methods[] = { 221 KOBJMETHOD(uart_probe, exynos4210_bus_probe), 222 KOBJMETHOD(uart_attach, exynos4210_bus_attach), 223 KOBJMETHOD(uart_flush, exynos4210_bus_flush), 224 KOBJMETHOD(uart_getsig, exynos4210_bus_getsig), 225 KOBJMETHOD(uart_ioctl, exynos4210_bus_ioctl), 226 KOBJMETHOD(uart_ipend, exynos4210_bus_ipend), 227 KOBJMETHOD(uart_param, exynos4210_bus_param), 228 KOBJMETHOD(uart_receive, exynos4210_bus_receive), 229 KOBJMETHOD(uart_setsig, exynos4210_bus_setsig), 230 KOBJMETHOD(uart_transmit, exynos4210_bus_transmit), 231 232 {0, 0 } 233}; 234 235int 236exynos4210_bus_probe(struct uart_softc *sc) 237{ 238 239 sc->sc_txfifosz = 16; 240 sc->sc_rxfifosz = 16; 241 242 return (0); 243} 244 245static int 246exynos4210_bus_attach(struct uart_softc *sc) 247{ 248 249 sc->sc_hwiflow = 0; 250 sc->sc_hwoflow = 0; 251 252 return (0); 253} 254 255static int 256exynos4210_bus_transmit(struct uart_softc *sc) 257{ 258 int i; 259 int reg; 260 261 uart_lock(sc->sc_hwmtx); 262 263 for (i = 0; i < sc->sc_txdatasz; i++) { 264 exynos4210_putc(&sc->sc_bas, sc->sc_txbuf[i]); 265 uart_barrier(&sc->sc_bas); 266 } 267 268 sc->sc_txbusy = 1; 269 270 uart_unlock(sc->sc_hwmtx); 271 272 /* unmask TX interrupt */ 273 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM); 274 reg &= ~(1 << 2); 275 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTM, reg); 276 277 return (0); 278} 279 280static int 281exynos4210_bus_setsig(struct uart_softc *sc, int sig) 282{ 283 284 return (0); 285} 286 287static int 288exynos4210_bus_receive(struct uart_softc *sc) 289{ 290 struct uart_bas *bas; 291 292 bas = &sc->sc_bas; 293 while (bus_space_read_4(bas->bst, bas->bsh, 294 SSCOM_UFSTAT) & UFSTAT_RXCOUNT) 295 uart_rx_put(sc, uart_getreg(&sc->sc_bas, SSCOM_URXH)); 296 297 return (0); 298} 299 300static int 301exynos4210_bus_param(struct uart_softc *sc, int baudrate, int databits, 302 int stopbits, int parity) 303{ 304 int error; 305 306 if (sc->sc_bas.rclk == 0) 307 sc->sc_bas.rclk = DEF_CLK; 308 309 KASSERT(sc->sc_bas.rclk != 0, ("exynos4210_init: Invalid rclk")); 310 311 uart_lock(sc->sc_hwmtx); 312 error = exynos4210_uart_param(&sc->sc_bas, baudrate, databits, stopbits, 313 parity); 314 uart_unlock(sc->sc_hwmtx); 315 316 return (error); 317} 318 319static int 320exynos4210_bus_ipend(struct uart_softc *sc) 321{ 322 uint32_t ints; 323 uint32_t txempty, rxready; 324 int reg; 325 int ipend; 326 327 uart_lock(sc->sc_hwmtx); 328 ints = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP); 329 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, SSCOM_UINTP, ints); 330 331 txempty = (1 << 2); 332 rxready = (1 << 0); 333 334 ipend = 0; 335 if ((ints & txempty) > 0) { 336 if (sc->sc_txbusy != 0) 337 ipend |= SER_INT_TXIDLE; 338 339 /* mask TX interrupt */ 340 reg = bus_space_read_4(sc->sc_bas.bst, sc->sc_bas.bsh, 341 SSCOM_UINTM); 342 reg |= (1 << 2); 343 bus_space_write_4(sc->sc_bas.bst, sc->sc_bas.bsh, 344 SSCOM_UINTM, reg); 345 } 346 347 if ((ints & rxready) > 0) { 348 ipend |= SER_INT_RXREADY; 349 } 350 351 uart_unlock(sc->sc_hwmtx); 352 return (ipend); 353} 354 355static int 356exynos4210_bus_flush(struct uart_softc *sc, int what) 357{ 358 359 return (0); 360} 361 362static int 363exynos4210_bus_getsig(struct uart_softc *sc) 364{ 365 366 return (0); 367} 368 369static int 370exynos4210_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 371{ 372 373 return (EINVAL); 374} 375 376static struct uart_class uart_exynos4210_class = { 377 "exynos4210 class", 378 exynos4210_methods, 379 1, 380 .uc_ops = &uart_exynos4210_ops, 381 .uc_range = 8, 382 .uc_rclk = 0,
|