|
Line 0
Link Here
|
|
|
1 |
/*- |
| 2 |
* Copyright (c) 2018 Diane Bruce |
| 3 |
* |
| 4 |
* Redistribution and use in source and binary forms, with or without |
| 5 |
* modification, are permitted provided that the following conditions |
| 6 |
* are met: |
| 7 |
* 1. Redistributions of source code must retain the above copyright |
| 8 |
* notice, this list of conditions and the following disclaimer. |
| 9 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 10 |
* notice, this list of conditions and the following disclaimer in the |
| 11 |
* documentation and/or other materials provided with the distribution. |
| 12 |
* |
| 13 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 14 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 15 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 16 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 17 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 18 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 19 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 20 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 21 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 22 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 23 |
* SUCH DAMAGE. |
| 24 |
*/ |
| 25 |
|
| 26 |
/* |
| 27 |
* Based on uart_dev_pl011.c |
| 28 |
* Copyright (c) 2012 Semihalf. |
| 29 |
* All rights reserved. |
| 30 |
*/ |
| 31 |
/* |
| 32 |
* The mini Uart has the following features: |
| 33 |
* - 7 or 8 bit operation. |
| 34 |
* - 1 start and 1 stop bit. |
| 35 |
* - No parities. |
| 36 |
* - Break generation. |
| 37 |
* - 8 symbols deep FIFOs for receive and transmit. |
| 38 |
* - SW controlled RTS, SW readable CTS. |
| 39 |
* - Auto flow control with programmable FIFO level. |
| 40 |
* - 16550 like registers. |
| 41 |
* - Baudrate derived from system clock. |
| 42 |
* This is a mini UART and it does NOT have the following capabilities: |
| 43 |
* - Break detection |
| 44 |
* - Framing errors detection. |
| 45 |
* - Parity bit |
| 46 |
* - Receive Time-out interrupt |
| 47 |
* - DCD, DSR, DTR or RI signals. |
| 48 |
* The implemented UART is not a 16650 compatible UART However as far |
| 49 |
* as possible the first 8 control and status registers are laid out |
| 50 |
* like a 16550 UART. All 16550 register bits which are not supported can |
| 51 |
* be written but will be ignored and read back as 0. All control bits |
| 52 |
* for simple UART receive/transmit operations are available. |
| 53 |
*/ |
| 54 |
|
| 55 |
#include "opt_acpi.h" |
| 56 |
#include "opt_platform.h" |
| 57 |
|
| 58 |
#include <sys/cdefs.h> |
| 59 |
__FBSDID("$FreeBSD$"); |
| 60 |
|
| 61 |
#include <sys/param.h> |
| 62 |
#include <sys/systm.h> |
| 63 |
#include <sys/kernel.h> |
| 64 |
#include <sys/bus.h> |
| 65 |
|
| 66 |
#include <machine/bus.h> |
| 67 |
#include <machine/machdep.h> |
| 68 |
#include <machine/pcpu.h> |
| 69 |
|
| 70 |
#include <dev/uart/uart.h> |
| 71 |
#include <dev/uart/uart_cpu.h> |
| 72 |
#ifdef FDT |
| 73 |
#include <dev/uart/uart_cpu_fdt.h> |
| 74 |
#include <dev/ofw/ofw_bus.h> |
| 75 |
#endif |
| 76 |
#include <dev/uart/uart_bus.h> |
| 77 |
#include "uart_if.h" |
| 78 |
|
| 79 |
#ifdef DEV_ACPI |
| 80 |
#include <dev/uart/uart_cpu_acpi.h> |
| 81 |
#include <contrib/dev/acpica/include/acpi.h> |
| 82 |
#include <contrib/dev/acpica/include/accommon.h> |
| 83 |
#include <contrib/dev/acpica/include/actables.h> |
| 84 |
#endif |
| 85 |
|
| 86 |
#include <sys/kdb.h> |
| 87 |
|
| 88 |
#ifdef __aarch64__ |
| 89 |
#define IS_FDT (arm64_bus_method == ARM64_BUS_FDT) |
| 90 |
#elif defined(FDT) |
| 91 |
#define IS_FDT 1 |
| 92 |
#else |
| 93 |
#error Unsupported configuration |
| 94 |
#endif |
| 95 |
|
| 96 |
/* BCM2835 Micro UART registers and masks*/ |
| 97 |
#define AUX_MU_IO_REG 0x00 /* I/O register */ |
| 98 |
|
| 99 |
/* |
| 100 |
* According to errata bits 1 and 2 are swapped, |
| 101 |
* Also bits 2 and 3 are required to enable interrupts. |
| 102 |
*/ |
| 103 |
#define AUX_MU_IER_REG 0x01 |
| 104 |
#define IER_RXENABLE (1) |
| 105 |
#define IER_TXENABLE (1<<1) |
| 106 |
#define IER_REQUIRED (3<<2) |
| 107 |
#define IER_MASK_ALL (IER_TXENABLE|IER_RXENABLE) |
| 108 |
|
| 109 |
#define AUX_MU_IIR_REG 0x02 |
| 110 |
#define IIR_READY (1) |
| 111 |
#define IIR_TXREADY (1<<1) |
| 112 |
#define IIR_RXREADY (1<<2) |
| 113 |
#define IIR_CLEAR (3<<1) |
| 114 |
|
| 115 |
#define AUX_MU_LCR_REG 0x03 |
| 116 |
#define LCR_WLEN7 (0) |
| 117 |
#define LCR_WLEN8 (3) |
| 118 |
|
| 119 |
#define AUX_MU_MCR_REG 0x04 |
| 120 |
#define AUX_MCR_RTS (1<<1) |
| 121 |
|
| 122 |
#define AUX_MU_LSR_REG 0x05 |
| 123 |
#define LSR_RXREADY (1) |
| 124 |
#define LSR_OVRRUN (1<<1) |
| 125 |
#define LSR_TXEMPTY (1<<5) |
| 126 |
#define LSR_TXIDLE (1<<6) |
| 127 |
|
| 128 |
#define AUX_MU_MSR_REG 0x06 |
| 129 |
#define MSR_CTS (1<<5) |
| 130 |
|
| 131 |
#define AUX_MU_SCRATCH_REG 0x07 |
| 132 |
|
| 133 |
#define AUX_MU_CNTL_REG 0x08 |
| 134 |
#define CNTL_RXENAB (1) |
| 135 |
#define CNTL_TXENAB (1<<1) |
| 136 |
|
| 137 |
#define AUX_MU_STAT_REG 0x09 |
| 138 |
#define STAT_TX_SA (1<<1) |
| 139 |
#define STAT_RX_SA (1) |
| 140 |
|
| 141 |
#define AUX_MU_BAUD_REG 0x0a |
| 142 |
|
| 143 |
/* |
| 144 |
* FIXME: actual register size is SoC-dependent, we need to handle it |
| 145 |
*/ |
| 146 |
#define __uart_getreg(bas, reg) \ |
| 147 |
bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg)) |
| 148 |
#define __uart_setreg(bas, reg, value) \ |
| 149 |
bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value) |
| 150 |
|
| 151 |
/* |
| 152 |
* Low-level UART interface. |
| 153 |
*/ |
| 154 |
static int uart_mu_probe(struct uart_bas *bas); |
| 155 |
static void uart_mu_init(struct uart_bas *bas, int, int, int, int); |
| 156 |
static void uart_mu_term(struct uart_bas *bas); |
| 157 |
static void uart_mu_putc(struct uart_bas *bas, int); |
| 158 |
static int uart_mu_rxready(struct uart_bas *bas); |
| 159 |
static int uart_mu_getc(struct uart_bas *bas, struct mtx *); |
| 160 |
static uint64_t cpu_clock(void); |
| 161 |
|
| 162 |
static struct uart_ops uart_mu_ops = { |
| 163 |
.probe = uart_mu_probe, |
| 164 |
.init = uart_mu_init, |
| 165 |
.term = uart_mu_term, |
| 166 |
.putc = uart_mu_putc, |
| 167 |
.rxready = uart_mu_rxready, |
| 168 |
.getc = uart_mu_getc, |
| 169 |
}; |
| 170 |
|
| 171 |
static int |
| 172 |
uart_mu_probe(struct uart_bas *bas) |
| 173 |
{ |
| 174 |
|
| 175 |
return (0); |
| 176 |
} |
| 177 |
|
| 178 |
/* |
| 179 |
* According to the docs, the cpu clock is locked to 250Mhz when |
| 180 |
* the micro-uart is used |
| 181 |
*/ |
| 182 |
#define CPU_CLOCK 250000000 |
| 183 |
|
| 184 |
static uint64_t |
| 185 |
cpu_clock(void) |
| 186 |
{ |
| 187 |
struct pcpu *apcpu; |
| 188 |
|
| 189 |
apcpu = get_pcpu(); |
| 190 |
return (apcpu->pc_clock); |
| 191 |
} |
| 192 |
|
| 193 |
static void |
| 194 |
uart_mu_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, |
| 195 |
int parity) |
| 196 |
{ |
| 197 |
uint32_t line; |
| 198 |
uint32_t baud; |
| 199 |
|
| 200 |
/* |
| 201 |
* Zero all settings to make sure |
| 202 |
* UART is disabled and not configured |
| 203 |
*/ |
| 204 |
line = 0x0; |
| 205 |
__uart_setreg(bas, AUX_MU_CNTL_REG, line); |
| 206 |
|
| 207 |
/* As I know UART is disabled I can setup the line */ |
| 208 |
switch (databits) { |
| 209 |
case 7: |
| 210 |
line |= LCR_WLEN7; |
| 211 |
break; |
| 212 |
case 6: |
| 213 |
case 8: |
| 214 |
default: |
| 215 |
line |= LCR_WLEN8; |
| 216 |
break; |
| 217 |
} |
| 218 |
|
| 219 |
__uart_setreg(bas, AUX_MU_LCR_REG, line); |
| 220 |
|
| 221 |
/* See 2.2.1 BCM2835-ARM-Peripherals baudrate */ |
| 222 |
if (baudrate != 0) { |
| 223 |
baud = CPU_CLOCK / (8 * baudrate); |
| 224 |
/* XXX |
| 225 |
* baud = cpu_clock() / (8 * baudrate); |
| 226 |
*/ |
| 227 |
__uart_setreg(bas, AUX_MU_BAUD_REG, ((uint32_t)(baud & 0xFFFF))); |
| 228 |
} |
| 229 |
|
| 230 |
/* reenable UART */ |
| 231 |
__uart_setreg(bas, AUX_MU_CNTL_REG, CNTL_RXENAB|CNTL_TXENAB); |
| 232 |
} |
| 233 |
|
| 234 |
static void |
| 235 |
uart_mu_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, |
| 236 |
int parity) |
| 237 |
{ |
| 238 |
|
| 239 |
/* Mask all interrupts */ |
| 240 |
__uart_setreg(bas, AUX_MU_IER_REG, 0); |
| 241 |
uart_mu_param(bas, baudrate, databits, stopbits, parity); |
| 242 |
} |
| 243 |
|
| 244 |
static void |
| 245 |
uart_mu_term(struct uart_bas *bas) |
| 246 |
{ |
| 247 |
} |
| 248 |
|
| 249 |
static void |
| 250 |
uart_mu_putc(struct uart_bas *bas, int c) |
| 251 |
{ |
| 252 |
|
| 253 |
/* Wait when TX FIFO full. Push character otherwise. */ |
| 254 |
while ((__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_TXEMPTY) == 0) |
| 255 |
; |
| 256 |
__uart_setreg(bas, AUX_MU_IO_REG, c & 0xff); |
| 257 |
} |
| 258 |
|
| 259 |
static int |
| 260 |
uart_mu_rxready(struct uart_bas *bas) |
| 261 |
{ |
| 262 |
|
| 263 |
return ((__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_RXREADY) != 0); |
| 264 |
} |
| 265 |
|
| 266 |
static int |
| 267 |
uart_mu_getc(struct uart_bas *bas, struct mtx *hwmtx) |
| 268 |
{ |
| 269 |
int c; |
| 270 |
|
| 271 |
while(!uart_mu_rxready(bas)) |
| 272 |
; |
| 273 |
c = __uart_getreg(bas, AUX_MU_IO_REG) & 0xff; |
| 274 |
return (c); |
| 275 |
} |
| 276 |
|
| 277 |
/* |
| 278 |
* High-level UART interface. |
| 279 |
*/ |
| 280 |
struct uart_mu_softc { |
| 281 |
struct uart_softc bas; |
| 282 |
uint16_t aux_ier; /* Interrupt mask */ |
| 283 |
}; |
| 284 |
|
| 285 |
static int uart_mu_bus_attach(struct uart_softc *); |
| 286 |
static int uart_mu_bus_detach(struct uart_softc *); |
| 287 |
static int uart_mu_bus_flush(struct uart_softc *, int); |
| 288 |
static int uart_mu_bus_getsig(struct uart_softc *); |
| 289 |
static int uart_mu_bus_ioctl(struct uart_softc *, int, intptr_t); |
| 290 |
static int uart_mu_bus_ipend(struct uart_softc *); |
| 291 |
static int uart_mu_bus_param(struct uart_softc *, int, int, int, int); |
| 292 |
static int uart_mu_bus_probe(struct uart_softc *); |
| 293 |
static int uart_mu_bus_receive(struct uart_softc *); |
| 294 |
static int uart_mu_bus_setsig(struct uart_softc *, int); |
| 295 |
static int uart_mu_bus_transmit(struct uart_softc *); |
| 296 |
static void uart_mu_bus_grab(struct uart_softc *); |
| 297 |
static void uart_mu_bus_ungrab(struct uart_softc *); |
| 298 |
|
| 299 |
static kobj_method_t uart_mu_methods[] = { |
| 300 |
KOBJMETHOD(uart_attach, uart_mu_bus_attach), |
| 301 |
KOBJMETHOD(uart_detach, uart_mu_bus_detach), |
| 302 |
KOBJMETHOD(uart_flush, uart_mu_bus_flush), |
| 303 |
KOBJMETHOD(uart_getsig, uart_mu_bus_getsig), |
| 304 |
KOBJMETHOD(uart_ioctl, uart_mu_bus_ioctl), |
| 305 |
KOBJMETHOD(uart_ipend, uart_mu_bus_ipend), |
| 306 |
KOBJMETHOD(uart_param, uart_mu_bus_param), |
| 307 |
KOBJMETHOD(uart_probe, uart_mu_bus_probe), |
| 308 |
KOBJMETHOD(uart_receive, uart_mu_bus_receive), |
| 309 |
KOBJMETHOD(uart_setsig, uart_mu_bus_setsig), |
| 310 |
KOBJMETHOD(uart_transmit, uart_mu_bus_transmit), |
| 311 |
KOBJMETHOD(uart_grab, uart_mu_bus_grab), |
| 312 |
KOBJMETHOD(uart_ungrab, uart_mu_bus_ungrab), |
| 313 |
|
| 314 |
{ 0, 0 } |
| 315 |
}; |
| 316 |
|
| 317 |
static struct uart_class uart_mu_class = { |
| 318 |
"aux-uart", |
| 319 |
uart_mu_methods, |
| 320 |
sizeof(struct uart_mu_softc), |
| 321 |
.uc_ops = &uart_mu_ops, |
| 322 |
.uc_range = 0x48, |
| 323 |
.uc_rclk = 0, |
| 324 |
.uc_rshift = 2 |
| 325 |
}; |
| 326 |
|
| 327 |
#ifdef FDT |
| 328 |
static struct ofw_compat_data fdt_compat_data[] = { |
| 329 |
{"brcm,bcm2835-aux-uart" , (uintptr_t)&uart_mu_class}, |
| 330 |
{NULL, (uintptr_t)NULL}, |
| 331 |
}; |
| 332 |
UART_FDT_CLASS_AND_DEVICE(fdt_compat_data); |
| 333 |
#endif |
| 334 |
|
| 335 |
/* XXX Where should ACPI_DBG2_ARM_MU go? */ |
| 336 |
#ifdef DEV_ACPI |
| 337 |
static struct acpi_uart_compat_data acpi_compat_data[] = { |
| 338 |
#if 0 |
| 339 |
{"ARMHMU", &uart_mu_class, ACPI_DBG2_ARM_MU}, |
| 340 |
#endif |
| 341 |
{"ARMHMU", &uart_mu_class, ACPI_DBG2_ARM_SBSA_GENERIC}, |
| 342 |
{NULL, NULL, 0}, |
| 343 |
}; |
| 344 |
UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); |
| 345 |
#endif |
| 346 |
|
| 347 |
static int |
| 348 |
uart_mu_bus_attach(struct uart_softc *sc) |
| 349 |
{ |
| 350 |
struct uart_mu_softc *psc; |
| 351 |
struct uart_bas *bas; |
| 352 |
|
| 353 |
psc = (struct uart_mu_softc *)sc; |
| 354 |
bas = &sc->sc_bas; |
| 355 |
/* Clear interrupts */ |
| 356 |
__uart_setreg(bas, AUX_MU_IIR_REG, IIR_CLEAR); |
| 357 |
/* Enable interrupts */ |
| 358 |
psc->aux_ier = (IER_RXENABLE|IER_TXENABLE|IER_REQUIRED); |
| 359 |
__uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier); |
| 360 |
sc->sc_txbusy = 0; |
| 361 |
|
| 362 |
return (0); |
| 363 |
} |
| 364 |
|
| 365 |
static int |
| 366 |
uart_mu_bus_detach(struct uart_softc *sc) |
| 367 |
{ |
| 368 |
|
| 369 |
return (0); |
| 370 |
} |
| 371 |
|
| 372 |
static int |
| 373 |
uart_mu_bus_flush(struct uart_softc *sc, int what) |
| 374 |
{ |
| 375 |
|
| 376 |
return (0); |
| 377 |
} |
| 378 |
|
| 379 |
static int |
| 380 |
uart_mu_bus_getsig(struct uart_softc *sc) |
| 381 |
{ |
| 382 |
|
| 383 |
return (0); |
| 384 |
} |
| 385 |
|
| 386 |
static int |
| 387 |
uart_mu_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) |
| 388 |
{ |
| 389 |
struct uart_bas *bas; |
| 390 |
int error; |
| 391 |
|
| 392 |
bas = &sc->sc_bas; |
| 393 |
error = 0; |
| 394 |
uart_lock(sc->sc_hwmtx); |
| 395 |
switch (request) { |
| 396 |
case UART_IOCTL_BREAK: |
| 397 |
break; |
| 398 |
case UART_IOCTL_BAUD: |
| 399 |
*(int*)data = 115200; |
| 400 |
break; |
| 401 |
default: |
| 402 |
error = EINVAL; |
| 403 |
break; |
| 404 |
} |
| 405 |
uart_unlock(sc->sc_hwmtx); |
| 406 |
|
| 407 |
return (error); |
| 408 |
} |
| 409 |
|
| 410 |
static int |
| 411 |
uart_mu_bus_ipend(struct uart_softc *sc) |
| 412 |
{ |
| 413 |
struct uart_mu_softc *psc; |
| 414 |
struct uart_bas *bas; |
| 415 |
uint32_t ints; |
| 416 |
int ipend; |
| 417 |
|
| 418 |
psc = (struct uart_mu_softc *)sc; |
| 419 |
bas = &sc->sc_bas; |
| 420 |
|
| 421 |
uart_lock(sc->sc_hwmtx); |
| 422 |
ints = __uart_getreg(bas, AUX_MU_IIR_REG); |
| 423 |
ipend = 0; |
| 424 |
|
| 425 |
/* |
| 426 |
* According to docs only one of IIR_RXREADY |
| 427 |
* or IIR_TXREADY are valid eg. Only one or the other. |
| 428 |
*/ |
| 429 |
if (ints & IIR_RXREADY) { |
| 430 |
ipend |= SER_INT_RXREADY; |
| 431 |
} else if (ints & IIR_TXREADY) { |
| 432 |
if (__uart_getreg(bas, AUX_MU_LSR_REG) & LSR_TXIDLE) { |
| 433 |
if (sc->sc_txbusy) |
| 434 |
ipend |= SER_INT_TXIDLE; |
| 435 |
|
| 436 |
/* Disable TX interrupt */ |
| 437 |
__uart_setreg(bas, AUX_MU_IER_REG, |
| 438 |
psc->aux_ier & ~IER_TXENABLE); |
| 439 |
} |
| 440 |
} |
| 441 |
|
| 442 |
uart_unlock(sc->sc_hwmtx); |
| 443 |
|
| 444 |
return (ipend); |
| 445 |
} |
| 446 |
|
| 447 |
static int |
| 448 |
uart_mu_bus_param(struct uart_softc *sc, int baudrate, int databits, |
| 449 |
int stopbits, int parity) |
| 450 |
{ |
| 451 |
|
| 452 |
uart_lock(sc->sc_hwmtx); |
| 453 |
uart_mu_param(&sc->sc_bas, baudrate, databits, stopbits, parity); |
| 454 |
uart_unlock(sc->sc_hwmtx); |
| 455 |
|
| 456 |
return (0); |
| 457 |
} |
| 458 |
|
| 459 |
static int |
| 460 |
uart_mu_bus_probe(struct uart_softc *sc) |
| 461 |
{ |
| 462 |
|
| 463 |
/* MU always has 8 byte deep fifo */ |
| 464 |
sc->sc_rxfifosz = 8; |
| 465 |
sc->sc_txfifosz = 8; |
| 466 |
device_set_desc(sc->sc_dev, "BCM2835 Mini-UART"); |
| 467 |
|
| 468 |
return (0); |
| 469 |
} |
| 470 |
|
| 471 |
static int |
| 472 |
uart_mu_bus_receive(struct uart_softc *sc) |
| 473 |
{ |
| 474 |
struct uart_mu_softc *psc; |
| 475 |
struct uart_bas *bas; |
| 476 |
uint32_t lsr, xc; |
| 477 |
int rx; |
| 478 |
|
| 479 |
bas = &sc->sc_bas; |
| 480 |
uart_lock(sc->sc_hwmtx); |
| 481 |
psc = (struct uart_mu_softc *)sc; |
| 482 |
|
| 483 |
lsr = __uart_getreg(bas, AUX_MU_LSR_REG); |
| 484 |
while (lsr & LSR_RXREADY) { |
| 485 |
xc = __uart_getreg(bas, AUX_MU_IO_REG); |
| 486 |
rx = xc & 0xff; |
| 487 |
if (uart_rx_full(sc)) { |
| 488 |
sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; |
| 489 |
break; |
| 490 |
} |
| 491 |
uart_rx_put(sc, rx); |
| 492 |
lsr = __uart_getreg(bas, AUX_MU_LSR_REG); |
| 493 |
} |
| 494 |
uart_unlock(sc->sc_hwmtx); |
| 495 |
|
| 496 |
return (0); |
| 497 |
} |
| 498 |
|
| 499 |
static int |
| 500 |
uart_mu_bus_setsig(struct uart_softc *sc, int sig) |
| 501 |
{ |
| 502 |
|
| 503 |
return (0); |
| 504 |
} |
| 505 |
|
| 506 |
static int |
| 507 |
uart_mu_bus_transmit(struct uart_softc *sc) |
| 508 |
{ |
| 509 |
struct uart_mu_softc *psc; |
| 510 |
struct uart_bas *bas; |
| 511 |
int i; |
| 512 |
|
| 513 |
psc = (struct uart_mu_softc *)sc; |
| 514 |
bas = &sc->sc_bas; |
| 515 |
uart_lock(sc->sc_hwmtx); |
| 516 |
|
| 517 |
for (i = 0; i < sc->sc_txdatasz; i++) { |
| 518 |
__uart_setreg(bas, AUX_MU_IO_REG, sc->sc_txbuf[i] & 0xff); |
| 519 |
uart_barrier(bas); |
| 520 |
} |
| 521 |
|
| 522 |
/* Mark busy and enable TX interrupt */ |
| 523 |
sc->sc_txbusy = 1; |
| 524 |
__uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier); |
| 525 |
|
| 526 |
uart_unlock(sc->sc_hwmtx); |
| 527 |
|
| 528 |
return (0); |
| 529 |
} |
| 530 |
|
| 531 |
static void |
| 532 |
uart_mu_bus_grab(struct uart_softc *sc) |
| 533 |
{ |
| 534 |
struct uart_mu_softc *psc; |
| 535 |
struct uart_bas *bas; |
| 536 |
|
| 537 |
psc = (struct uart_mu_softc *)sc; |
| 538 |
bas = &sc->sc_bas; |
| 539 |
|
| 540 |
/* Disable interrupts on switch to polling */ |
| 541 |
uart_lock(sc->sc_hwmtx); |
| 542 |
__uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier &~IER_MASK_ALL); |
| 543 |
uart_unlock(sc->sc_hwmtx); |
| 544 |
} |
| 545 |
|
| 546 |
static void |
| 547 |
uart_mu_bus_ungrab(struct uart_softc *sc) |
| 548 |
{ |
| 549 |
struct uart_mu_softc *psc; |
| 550 |
struct uart_bas *bas; |
| 551 |
|
| 552 |
psc = (struct uart_mu_softc *)sc; |
| 553 |
bas = &sc->sc_bas; |
| 554 |
|
| 555 |
/* Switch to using interrupts while not grabbed */ |
| 556 |
uart_lock(sc->sc_hwmtx); |
| 557 |
__uart_setreg(bas, AUX_MU_CNTL_REG, CNTL_RXENAB|CNTL_TXENAB); |
| 558 |
__uart_setreg(bas, AUX_MU_IER_REG, psc->aux_ier); |
| 559 |
uart_unlock(sc->sc_hwmtx); |
| 560 |
} |