1098ca2bdSWarner Losh /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 42ae4f1fdSMarcel Moolenaar * Copyright (c) 2004 Marcel Moolenaar 52ae4f1fdSMarcel Moolenaar * All rights reserved. 62ae4f1fdSMarcel Moolenaar * 72ae4f1fdSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 82ae4f1fdSMarcel Moolenaar * modification, are permitted provided that the following conditions 92ae4f1fdSMarcel Moolenaar * are met: 102ae4f1fdSMarcel Moolenaar * 112ae4f1fdSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 122ae4f1fdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 132ae4f1fdSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 142ae4f1fdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 152ae4f1fdSMarcel Moolenaar * documentation and/or other materials provided with the distribution. 162ae4f1fdSMarcel Moolenaar * 172ae4f1fdSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 182ae4f1fdSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 192ae4f1fdSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 202ae4f1fdSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 212ae4f1fdSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 222ae4f1fdSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232ae4f1fdSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242ae4f1fdSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252ae4f1fdSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 262ae4f1fdSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272ae4f1fdSMarcel Moolenaar */ 282ae4f1fdSMarcel Moolenaar 292ae4f1fdSMarcel Moolenaar #include <sys/cdefs.h> 302ae4f1fdSMarcel Moolenaar __FBSDID("$FreeBSD$"); 312ae4f1fdSMarcel Moolenaar 322ae4f1fdSMarcel Moolenaar #include <sys/param.h> 332ae4f1fdSMarcel Moolenaar #include <sys/systm.h> 342ae4f1fdSMarcel Moolenaar #include <sys/bus.h> 352ae4f1fdSMarcel Moolenaar 362ae4f1fdSMarcel Moolenaar #include <machine/bus.h> 372ae4f1fdSMarcel Moolenaar #include <machine/vmparam.h> 382ae4f1fdSMarcel Moolenaar 392ae4f1fdSMarcel Moolenaar #include <dev/uart/uart.h> 402ae4f1fdSMarcel Moolenaar #include <dev/uart/uart_cpu.h> 412ae4f1fdSMarcel Moolenaar 422ae4f1fdSMarcel Moolenaar #define UART_TAG_BR 0 432ae4f1fdSMarcel Moolenaar #define UART_TAG_CH 1 442ae4f1fdSMarcel Moolenaar #define UART_TAG_DB 2 452ae4f1fdSMarcel Moolenaar #define UART_TAG_DT 3 462ae4f1fdSMarcel Moolenaar #define UART_TAG_IO 4 472ae4f1fdSMarcel Moolenaar #define UART_TAG_MM 5 482ae4f1fdSMarcel Moolenaar #define UART_TAG_PA 6 492ae4f1fdSMarcel Moolenaar #define UART_TAG_RS 7 502ae4f1fdSMarcel Moolenaar #define UART_TAG_SB 8 512ae4f1fdSMarcel Moolenaar #define UART_TAG_XO 9 52*f30f0f2bSMatt Macy #define UART_TAG_BD 10 532ae4f1fdSMarcel Moolenaar 54f8100ce2SMarcel Moolenaar static struct uart_class *uart_classes[] = { 55f8100ce2SMarcel Moolenaar &uart_ns8250_class, 56f8100ce2SMarcel Moolenaar &uart_sab82532_class, 57f8100ce2SMarcel Moolenaar &uart_z8530_class, 5832803452SYoshihiro Takahashi #if defined(__arm__) 595d490515SAleksandr Rybalko &uart_s3c2410_class, 6032803452SYoshihiro Takahashi #endif 61f8100ce2SMarcel Moolenaar }; 62f8100ce2SMarcel Moolenaar 632ae4f1fdSMarcel Moolenaar static bus_addr_t 64f6ab8089SEd Schouten uart_parse_addr(const char **p) 652ae4f1fdSMarcel Moolenaar { 662ae4f1fdSMarcel Moolenaar return (strtoul(*p, (char**)(uintptr_t)p, 0)); 672ae4f1fdSMarcel Moolenaar } 682ae4f1fdSMarcel Moolenaar 69f8100ce2SMarcel Moolenaar static struct uart_class * 70f6ab8089SEd Schouten uart_parse_class(struct uart_class *class, const char **p) 71f8100ce2SMarcel Moolenaar { 72f8100ce2SMarcel Moolenaar struct uart_class *uc; 73f8100ce2SMarcel Moolenaar const char *nm; 74f8100ce2SMarcel Moolenaar size_t len; 75f8100ce2SMarcel Moolenaar u_int i; 76f8100ce2SMarcel Moolenaar 778dfea464SPedro F. Giffuni for (i = 0; i < nitems(uart_classes); i++) { 78f8100ce2SMarcel Moolenaar uc = uart_classes[i]; 79f8100ce2SMarcel Moolenaar nm = uart_getname(uc); 80f8100ce2SMarcel Moolenaar if (nm == NULL || *nm == '\0') 81f8100ce2SMarcel Moolenaar continue; 82f8100ce2SMarcel Moolenaar len = strlen(nm); 83f8100ce2SMarcel Moolenaar if (strncmp(nm, *p, len) == 0) { 84f8100ce2SMarcel Moolenaar *p += len; 85f8100ce2SMarcel Moolenaar return (uc); 86f8100ce2SMarcel Moolenaar } 87f8100ce2SMarcel Moolenaar } 88f8100ce2SMarcel Moolenaar return (class); 89f8100ce2SMarcel Moolenaar } 90f8100ce2SMarcel Moolenaar 912ae4f1fdSMarcel Moolenaar static long 92f6ab8089SEd Schouten uart_parse_long(const char **p) 932ae4f1fdSMarcel Moolenaar { 942ae4f1fdSMarcel Moolenaar return (strtol(*p, (char**)(uintptr_t)p, 0)); 952ae4f1fdSMarcel Moolenaar } 962ae4f1fdSMarcel Moolenaar 972ae4f1fdSMarcel Moolenaar static int 98f6ab8089SEd Schouten uart_parse_parity(const char **p) 992ae4f1fdSMarcel Moolenaar { 1002ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "even", 4)) { 1012ae4f1fdSMarcel Moolenaar *p += 4; 1022ae4f1fdSMarcel Moolenaar return UART_PARITY_EVEN; 1032ae4f1fdSMarcel Moolenaar } 1042ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "mark", 4)) { 1052ae4f1fdSMarcel Moolenaar *p += 4; 1062ae4f1fdSMarcel Moolenaar return UART_PARITY_MARK; 1072ae4f1fdSMarcel Moolenaar } 1082ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "none", 4)) { 1092ae4f1fdSMarcel Moolenaar *p += 4; 1102ae4f1fdSMarcel Moolenaar return UART_PARITY_NONE; 1112ae4f1fdSMarcel Moolenaar } 1122ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "odd", 3)) { 1132ae4f1fdSMarcel Moolenaar *p += 3; 1142ae4f1fdSMarcel Moolenaar return UART_PARITY_ODD; 1152ae4f1fdSMarcel Moolenaar } 1162ae4f1fdSMarcel Moolenaar if (!strncmp(*p, "space", 5)) { 1172ae4f1fdSMarcel Moolenaar *p += 5; 1182ae4f1fdSMarcel Moolenaar return UART_PARITY_SPACE; 1192ae4f1fdSMarcel Moolenaar } 1202ae4f1fdSMarcel Moolenaar return (-1); 1212ae4f1fdSMarcel Moolenaar } 1222ae4f1fdSMarcel Moolenaar 1232ae4f1fdSMarcel Moolenaar static int 124f6ab8089SEd Schouten uart_parse_tag(const char **p) 1252ae4f1fdSMarcel Moolenaar { 1262ae4f1fdSMarcel Moolenaar int tag; 1272ae4f1fdSMarcel Moolenaar 128*f30f0f2bSMatt Macy if ((*p)[0] == 'b' && (*p)[1] == 'd') { 129*f30f0f2bSMatt Macy tag = UART_TAG_BD; 130*f30f0f2bSMatt Macy goto out; 131*f30f0f2bSMatt Macy } 1322ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'b' && (*p)[1] == 'r') { 1332ae4f1fdSMarcel Moolenaar tag = UART_TAG_BR; 1342ae4f1fdSMarcel Moolenaar goto out; 1352ae4f1fdSMarcel Moolenaar } 1362ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'c' && (*p)[1] == 'h') { 1372ae4f1fdSMarcel Moolenaar tag = UART_TAG_CH; 1382ae4f1fdSMarcel Moolenaar goto out; 1392ae4f1fdSMarcel Moolenaar } 1402ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'd' && (*p)[1] == 'b') { 1412ae4f1fdSMarcel Moolenaar tag = UART_TAG_DB; 1422ae4f1fdSMarcel Moolenaar goto out; 1432ae4f1fdSMarcel Moolenaar } 1442ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'd' && (*p)[1] == 't') { 1452ae4f1fdSMarcel Moolenaar tag = UART_TAG_DT; 1462ae4f1fdSMarcel Moolenaar goto out; 1472ae4f1fdSMarcel Moolenaar } 1482ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'i' && (*p)[1] == 'o') { 1492ae4f1fdSMarcel Moolenaar tag = UART_TAG_IO; 1502ae4f1fdSMarcel Moolenaar goto out; 1512ae4f1fdSMarcel Moolenaar } 1522ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'm' && (*p)[1] == 'm') { 1532ae4f1fdSMarcel Moolenaar tag = UART_TAG_MM; 1542ae4f1fdSMarcel Moolenaar goto out; 1552ae4f1fdSMarcel Moolenaar } 1562ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'p' && (*p)[1] == 'a') { 1572ae4f1fdSMarcel Moolenaar tag = UART_TAG_PA; 1582ae4f1fdSMarcel Moolenaar goto out; 1592ae4f1fdSMarcel Moolenaar } 1602ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'r' && (*p)[1] == 's') { 1612ae4f1fdSMarcel Moolenaar tag = UART_TAG_RS; 1622ae4f1fdSMarcel Moolenaar goto out; 1632ae4f1fdSMarcel Moolenaar } 1642ae4f1fdSMarcel Moolenaar if ((*p)[0] == 's' && (*p)[1] == 'b') { 1652ae4f1fdSMarcel Moolenaar tag = UART_TAG_SB; 1662ae4f1fdSMarcel Moolenaar goto out; 1672ae4f1fdSMarcel Moolenaar } 1682ae4f1fdSMarcel Moolenaar if ((*p)[0] == 'x' && (*p)[1] == 'o') { 1692ae4f1fdSMarcel Moolenaar tag = UART_TAG_XO; 1702ae4f1fdSMarcel Moolenaar goto out; 1712ae4f1fdSMarcel Moolenaar } 1722ae4f1fdSMarcel Moolenaar return (-1); 1732ae4f1fdSMarcel Moolenaar 1742ae4f1fdSMarcel Moolenaar out: 1752ae4f1fdSMarcel Moolenaar *p += 2; 1762ae4f1fdSMarcel Moolenaar if ((*p)[0] != ':') 1772ae4f1fdSMarcel Moolenaar return (-1); 1782ae4f1fdSMarcel Moolenaar (*p)++; 1792ae4f1fdSMarcel Moolenaar return (tag); 1802ae4f1fdSMarcel Moolenaar } 1812ae4f1fdSMarcel Moolenaar 1822ae4f1fdSMarcel Moolenaar /* 1832ae4f1fdSMarcel Moolenaar * Parse a device specification. The specification is a list of attributes 184b1ce21c6SRebecca Cran * separated by commas. Each attribute is a tag-value pair with the tag and 185b1ce21c6SRebecca Cran * value separated by a colon. Supported tags are: 1862ae4f1fdSMarcel Moolenaar * 187*f30f0f2bSMatt Macy * bd = Busy Detect 1882ae4f1fdSMarcel Moolenaar * br = Baudrate 1892ae4f1fdSMarcel Moolenaar * ch = Channel 1902ae4f1fdSMarcel Moolenaar * db = Data bits 1912ae4f1fdSMarcel Moolenaar * dt = Device type 1922ae4f1fdSMarcel Moolenaar * io = I/O port address 1932ae4f1fdSMarcel Moolenaar * mm = Memory mapped I/O address 1942ae4f1fdSMarcel Moolenaar * pa = Parity 1952ae4f1fdSMarcel Moolenaar * rs = Register shift 1962ae4f1fdSMarcel Moolenaar * sb = Stopbits 1972ae4f1fdSMarcel Moolenaar * xo = Device clock (xtal oscillator) 1982ae4f1fdSMarcel Moolenaar * 1992ae4f1fdSMarcel Moolenaar * The io and mm tags are mutually exclusive. 2002ae4f1fdSMarcel Moolenaar */ 2012ae4f1fdSMarcel Moolenaar 2022ae4f1fdSMarcel Moolenaar int 203f8100ce2SMarcel Moolenaar uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) 2042ae4f1fdSMarcel Moolenaar { 2053bde8109SMarcelo Araujo const char *spec; 2063bde8109SMarcelo Araujo char *cp; 2072ae4f1fdSMarcel Moolenaar bus_addr_t addr = ~0U; 208f8100ce2SMarcel Moolenaar int error; 209f8100ce2SMarcel Moolenaar 210f8100ce2SMarcel Moolenaar /* 211f8100ce2SMarcel Moolenaar * All uart_class references are weak. Make sure the default 212f8100ce2SMarcel Moolenaar * device class has been compiled-in. 213f8100ce2SMarcel Moolenaar */ 214f8100ce2SMarcel Moolenaar if (class == NULL) 215f8100ce2SMarcel Moolenaar return (ENXIO); 2162ae4f1fdSMarcel Moolenaar 2172ae4f1fdSMarcel Moolenaar /* 2182ae4f1fdSMarcel Moolenaar * Check the environment variables "hw.uart.console" and 2192ae4f1fdSMarcel Moolenaar * "hw.uart.dbgport". These variables, when present, specify 2202ae4f1fdSMarcel Moolenaar * which UART port is to be used as serial console or debug 2212ae4f1fdSMarcel Moolenaar * port (resp). 2222ae4f1fdSMarcel Moolenaar */ 2233bde8109SMarcelo Araujo switch (devtype) { 2243bde8109SMarcelo Araujo case UART_DEV_CONSOLE: 225f695e046SMarcelo Araujo cp = kern_getenv("hw.uart.console"); 2263bde8109SMarcelo Araujo break; 2273bde8109SMarcelo Araujo case UART_DEV_DBGPORT: 228f695e046SMarcelo Araujo cp = kern_getenv("hw.uart.dbgport"); 2293bde8109SMarcelo Araujo break; 2303bde8109SMarcelo Araujo default: 231f695e046SMarcelo Araujo cp = NULL; 2323bde8109SMarcelo Araujo break; 2333bde8109SMarcelo Araujo } 2343bde8109SMarcelo Araujo 235f695e046SMarcelo Araujo if (cp == NULL) 2362ae4f1fdSMarcel Moolenaar return (ENXIO); 2372ae4f1fdSMarcel Moolenaar 2382ae4f1fdSMarcel Moolenaar /* Set defaults. */ 2392ae4f1fdSMarcel Moolenaar di->bas.chan = 0; 2402ae4f1fdSMarcel Moolenaar di->bas.regshft = 0; 2412ae4f1fdSMarcel Moolenaar di->bas.rclk = 0; 2422ae4f1fdSMarcel Moolenaar di->baudrate = 0; 2432ae4f1fdSMarcel Moolenaar di->databits = 8; 2442ae4f1fdSMarcel Moolenaar di->stopbits = 1; 2452ae4f1fdSMarcel Moolenaar di->parity = UART_PARITY_NONE; 2462ae4f1fdSMarcel Moolenaar 2472ae4f1fdSMarcel Moolenaar /* Parse the attributes. */ 248f695e046SMarcelo Araujo spec = cp; 2493bde8109SMarcelo Araujo for (;;) { 2502ae4f1fdSMarcel Moolenaar switch (uart_parse_tag(&spec)) { 251*f30f0f2bSMatt Macy case UART_TAG_BD: 252*f30f0f2bSMatt Macy di->bas.busy_detect = uart_parse_long(&spec); 253*f30f0f2bSMatt Macy break; 2542ae4f1fdSMarcel Moolenaar case UART_TAG_BR: 2552ae4f1fdSMarcel Moolenaar di->baudrate = uart_parse_long(&spec); 2562ae4f1fdSMarcel Moolenaar break; 2572ae4f1fdSMarcel Moolenaar case UART_TAG_CH: 2582ae4f1fdSMarcel Moolenaar di->bas.chan = uart_parse_long(&spec); 2592ae4f1fdSMarcel Moolenaar break; 2602ae4f1fdSMarcel Moolenaar case UART_TAG_DB: 2612ae4f1fdSMarcel Moolenaar di->databits = uart_parse_long(&spec); 2622ae4f1fdSMarcel Moolenaar break; 2632ae4f1fdSMarcel Moolenaar case UART_TAG_DT: 264f8100ce2SMarcel Moolenaar class = uart_parse_class(class, &spec); 2652ae4f1fdSMarcel Moolenaar break; 2662ae4f1fdSMarcel Moolenaar case UART_TAG_IO: 2672ae4f1fdSMarcel Moolenaar di->bas.bst = uart_bus_space_io; 2682ae4f1fdSMarcel Moolenaar addr = uart_parse_addr(&spec); 2692ae4f1fdSMarcel Moolenaar break; 2702ae4f1fdSMarcel Moolenaar case UART_TAG_MM: 2712ae4f1fdSMarcel Moolenaar di->bas.bst = uart_bus_space_mem; 2722ae4f1fdSMarcel Moolenaar addr = uart_parse_addr(&spec); 2732ae4f1fdSMarcel Moolenaar break; 2742ae4f1fdSMarcel Moolenaar case UART_TAG_PA: 2752ae4f1fdSMarcel Moolenaar di->parity = uart_parse_parity(&spec); 2762ae4f1fdSMarcel Moolenaar break; 2772ae4f1fdSMarcel Moolenaar case UART_TAG_RS: 2782ae4f1fdSMarcel Moolenaar di->bas.regshft = uart_parse_long(&spec); 2792ae4f1fdSMarcel Moolenaar break; 2802ae4f1fdSMarcel Moolenaar case UART_TAG_SB: 2812ae4f1fdSMarcel Moolenaar di->stopbits = uart_parse_long(&spec); 2822ae4f1fdSMarcel Moolenaar break; 2832ae4f1fdSMarcel Moolenaar case UART_TAG_XO: 2842ae4f1fdSMarcel Moolenaar di->bas.rclk = uart_parse_long(&spec); 2852ae4f1fdSMarcel Moolenaar break; 2862ae4f1fdSMarcel Moolenaar default: 2873bde8109SMarcelo Araujo freeenv(cp); 2882ae4f1fdSMarcel Moolenaar return (EINVAL); 2892ae4f1fdSMarcel Moolenaar } 2902ae4f1fdSMarcel Moolenaar if (*spec == '\0') 2912ae4f1fdSMarcel Moolenaar break; 292f695e046SMarcelo Araujo if (*spec != ',') { 2933bde8109SMarcelo Araujo freeenv(cp); 2942ae4f1fdSMarcel Moolenaar return (EINVAL); 295f695e046SMarcelo Araujo } 2962ae4f1fdSMarcel Moolenaar spec++; 2972ae4f1fdSMarcel Moolenaar } 2983bde8109SMarcelo Araujo freeenv(cp); 2992ae4f1fdSMarcel Moolenaar 3002ae4f1fdSMarcel Moolenaar /* 3012ae4f1fdSMarcel Moolenaar * If we still have an invalid address, the specification must be 3022ae4f1fdSMarcel Moolenaar * missing an I/O port or memory address. We don't like that. 3032ae4f1fdSMarcel Moolenaar */ 3042ae4f1fdSMarcel Moolenaar if (addr == ~0U) 3052ae4f1fdSMarcel Moolenaar return (EINVAL); 306ecf4dc25SMarcel Moolenaar 307ecf4dc25SMarcel Moolenaar /* 308ecf4dc25SMarcel Moolenaar * Accept only the well-known baudrates. Any invalid baudrate 309ecf4dc25SMarcel Moolenaar * is silently replaced with a 0-valued baudrate. The 0 baudrate 310ecf4dc25SMarcel Moolenaar * has special meaning. It means that we're not supposed to 311ecf4dc25SMarcel Moolenaar * program the baudrate and simply communicate with whatever 312ecf4dc25SMarcel Moolenaar * speed the hardware is currently programmed for. 313ecf4dc25SMarcel Moolenaar */ 314ecf4dc25SMarcel Moolenaar if (di->baudrate >= 19200) { 315ecf4dc25SMarcel Moolenaar if (di->baudrate % 19200) 316ecf4dc25SMarcel Moolenaar di->baudrate = 0; 317ecf4dc25SMarcel Moolenaar } else if (di->baudrate >= 1200) { 318ecf4dc25SMarcel Moolenaar if (di->baudrate % 1200) 319ecf4dc25SMarcel Moolenaar di->baudrate = 0; 320ecf4dc25SMarcel Moolenaar } else if (di->baudrate > 0) { 321ecf4dc25SMarcel Moolenaar if (di->baudrate % 75) 322ecf4dc25SMarcel Moolenaar di->baudrate = 0; 323ecf4dc25SMarcel Moolenaar } else 324ecf4dc25SMarcel Moolenaar di->baudrate = 0; 325ecf4dc25SMarcel Moolenaar 326f8100ce2SMarcel Moolenaar /* Set the ops and create a bus space handle. */ 327f8100ce2SMarcel Moolenaar di->ops = uart_getops(class); 328f8100ce2SMarcel Moolenaar error = bus_space_map(di->bas.bst, addr, uart_getrange(class), 0, 329f8100ce2SMarcel Moolenaar &di->bas.bsh); 330f8100ce2SMarcel Moolenaar return (error); 3312ae4f1fdSMarcel Moolenaar } 332