1139749Simp/*- 2127215Smarcel * Copyright (c) 2004 Marcel Moolenaar 3127215Smarcel * All rights reserved. 4127215Smarcel * 5127215Smarcel * Redistribution and use in source and binary forms, with or without 6127215Smarcel * modification, are permitted provided that the following conditions 7127215Smarcel * are met: 8127215Smarcel * 9127215Smarcel * 1. Redistributions of source code must retain the above copyright 10127215Smarcel * notice, this list of conditions and the following disclaimer. 11127215Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12127215Smarcel * notice, this list of conditions and the following disclaimer in the 13127215Smarcel * documentation and/or other materials provided with the distribution. 14127215Smarcel * 15127215Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16127215Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17127215Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18127215Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19127215Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20127215Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21127215Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22127215Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23127215Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24127215Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25127215Smarcel */ 26127215Smarcel 27127215Smarcel#include <sys/cdefs.h> 28127215Smarcel__FBSDID("$FreeBSD: stable/11/sys/dev/uart/uart_subr.c 356923 2020-01-20 18:54:19Z loos $"); 29127215Smarcel 30127215Smarcel#include <sys/param.h> 31127215Smarcel#include <sys/systm.h> 32127215Smarcel#include <sys/bus.h> 33127215Smarcel 34127215Smarcel#include <machine/bus.h> 35127215Smarcel#include <machine/vmparam.h> 36127215Smarcel 37127215Smarcel#include <dev/uart/uart.h> 38127215Smarcel#include <dev/uart/uart_cpu.h> 39127215Smarcel 40127215Smarcel#define UART_TAG_BR 0 41127215Smarcel#define UART_TAG_CH 1 42127215Smarcel#define UART_TAG_DB 2 43127215Smarcel#define UART_TAG_DT 3 44127215Smarcel#define UART_TAG_IO 4 45127215Smarcel#define UART_TAG_MM 5 46127215Smarcel#define UART_TAG_PA 6 47127215Smarcel#define UART_TAG_RS 7 48127215Smarcel#define UART_TAG_SB 8 49127215Smarcel#define UART_TAG_XO 9 50356923Sloos#define UART_TAG_BD 10 51127215Smarcel 52168281Smarcelstatic struct uart_class *uart_classes[] = { 53168281Smarcel &uart_ns8250_class, 54168281Smarcel &uart_sab82532_class, 55168281Smarcel &uart_z8530_class, 56249765Snyan#if defined(__arm__) 57252394Sray &uart_s3c2410_class, 58249765Snyan#endif 59168281Smarcel}; 60168281Smarcel 61127215Smarcelstatic bus_addr_t 62228468Seduart_parse_addr(const char **p) 63127215Smarcel{ 64127215Smarcel return (strtoul(*p, (char**)(uintptr_t)p, 0)); 65127215Smarcel} 66127215Smarcel 67168281Smarcelstatic struct uart_class * 68228468Seduart_parse_class(struct uart_class *class, const char **p) 69168281Smarcel{ 70168281Smarcel struct uart_class *uc; 71168281Smarcel const char *nm; 72168281Smarcel size_t len; 73168281Smarcel u_int i; 74168281Smarcel 75298411Spfg for (i = 0; i < nitems(uart_classes); i++) { 76168281Smarcel uc = uart_classes[i]; 77168281Smarcel nm = uart_getname(uc); 78168281Smarcel if (nm == NULL || *nm == '\0') 79168281Smarcel continue; 80168281Smarcel len = strlen(nm); 81168281Smarcel if (strncmp(nm, *p, len) == 0) { 82168281Smarcel *p += len; 83168281Smarcel return (uc); 84168281Smarcel } 85168281Smarcel } 86168281Smarcel return (class); 87168281Smarcel} 88168281Smarcel 89127215Smarcelstatic long 90228468Seduart_parse_long(const char **p) 91127215Smarcel{ 92127215Smarcel return (strtol(*p, (char**)(uintptr_t)p, 0)); 93127215Smarcel} 94127215Smarcel 95127215Smarcelstatic int 96228468Seduart_parse_parity(const char **p) 97127215Smarcel{ 98127215Smarcel if (!strncmp(*p, "even", 4)) { 99127215Smarcel *p += 4; 100127215Smarcel return UART_PARITY_EVEN; 101127215Smarcel } 102127215Smarcel if (!strncmp(*p, "mark", 4)) { 103127215Smarcel *p += 4; 104127215Smarcel return UART_PARITY_MARK; 105127215Smarcel } 106127215Smarcel if (!strncmp(*p, "none", 4)) { 107127215Smarcel *p += 4; 108127215Smarcel return UART_PARITY_NONE; 109127215Smarcel } 110127215Smarcel if (!strncmp(*p, "odd", 3)) { 111127215Smarcel *p += 3; 112127215Smarcel return UART_PARITY_ODD; 113127215Smarcel } 114127215Smarcel if (!strncmp(*p, "space", 5)) { 115127215Smarcel *p += 5; 116127215Smarcel return UART_PARITY_SPACE; 117127215Smarcel } 118127215Smarcel return (-1); 119127215Smarcel} 120127215Smarcel 121127215Smarcelstatic int 122228468Seduart_parse_tag(const char **p) 123127215Smarcel{ 124127215Smarcel int tag; 125127215Smarcel 126356923Sloos if ((*p)[0] == 'b' && (*p)[1] == 'd') { 127356923Sloos tag = UART_TAG_BD; 128356923Sloos goto out; 129356923Sloos } 130127215Smarcel if ((*p)[0] == 'b' && (*p)[1] == 'r') { 131127215Smarcel tag = UART_TAG_BR; 132127215Smarcel goto out; 133127215Smarcel } 134127215Smarcel if ((*p)[0] == 'c' && (*p)[1] == 'h') { 135127215Smarcel tag = UART_TAG_CH; 136127215Smarcel goto out; 137127215Smarcel } 138127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 'b') { 139127215Smarcel tag = UART_TAG_DB; 140127215Smarcel goto out; 141127215Smarcel } 142127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 't') { 143127215Smarcel tag = UART_TAG_DT; 144127215Smarcel goto out; 145127215Smarcel } 146127215Smarcel if ((*p)[0] == 'i' && (*p)[1] == 'o') { 147127215Smarcel tag = UART_TAG_IO; 148127215Smarcel goto out; 149127215Smarcel } 150127215Smarcel if ((*p)[0] == 'm' && (*p)[1] == 'm') { 151127215Smarcel tag = UART_TAG_MM; 152127215Smarcel goto out; 153127215Smarcel } 154127215Smarcel if ((*p)[0] == 'p' && (*p)[1] == 'a') { 155127215Smarcel tag = UART_TAG_PA; 156127215Smarcel goto out; 157127215Smarcel } 158127215Smarcel if ((*p)[0] == 'r' && (*p)[1] == 's') { 159127215Smarcel tag = UART_TAG_RS; 160127215Smarcel goto out; 161127215Smarcel } 162127215Smarcel if ((*p)[0] == 's' && (*p)[1] == 'b') { 163127215Smarcel tag = UART_TAG_SB; 164127215Smarcel goto out; 165127215Smarcel } 166127215Smarcel if ((*p)[0] == 'x' && (*p)[1] == 'o') { 167127215Smarcel tag = UART_TAG_XO; 168127215Smarcel goto out; 169127215Smarcel } 170127215Smarcel return (-1); 171127215Smarcel 172127215Smarcelout: 173127215Smarcel *p += 2; 174127215Smarcel if ((*p)[0] != ':') 175127215Smarcel return (-1); 176127215Smarcel (*p)++; 177127215Smarcel return (tag); 178127215Smarcel} 179127215Smarcel 180127215Smarcel/* 181127215Smarcel * Parse a device specification. The specification is a list of attributes 182215034Sbrucec * separated by commas. Each attribute is a tag-value pair with the tag and 183215034Sbrucec * value separated by a colon. Supported tags are: 184127215Smarcel * 185356923Sloos * bd = Busy Detect 186127215Smarcel * br = Baudrate 187127215Smarcel * ch = Channel 188127215Smarcel * db = Data bits 189127215Smarcel * dt = Device type 190127215Smarcel * io = I/O port address 191127215Smarcel * mm = Memory mapped I/O address 192127215Smarcel * pa = Parity 193127215Smarcel * rs = Register shift 194127215Smarcel * sb = Stopbits 195127215Smarcel * xo = Device clock (xtal oscillator) 196127215Smarcel * 197127215Smarcel * The io and mm tags are mutually exclusive. 198127215Smarcel */ 199127215Smarcel 200127215Smarcelint 201168281Smarceluart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) 202127215Smarcel{ 203273761Saraujo const char *spec; 204273761Saraujo char *cp; 205127215Smarcel bus_addr_t addr = ~0U; 206168281Smarcel int error; 207127215Smarcel 208127215Smarcel /* 209168281Smarcel * All uart_class references are weak. Make sure the default 210168281Smarcel * device class has been compiled-in. 211168281Smarcel */ 212168281Smarcel if (class == NULL) 213168281Smarcel return (ENXIO); 214168281Smarcel 215168281Smarcel /* 216127215Smarcel * Check the environment variables "hw.uart.console" and 217127215Smarcel * "hw.uart.dbgport". These variables, when present, specify 218127215Smarcel * which UART port is to be used as serial console or debug 219127215Smarcel * port (resp). 220127215Smarcel */ 221273761Saraujo switch (devtype) { 222273761Saraujo case UART_DEV_CONSOLE: 223273576Saraujo cp = kern_getenv("hw.uart.console"); 224273761Saraujo break; 225273761Saraujo case UART_DEV_DBGPORT: 226273576Saraujo cp = kern_getenv("hw.uart.dbgport"); 227273761Saraujo break; 228273761Saraujo default: 229273576Saraujo cp = NULL; 230273761Saraujo break; 231273761Saraujo } 232273761Saraujo 233273576Saraujo if (cp == NULL) 234127215Smarcel return (ENXIO); 235127215Smarcel 236127215Smarcel /* Set defaults. */ 237127215Smarcel di->bas.chan = 0; 238127215Smarcel di->bas.regshft = 0; 239127215Smarcel di->bas.rclk = 0; 240127215Smarcel di->baudrate = 0; 241127215Smarcel di->databits = 8; 242127215Smarcel di->stopbits = 1; 243127215Smarcel di->parity = UART_PARITY_NONE; 244127215Smarcel 245127215Smarcel /* Parse the attributes. */ 246273576Saraujo spec = cp; 247273761Saraujo for (;;) { 248127215Smarcel switch (uart_parse_tag(&spec)) { 249356923Sloos case UART_TAG_BD: 250356923Sloos di->bas.busy_detect = uart_parse_long(&spec); 251356923Sloos break; 252127215Smarcel case UART_TAG_BR: 253127215Smarcel di->baudrate = uart_parse_long(&spec); 254127215Smarcel break; 255127215Smarcel case UART_TAG_CH: 256127215Smarcel di->bas.chan = uart_parse_long(&spec); 257127215Smarcel break; 258127215Smarcel case UART_TAG_DB: 259127215Smarcel di->databits = uart_parse_long(&spec); 260127215Smarcel break; 261127215Smarcel case UART_TAG_DT: 262168281Smarcel class = uart_parse_class(class, &spec); 263127215Smarcel break; 264127215Smarcel case UART_TAG_IO: 265127215Smarcel di->bas.bst = uart_bus_space_io; 266127215Smarcel addr = uart_parse_addr(&spec); 267127215Smarcel break; 268127215Smarcel case UART_TAG_MM: 269127215Smarcel di->bas.bst = uart_bus_space_mem; 270127215Smarcel addr = uart_parse_addr(&spec); 271127215Smarcel break; 272127215Smarcel case UART_TAG_PA: 273127215Smarcel di->parity = uart_parse_parity(&spec); 274127215Smarcel break; 275127215Smarcel case UART_TAG_RS: 276127215Smarcel di->bas.regshft = uart_parse_long(&spec); 277127215Smarcel break; 278127215Smarcel case UART_TAG_SB: 279127215Smarcel di->stopbits = uart_parse_long(&spec); 280127215Smarcel break; 281127215Smarcel case UART_TAG_XO: 282127215Smarcel di->bas.rclk = uart_parse_long(&spec); 283127215Smarcel break; 284127215Smarcel default: 285273761Saraujo freeenv(cp); 286127215Smarcel return (EINVAL); 287127215Smarcel } 288127215Smarcel if (*spec == '\0') 289127215Smarcel break; 290273576Saraujo if (*spec != ',') { 291273761Saraujo freeenv(cp); 292127215Smarcel return (EINVAL); 293273576Saraujo } 294127215Smarcel spec++; 295127215Smarcel } 296273761Saraujo freeenv(cp); 297127215Smarcel 298127215Smarcel /* 299127215Smarcel * If we still have an invalid address, the specification must be 300127215Smarcel * missing an I/O port or memory address. We don't like that. 301127215Smarcel */ 302127215Smarcel if (addr == ~0U) 303127215Smarcel return (EINVAL); 304137704Smarcel 305137704Smarcel /* 306137704Smarcel * Accept only the well-known baudrates. Any invalid baudrate 307137704Smarcel * is silently replaced with a 0-valued baudrate. The 0 baudrate 308137704Smarcel * has special meaning. It means that we're not supposed to 309137704Smarcel * program the baudrate and simply communicate with whatever 310137704Smarcel * speed the hardware is currently programmed for. 311137704Smarcel */ 312137704Smarcel if (di->baudrate >= 19200) { 313137704Smarcel if (di->baudrate % 19200) 314137704Smarcel di->baudrate = 0; 315137704Smarcel } else if (di->baudrate >= 1200) { 316137704Smarcel if (di->baudrate % 1200) 317137704Smarcel di->baudrate = 0; 318137704Smarcel } else if (di->baudrate > 0) { 319137704Smarcel if (di->baudrate % 75) 320137704Smarcel di->baudrate = 0; 321137704Smarcel } else 322137704Smarcel di->baudrate = 0; 323137704Smarcel 324168281Smarcel /* Set the ops and create a bus space handle. */ 325168281Smarcel di->ops = uart_getops(class); 326168281Smarcel error = bus_space_map(di->bas.bst, addr, uart_getrange(class), 0, 327168281Smarcel &di->bas.bsh); 328168281Smarcel return (error); 329127215Smarcel} 330