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$"); 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 50127215Smarcel 51168281Smarcelstatic struct uart_class *uart_classes[] = { 52168281Smarcel &uart_ns8250_class, 53168281Smarcel &uart_sab82532_class, 54168281Smarcel &uart_z8530_class, 55249765Snyan#if defined(__arm__) 56239278Sgonzo &uart_lpc_class, 57252394Sray &uart_s3c2410_class, 58249765Snyan#endif 59168281Smarcel}; 60168281Smarcelstatic size_t uart_nclasses = sizeof(uart_classes) / sizeof(uart_classes[0]); 61168281Smarcel 62127215Smarcelstatic bus_addr_t 63228468Seduart_parse_addr(const char **p) 64127215Smarcel{ 65127215Smarcel return (strtoul(*p, (char**)(uintptr_t)p, 0)); 66127215Smarcel} 67127215Smarcel 68168281Smarcelstatic struct uart_class * 69228468Seduart_parse_class(struct uart_class *class, const char **p) 70168281Smarcel{ 71168281Smarcel struct uart_class *uc; 72168281Smarcel const char *nm; 73168281Smarcel size_t len; 74168281Smarcel u_int i; 75168281Smarcel 76168281Smarcel for (i = 0; i < uart_nclasses; i++) { 77168281Smarcel uc = uart_classes[i]; 78168281Smarcel nm = uart_getname(uc); 79168281Smarcel if (nm == NULL || *nm == '\0') 80168281Smarcel continue; 81168281Smarcel len = strlen(nm); 82168281Smarcel if (strncmp(nm, *p, len) == 0) { 83168281Smarcel *p += len; 84168281Smarcel return (uc); 85168281Smarcel } 86168281Smarcel } 87168281Smarcel return (class); 88168281Smarcel} 89168281Smarcel 90127215Smarcelstatic long 91228468Seduart_parse_long(const char **p) 92127215Smarcel{ 93127215Smarcel return (strtol(*p, (char**)(uintptr_t)p, 0)); 94127215Smarcel} 95127215Smarcel 96127215Smarcelstatic int 97228468Seduart_parse_parity(const char **p) 98127215Smarcel{ 99127215Smarcel if (!strncmp(*p, "even", 4)) { 100127215Smarcel *p += 4; 101127215Smarcel return UART_PARITY_EVEN; 102127215Smarcel } 103127215Smarcel if (!strncmp(*p, "mark", 4)) { 104127215Smarcel *p += 4; 105127215Smarcel return UART_PARITY_MARK; 106127215Smarcel } 107127215Smarcel if (!strncmp(*p, "none", 4)) { 108127215Smarcel *p += 4; 109127215Smarcel return UART_PARITY_NONE; 110127215Smarcel } 111127215Smarcel if (!strncmp(*p, "odd", 3)) { 112127215Smarcel *p += 3; 113127215Smarcel return UART_PARITY_ODD; 114127215Smarcel } 115127215Smarcel if (!strncmp(*p, "space", 5)) { 116127215Smarcel *p += 5; 117127215Smarcel return UART_PARITY_SPACE; 118127215Smarcel } 119127215Smarcel return (-1); 120127215Smarcel} 121127215Smarcel 122127215Smarcelstatic int 123228468Seduart_parse_tag(const char **p) 124127215Smarcel{ 125127215Smarcel int tag; 126127215Smarcel 127127215Smarcel if ((*p)[0] == 'b' && (*p)[1] == 'r') { 128127215Smarcel tag = UART_TAG_BR; 129127215Smarcel goto out; 130127215Smarcel } 131127215Smarcel if ((*p)[0] == 'c' && (*p)[1] == 'h') { 132127215Smarcel tag = UART_TAG_CH; 133127215Smarcel goto out; 134127215Smarcel } 135127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 'b') { 136127215Smarcel tag = UART_TAG_DB; 137127215Smarcel goto out; 138127215Smarcel } 139127215Smarcel if ((*p)[0] == 'd' && (*p)[1] == 't') { 140127215Smarcel tag = UART_TAG_DT; 141127215Smarcel goto out; 142127215Smarcel } 143127215Smarcel if ((*p)[0] == 'i' && (*p)[1] == 'o') { 144127215Smarcel tag = UART_TAG_IO; 145127215Smarcel goto out; 146127215Smarcel } 147127215Smarcel if ((*p)[0] == 'm' && (*p)[1] == 'm') { 148127215Smarcel tag = UART_TAG_MM; 149127215Smarcel goto out; 150127215Smarcel } 151127215Smarcel if ((*p)[0] == 'p' && (*p)[1] == 'a') { 152127215Smarcel tag = UART_TAG_PA; 153127215Smarcel goto out; 154127215Smarcel } 155127215Smarcel if ((*p)[0] == 'r' && (*p)[1] == 's') { 156127215Smarcel tag = UART_TAG_RS; 157127215Smarcel goto out; 158127215Smarcel } 159127215Smarcel if ((*p)[0] == 's' && (*p)[1] == 'b') { 160127215Smarcel tag = UART_TAG_SB; 161127215Smarcel goto out; 162127215Smarcel } 163127215Smarcel if ((*p)[0] == 'x' && (*p)[1] == 'o') { 164127215Smarcel tag = UART_TAG_XO; 165127215Smarcel goto out; 166127215Smarcel } 167127215Smarcel return (-1); 168127215Smarcel 169127215Smarcelout: 170127215Smarcel *p += 2; 171127215Smarcel if ((*p)[0] != ':') 172127215Smarcel return (-1); 173127215Smarcel (*p)++; 174127215Smarcel return (tag); 175127215Smarcel} 176127215Smarcel 177127215Smarcel/* 178127215Smarcel * Parse a device specification. The specification is a list of attributes 179215034Sbrucec * separated by commas. Each attribute is a tag-value pair with the tag and 180215034Sbrucec * value separated by a colon. Supported tags are: 181127215Smarcel * 182127215Smarcel * br = Baudrate 183127215Smarcel * ch = Channel 184127215Smarcel * db = Data bits 185127215Smarcel * dt = Device type 186127215Smarcel * io = I/O port address 187127215Smarcel * mm = Memory mapped I/O address 188127215Smarcel * pa = Parity 189127215Smarcel * rs = Register shift 190127215Smarcel * sb = Stopbits 191127215Smarcel * xo = Device clock (xtal oscillator) 192127215Smarcel * 193127215Smarcel * The io and mm tags are mutually exclusive. 194127215Smarcel */ 195127215Smarcel 196127215Smarcelint 197168281Smarceluart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) 198127215Smarcel{ 199228468Sed const char *spec; 200127215Smarcel bus_addr_t addr = ~0U; 201168281Smarcel int error; 202127215Smarcel 203127215Smarcel /* 204168281Smarcel * All uart_class references are weak. Make sure the default 205168281Smarcel * device class has been compiled-in. 206168281Smarcel */ 207168281Smarcel if (class == NULL) 208168281Smarcel return (ENXIO); 209168281Smarcel 210168281Smarcel /* 211127215Smarcel * Check the environment variables "hw.uart.console" and 212127215Smarcel * "hw.uart.dbgport". These variables, when present, specify 213127215Smarcel * which UART port is to be used as serial console or debug 214127215Smarcel * port (resp). 215127215Smarcel */ 216127215Smarcel if (devtype == UART_DEV_CONSOLE) 217127215Smarcel spec = getenv("hw.uart.console"); 218127215Smarcel else if (devtype == UART_DEV_DBGPORT) 219127215Smarcel spec = getenv("hw.uart.dbgport"); 220127215Smarcel else 221127226Smarcel spec = NULL; 222127226Smarcel if (spec == NULL) 223127215Smarcel return (ENXIO); 224127215Smarcel 225127215Smarcel /* Set defaults. */ 226127215Smarcel di->bas.chan = 0; 227127215Smarcel di->bas.regshft = 0; 228127215Smarcel di->bas.rclk = 0; 229127215Smarcel di->baudrate = 0; 230127215Smarcel di->databits = 8; 231127215Smarcel di->stopbits = 1; 232127215Smarcel di->parity = UART_PARITY_NONE; 233127215Smarcel 234127215Smarcel /* Parse the attributes. */ 235127215Smarcel while (1) { 236127215Smarcel switch (uart_parse_tag(&spec)) { 237127215Smarcel case UART_TAG_BR: 238127215Smarcel di->baudrate = uart_parse_long(&spec); 239127215Smarcel break; 240127215Smarcel case UART_TAG_CH: 241127215Smarcel di->bas.chan = uart_parse_long(&spec); 242127215Smarcel break; 243127215Smarcel case UART_TAG_DB: 244127215Smarcel di->databits = uart_parse_long(&spec); 245127215Smarcel break; 246127215Smarcel case UART_TAG_DT: 247168281Smarcel class = uart_parse_class(class, &spec); 248127215Smarcel break; 249127215Smarcel case UART_TAG_IO: 250127215Smarcel di->bas.bst = uart_bus_space_io; 251127215Smarcel addr = uart_parse_addr(&spec); 252127215Smarcel break; 253127215Smarcel case UART_TAG_MM: 254127215Smarcel di->bas.bst = uart_bus_space_mem; 255127215Smarcel addr = uart_parse_addr(&spec); 256127215Smarcel break; 257127215Smarcel case UART_TAG_PA: 258127215Smarcel di->parity = uart_parse_parity(&spec); 259127215Smarcel break; 260127215Smarcel case UART_TAG_RS: 261127215Smarcel di->bas.regshft = uart_parse_long(&spec); 262127215Smarcel break; 263127215Smarcel case UART_TAG_SB: 264127215Smarcel di->stopbits = uart_parse_long(&spec); 265127215Smarcel break; 266127215Smarcel case UART_TAG_XO: 267127215Smarcel di->bas.rclk = uart_parse_long(&spec); 268127215Smarcel break; 269127215Smarcel default: 270127215Smarcel return (EINVAL); 271127215Smarcel } 272127215Smarcel if (*spec == '\0') 273127215Smarcel break; 274127215Smarcel if (*spec != ',') 275127215Smarcel return (EINVAL); 276127215Smarcel spec++; 277127215Smarcel } 278127215Smarcel 279127215Smarcel /* 280127215Smarcel * If we still have an invalid address, the specification must be 281127215Smarcel * missing an I/O port or memory address. We don't like that. 282127215Smarcel */ 283127215Smarcel if (addr == ~0U) 284127215Smarcel return (EINVAL); 285137704Smarcel 286137704Smarcel /* 287137704Smarcel * Accept only the well-known baudrates. Any invalid baudrate 288137704Smarcel * is silently replaced with a 0-valued baudrate. The 0 baudrate 289137704Smarcel * has special meaning. It means that we're not supposed to 290137704Smarcel * program the baudrate and simply communicate with whatever 291137704Smarcel * speed the hardware is currently programmed for. 292137704Smarcel */ 293137704Smarcel if (di->baudrate >= 19200) { 294137704Smarcel if (di->baudrate % 19200) 295137704Smarcel di->baudrate = 0; 296137704Smarcel } else if (di->baudrate >= 1200) { 297137704Smarcel if (di->baudrate % 1200) 298137704Smarcel di->baudrate = 0; 299137704Smarcel } else if (di->baudrate > 0) { 300137704Smarcel if (di->baudrate % 75) 301137704Smarcel di->baudrate = 0; 302137704Smarcel } else 303137704Smarcel di->baudrate = 0; 304137704Smarcel 305168281Smarcel /* Set the ops and create a bus space handle. */ 306168281Smarcel di->ops = uart_getops(class); 307168281Smarcel error = bus_space_map(di->bas.bst, addr, uart_getrange(class), 0, 308168281Smarcel &di->bas.bsh); 309168281Smarcel return (error); 310127215Smarcel} 311