1098ca2bdSWarner Losh /*- 22ae4f1fdSMarcel Moolenaar * Copyright (c) 2004 Marcel Moolenaar 32ae4f1fdSMarcel Moolenaar * All rights reserved. 42ae4f1fdSMarcel Moolenaar * 52ae4f1fdSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 62ae4f1fdSMarcel Moolenaar * modification, are permitted provided that the following conditions 72ae4f1fdSMarcel Moolenaar * are met: 82ae4f1fdSMarcel Moolenaar * 92ae4f1fdSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 102ae4f1fdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 112ae4f1fdSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 122ae4f1fdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 132ae4f1fdSMarcel Moolenaar * documentation and/or other materials provided with the distribution. 142ae4f1fdSMarcel Moolenaar * 152ae4f1fdSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 162ae4f1fdSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 172ae4f1fdSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 182ae4f1fdSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 192ae4f1fdSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 202ae4f1fdSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 212ae4f1fdSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 222ae4f1fdSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 232ae4f1fdSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 242ae4f1fdSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 252ae4f1fdSMarcel Moolenaar */ 262ae4f1fdSMarcel Moolenaar 272ae4f1fdSMarcel Moolenaar #include <sys/cdefs.h> 282ae4f1fdSMarcel Moolenaar __FBSDID("$FreeBSD$"); 292ae4f1fdSMarcel Moolenaar 302ae4f1fdSMarcel Moolenaar #include <sys/param.h> 312ae4f1fdSMarcel Moolenaar #include <sys/systm.h> 322ae4f1fdSMarcel Moolenaar #include <sys/bus.h> 332ae4f1fdSMarcel Moolenaar 342ae4f1fdSMarcel Moolenaar #include <machine/bus.h> 352ae4f1fdSMarcel Moolenaar #include <machine/vmparam.h> 362ae4f1fdSMarcel Moolenaar 372ae4f1fdSMarcel Moolenaar #include <dev/uart/uart.h> 382ae4f1fdSMarcel Moolenaar #include <dev/uart/uart_cpu.h> 392ae4f1fdSMarcel Moolenaar 402ae4f1fdSMarcel Moolenaar #define UART_TAG_BR 0 412ae4f1fdSMarcel Moolenaar #define UART_TAG_CH 1 422ae4f1fdSMarcel Moolenaar #define UART_TAG_DB 2 432ae4f1fdSMarcel Moolenaar #define UART_TAG_DT 3 442ae4f1fdSMarcel Moolenaar #define UART_TAG_IO 4 452ae4f1fdSMarcel Moolenaar #define UART_TAG_MM 5 462ae4f1fdSMarcel Moolenaar #define UART_TAG_PA 6 472ae4f1fdSMarcel Moolenaar #define UART_TAG_RS 7 482ae4f1fdSMarcel Moolenaar #define UART_TAG_SB 8 492ae4f1fdSMarcel Moolenaar #define UART_TAG_XO 9 502ae4f1fdSMarcel Moolenaar 512ae4f1fdSMarcel Moolenaar static bus_addr_t 522ae4f1fdSMarcel Moolenaar uart_parse_addr(__const char **p) 532ae4f1fdSMarcel Moolenaar { 542ae4f1fdSMarcel Moolenaar return (strtoul(*p, (char**)(uintptr_t)p, 0)); 552ae4f1fdSMarcel Moolenaar } 562ae4f1fdSMarcel Moolenaar 572ae4f1fdSMarcel Moolenaar static long 582ae4f1fdSMarcel Moolenaar uart_parse_long(__const char **p) 592ae4f1fdSMarcel Moolenaar { 602ae4f1fdSMarcel Moolenaar return (strtol(*p, (char**)(uintptr_t)p, 0)); 612ae4f1fdSMarcel Moolenaar } 622ae4f1fdSMarcel Moolenaar 632ae4f1fdSMarcel Moolenaar static int 642ae4f1fdSMarcel Moolenaar uart_parse_parity(__const char **p) 652ae4f1fdSMarcel Moolenaar { 662ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "even", 4)) { 672ae4f1fdSMarcel Moolenaar *p += 4; 682ae4f1fdSMarcel Moolenaar return UART_PARITY_EVEN; 692ae4f1fdSMarcel Moolenaar } 702ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "mark", 4)) { 712ae4f1fdSMarcel Moolenaar *p += 4; 722ae4f1fdSMarcel Moolenaar return UART_PARITY_MARK; 732ae4f1fdSMarcel Moolenaar } 742ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "none", 4)) { 752ae4f1fdSMarcel Moolenaar *p += 4; 762ae4f1fdSMarcel Moolenaar return UART_PARITY_NONE; 772ae4f1fdSMarcel Moolenaar } 782ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "odd", 3)) { 792ae4f1fdSMarcel Moolenaar *p += 3; 802ae4f1fdSMarcel Moolenaar return UART_PARITY_ODD; 812ae4f1fdSMarcel Moolenaar } 822ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "space", 5)) { 832ae4f1fdSMarcel Moolenaar *p += 5; 842ae4f1fdSMarcel Moolenaar return UART_PARITY_SPACE; 852ae4f1fdSMarcel Moolenaar } 862ae4f1fdSMarcel Moolenaar return (-1); 872ae4f1fdSMarcel Moolenaar } 882ae4f1fdSMarcel Moolenaar 892ae4f1fdSMarcel Moolenaar static int 902ae4f1fdSMarcel Moolenaar uart_parse_tag(__const char **p) 912ae4f1fdSMarcel Moolenaar { 922ae4f1fdSMarcel Moolenaar int tag; 932ae4f1fdSMarcel Moolenaar 942ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'b' && (*p)[1] == 'r') { 952ae4f1fdSMarcel Moolenaar tag = UART_TAG_BR; 962ae4f1fdSMarcel Moolenaar goto out; 972ae4f1fdSMarcel Moolenaar } 982ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'c' && (*p)[1] == 'h') { 992ae4f1fdSMarcel Moolenaar tag = UART_TAG_CH; 1002ae4f1fdSMarcel Moolenaar goto out; 1012ae4f1fdSMarcel Moolenaar } 1022ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'd' && (*p)[1] == 'b') { 1032ae4f1fdSMarcel Moolenaar tag = UART_TAG_DB; 1042ae4f1fdSMarcel Moolenaar goto out; 1052ae4f1fdSMarcel Moolenaar } 1062ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'd' && (*p)[1] == 't') { 1072ae4f1fdSMarcel Moolenaar tag = UART_TAG_DT; 1082ae4f1fdSMarcel Moolenaar goto out; 1092ae4f1fdSMarcel Moolenaar } 1102ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'i' && (*p)[1] == 'o') { 1112ae4f1fdSMarcel Moolenaar tag = UART_TAG_IO; 1122ae4f1fdSMarcel Moolenaar goto out; 1132ae4f1fdSMarcel Moolenaar } 1142ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'm' && (*p)[1] == 'm') { 1152ae4f1fdSMarcel Moolenaar tag = UART_TAG_MM; 1162ae4f1fdSMarcel Moolenaar goto out; 1172ae4f1fdSMarcel Moolenaar } 1182ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'p' && (*p)[1] == 'a') { 1192ae4f1fdSMarcel Moolenaar tag = UART_TAG_PA; 1202ae4f1fdSMarcel Moolenaar goto out; 1212ae4f1fdSMarcel Moolenaar } 1222ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'r' && (*p)[1] == 's') { 1232ae4f1fdSMarcel Moolenaar tag = UART_TAG_RS; 1242ae4f1fdSMarcel Moolenaar goto out; 1252ae4f1fdSMarcel Moolenaar } 1262ae4f1fdSMarcel Moolenaar if ((*p)[0] == 's' && (*p)[1] == 'b') { 1272ae4f1fdSMarcel Moolenaar tag = UART_TAG_SB; 1282ae4f1fdSMarcel Moolenaar goto out; 1292ae4f1fdSMarcel Moolenaar } 1302ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'x' && (*p)[1] == 'o') { 1312ae4f1fdSMarcel Moolenaar tag = UART_TAG_XO; 1322ae4f1fdSMarcel Moolenaar goto out; 1332ae4f1fdSMarcel Moolenaar } 1342ae4f1fdSMarcel Moolenaar return (-1); 1352ae4f1fdSMarcel Moolenaar 1362ae4f1fdSMarcel Moolenaar out: 1372ae4f1fdSMarcel Moolenaar *p += 2; 1382ae4f1fdSMarcel Moolenaar if ((*p)[0] != ':') 1392ae4f1fdSMarcel Moolenaar return (-1); 1402ae4f1fdSMarcel Moolenaar (*p)++; 1412ae4f1fdSMarcel Moolenaar return (tag); 1422ae4f1fdSMarcel Moolenaar } 1432ae4f1fdSMarcel Moolenaar 1442ae4f1fdSMarcel Moolenaar /* 1452ae4f1fdSMarcel Moolenaar * Parse a device specification. The specification is a list of attributes 1462ae4f1fdSMarcel Moolenaar * seperated by commas. Each attribute is a tag-value pair with the tag and 1472ae4f1fdSMarcel Moolenaar * value seperated by a colon. Supported tags are: 1482ae4f1fdSMarcel Moolenaar * 1492ae4f1fdSMarcel Moolenaar * br = Baudrate 1502ae4f1fdSMarcel Moolenaar * ch = Channel 1512ae4f1fdSMarcel Moolenaar * db = Data bits 1522ae4f1fdSMarcel Moolenaar * dt = Device type 1532ae4f1fdSMarcel Moolenaar * io = I/O port address 1542ae4f1fdSMarcel Moolenaar * mm = Memory mapped I/O address 1552ae4f1fdSMarcel Moolenaar * pa = Parity 1562ae4f1fdSMarcel Moolenaar * rs = Register shift 1572ae4f1fdSMarcel Moolenaar * sb = Stopbits 1582ae4f1fdSMarcel Moolenaar * xo = Device clock (xtal oscillator) 1592ae4f1fdSMarcel Moolenaar * 1602ae4f1fdSMarcel Moolenaar * The io and mm tags are mutually exclusive. 1612ae4f1fdSMarcel Moolenaar */ 1622ae4f1fdSMarcel Moolenaar 1632ae4f1fdSMarcel Moolenaar int 1642ae4f1fdSMarcel Moolenaar uart_getenv(int devtype, struct uart_devinfo *di) 1652ae4f1fdSMarcel Moolenaar { 1662ae4f1fdSMarcel Moolenaar __const char *spec; 1672ae4f1fdSMarcel Moolenaar bus_addr_t addr = ~0U; 1682ae4f1fdSMarcel Moolenaar 1692ae4f1fdSMarcel Moolenaar /* 1702ae4f1fdSMarcel Moolenaar * Check the environment variables "hw.uart.console" and 1712ae4f1fdSMarcel Moolenaar * "hw.uart.dbgport". These variables, when present, specify 1722ae4f1fdSMarcel Moolenaar * which UART port is to be used as serial console or debug 1732ae4f1fdSMarcel Moolenaar * port (resp). 1742ae4f1fdSMarcel Moolenaar */ 1752ae4f1fdSMarcel Moolenaar if (devtype == UART_DEV_CONSOLE) 1762ae4f1fdSMarcel Moolenaar spec = getenv("hw.uart.console"); 1772ae4f1fdSMarcel Moolenaar else if (devtype == UART_DEV_DBGPORT) 1782ae4f1fdSMarcel Moolenaar spec = getenv("hw.uart.dbgport"); 1792ae4f1fdSMarcel Moolenaar else 180139a40ebSMarcel Moolenaar spec = NULL; 181139a40ebSMarcel Moolenaar if (spec == NULL) 1822ae4f1fdSMarcel Moolenaar return (ENXIO); 1832ae4f1fdSMarcel Moolenaar 1842ae4f1fdSMarcel Moolenaar /* Set defaults. */ 1852ae4f1fdSMarcel Moolenaar di->ops = uart_ns8250_ops; 1862ae4f1fdSMarcel Moolenaar di->bas.chan = 0; 1872ae4f1fdSMarcel Moolenaar di->bas.regshft = 0; 1882ae4f1fdSMarcel Moolenaar di->bas.rclk = 0; 1892ae4f1fdSMarcel Moolenaar di->baudrate = 0; 1902ae4f1fdSMarcel Moolenaar di->databits = 8; 1912ae4f1fdSMarcel Moolenaar di->stopbits = 1; 1922ae4f1fdSMarcel Moolenaar di->parity = UART_PARITY_NONE; 1932ae4f1fdSMarcel Moolenaar 1942ae4f1fdSMarcel Moolenaar /* Parse the attributes. */ 1952ae4f1fdSMarcel Moolenaar while (1) { 1962ae4f1fdSMarcel Moolenaar switch (uart_parse_tag(&spec)) { 1972ae4f1fdSMarcel Moolenaar case UART_TAG_BR: 1982ae4f1fdSMarcel Moolenaar di->baudrate = uart_parse_long(&spec); 1992ae4f1fdSMarcel Moolenaar break; 2002ae4f1fdSMarcel Moolenaar case UART_TAG_CH: 2012ae4f1fdSMarcel Moolenaar di->bas.chan = uart_parse_long(&spec); 2022ae4f1fdSMarcel Moolenaar break; 2032ae4f1fdSMarcel Moolenaar case UART_TAG_DB: 2042ae4f1fdSMarcel Moolenaar di->databits = uart_parse_long(&spec); 2052ae4f1fdSMarcel Moolenaar break; 2062ae4f1fdSMarcel Moolenaar case UART_TAG_DT: 2072ae4f1fdSMarcel Moolenaar return (EINVAL); /* XXX not yet implemented. */ 2082ae4f1fdSMarcel Moolenaar break; 2092ae4f1fdSMarcel Moolenaar case UART_TAG_IO: 2102ae4f1fdSMarcel Moolenaar di->bas.bst = uart_bus_space_io; 2112ae4f1fdSMarcel Moolenaar addr = uart_parse_addr(&spec); 2122ae4f1fdSMarcel Moolenaar break; 2132ae4f1fdSMarcel Moolenaar case UART_TAG_MM: 2142ae4f1fdSMarcel Moolenaar di->bas.bst = uart_bus_space_mem; 2152ae4f1fdSMarcel Moolenaar addr = uart_parse_addr(&spec); 2162ae4f1fdSMarcel Moolenaar break; 2172ae4f1fdSMarcel Moolenaar case UART_TAG_PA: 2182ae4f1fdSMarcel Moolenaar di->parity = uart_parse_parity(&spec); 2192ae4f1fdSMarcel Moolenaar break; 2202ae4f1fdSMarcel Moolenaar case UART_TAG_RS: 2212ae4f1fdSMarcel Moolenaar di->bas.regshft = uart_parse_long(&spec); 2222ae4f1fdSMarcel Moolenaar break; 2232ae4f1fdSMarcel Moolenaar case UART_TAG_SB: 2242ae4f1fdSMarcel Moolenaar di->stopbits = uart_parse_long(&spec); 2252ae4f1fdSMarcel Moolenaar break; 2262ae4f1fdSMarcel Moolenaar case UART_TAG_XO: 2272ae4f1fdSMarcel Moolenaar di->bas.rclk = uart_parse_long(&spec); 2282ae4f1fdSMarcel Moolenaar break; 2292ae4f1fdSMarcel Moolenaar default: 2302ae4f1fdSMarcel Moolenaar return (EINVAL); 2312ae4f1fdSMarcel Moolenaar } 2322ae4f1fdSMarcel Moolenaar if (*spec == '\0') 2332ae4f1fdSMarcel Moolenaar break; 2342ae4f1fdSMarcel Moolenaar if (*spec != ',') 2352ae4f1fdSMarcel Moolenaar return (EINVAL); 2362ae4f1fdSMarcel Moolenaar spec++; 2372ae4f1fdSMarcel Moolenaar } 2382ae4f1fdSMarcel Moolenaar 2392ae4f1fdSMarcel Moolenaar /* 2402ae4f1fdSMarcel Moolenaar * If we still have an invalid address, the specification must be 2412ae4f1fdSMarcel Moolenaar * missing an I/O port or memory address. We don't like that. 2422ae4f1fdSMarcel Moolenaar */ 2432ae4f1fdSMarcel Moolenaar if (addr == ~0U) 2442ae4f1fdSMarcel Moolenaar return (EINVAL); 245ecf4dc25SMarcel Moolenaar 246ecf4dc25SMarcel Moolenaar /* 247ecf4dc25SMarcel Moolenaar * Accept only the well-known baudrates. Any invalid baudrate 248ecf4dc25SMarcel Moolenaar * is silently replaced with a 0-valued baudrate. The 0 baudrate 249ecf4dc25SMarcel Moolenaar * has special meaning. It means that we're not supposed to 250ecf4dc25SMarcel Moolenaar * program the baudrate and simply communicate with whatever 251ecf4dc25SMarcel Moolenaar * speed the hardware is currently programmed for. 252ecf4dc25SMarcel Moolenaar */ 253ecf4dc25SMarcel Moolenaar if (di->baudrate >= 19200) { 254ecf4dc25SMarcel Moolenaar if (di->baudrate % 19200) 255ecf4dc25SMarcel Moolenaar di->baudrate = 0; 256ecf4dc25SMarcel Moolenaar } else if (di->baudrate >= 1200) { 257ecf4dc25SMarcel Moolenaar if (di->baudrate % 1200) 258ecf4dc25SMarcel Moolenaar di->baudrate = 0; 259ecf4dc25SMarcel Moolenaar } else if (di->baudrate > 0) { 260ecf4dc25SMarcel Moolenaar if (di->baudrate % 75) 261ecf4dc25SMarcel Moolenaar di->baudrate = 0; 262ecf4dc25SMarcel Moolenaar } else 263ecf4dc25SMarcel Moolenaar di->baudrate = 0; 264ecf4dc25SMarcel Moolenaar 2652ae4f1fdSMarcel Moolenaar /* XXX the size of the mapping depends on the UART class. */ 2662ae4f1fdSMarcel Moolenaar if (bus_space_map(di->bas.bst, addr, 8, 0, &di->bas.bsh) != 0) 2672ae4f1fdSMarcel Moolenaar return (EINVAL); 2682ae4f1fdSMarcel Moolenaar return (0); 2692ae4f1fdSMarcel Moolenaar } 270