uart_cpu_sparc64.c revision 200926
1139749Simp/*- 2127215Smarcel * Copyright (c) 2003, 2004 Marcel Moolenaar 3155322Smarius * Copyright (c) 2004 - 2006 Marius Strobl <marius@FreeBSD.org> 4119815Smarcel * All rights reserved. 5119815Smarcel * 6119815Smarcel * Redistribution and use in source and binary forms, with or without 7119815Smarcel * modification, are permitted provided that the following conditions 8119815Smarcel * are met: 9119815Smarcel * 10119815Smarcel * 1. Redistributions of source code must retain the above copyright 11119815Smarcel * notice, this list of conditions and the following disclaimer. 12119815Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13119815Smarcel * notice, this list of conditions and the following disclaimer in the 14119815Smarcel * documentation and/or other materials provided with the distribution. 15119815Smarcel * 16119815Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17119815Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18119815Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19119815Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20119815Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21119815Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22119815Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23119815Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24119815Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25119815Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26119815Smarcel */ 27119815Smarcel 28119815Smarcel#include <sys/cdefs.h> 29119815Smarcel__FBSDID("$FreeBSD: head/sys/dev/uart/uart_cpu_sparc64.c 200926 2009-12-23 22:31:43Z marius $"); 30119815Smarcel 31119815Smarcel#include <sys/param.h> 32119815Smarcel#include <sys/systm.h> 33119815Smarcel 34119815Smarcel#include <machine/bus.h> 35119815Smarcel#include <machine/bus_private.h> 36119815Smarcel 37119815Smarcel#include <dev/ofw/openfirm.h> 38119815Smarcel#include <machine/ofw_machdep.h> 39119815Smarcel 40119815Smarcel#include <dev/uart/uart.h> 41119815Smarcel#include <dev/uart/uart_cpu.h> 42119815Smarcel 43127215Smarcelbus_space_tag_t uart_bus_space_io; 44127215Smarcelbus_space_tag_t uart_bus_space_mem; 45127215Smarcel 46119815Smarcelstatic struct bus_space_tag bst_store[3]; 47119815Smarcel 48138157Smarius/* 49155322Smarius * Determine which channel of a SCC a device referenced by a full device 50155322Smarius * path or as an alias is (in the latter case we try to look up the device 51155322Smarius * path via the /aliases node). 52155322Smarius * Only the device paths of devices which are used for TTYs really allow 53155322Smarius * to do this as they look like these (taken from /aliases nodes): 54138157Smarius * ttya: '/central/fhc/zs@0,902000:a' 55138157Smarius * ttyc: '/pci@1f,0/pci@1,1/ebus@1/se@14,400000:a' 56155322Smarius * Additionally, for device paths of SCCs which are connected to a RSC 57155322Smarius * (Remote System Control) device we can hardcode the appropriate channel. 58155322Smarius * Such device paths look like these: 59155322Smarius * rsc: '/pci@1f,4000/ebus@1/se@14,200000:ssp' 60155322Smarius * ttyc: '/pci@1f,4000/ebus@1/se@14,200000:ssp' 61138157Smarius */ 62119815Smarcelstatic int 63119815Smarceluart_cpu_channel(char *dev) 64119815Smarcel{ 65119815Smarcel char alias[64]; 66119815Smarcel phandle_t aliases; 67119815Smarcel int len; 68155322Smarius const char *p; 69119815Smarcel 70119815Smarcel strcpy(alias, dev); 71119815Smarcel if ((aliases = OF_finddevice("/aliases")) != -1) 72155322Smarius (void)OF_getprop(aliases, dev, alias, sizeof(alias)); 73119815Smarcel len = strlen(alias); 74155322Smarius if ((p = rindex(alias, ':')) == NULL) 75119815Smarcel return (0); 76155322Smarius p++; 77155322Smarius if (p - alias == len - 1 && (*p == 'a' || *p == 'b')) 78155322Smarius return (*p - 'a' + 1); 79155322Smarius if (strcmp(p, "ssp") == 0) 80155322Smarius return (1); 81155322Smarius return (0); 82119815Smarcel} 83119815Smarcel 84119815Smarcelint 85119866Smarceluart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) 86119866Smarcel{ 87119866Smarcel 88119866Smarcel return ((b1->bsh == b2->bsh) ? 1 : 0); 89119866Smarcel} 90119866Smarcel 91127741Smarcel/* 92138157Smarius * Get the package handle of the UART that is selected as the console, if 93149111Smarius * the console is an UART of course. Note that we enforce that both input 94149111Smarius * and output are selected. 95127741Smarcel * Note that the currently active console (i.e. /chosen/stdout and 96127741Smarcel * /chosen/stdin) may not be the same as the device selected in the 97127741Smarcel * environment (ie /options/output-device and /options/input-device) because 98127825Smarcel * keyboard and screen were selected but the keyboard was unplugged or the 99127825Smarcel * user has changed the environment. In the latter case I would assume that 100127825Smarcel * the user expects that FreeBSD uses the new console setting. 101127825Smarcel * For weirder configurations, use ofw_console(4). 102127741Smarcel */ 103122466Sjakestatic phandle_t 104127741Smarceluart_cpu_getdev_console(phandle_t options, char *dev, size_t devsz) 105122466Sjake{ 106149111Smarius char buf[sizeof("serial")]; 107149111Smarius ihandle_t inst; 108149111Smarius phandle_t chosen, input, output; 109122466Sjake 110127741Smarcel if (OF_getprop(options, "input-device", dev, devsz) == -1) 111127741Smarcel return (-1); 112149111Smarius input = OF_finddevice(dev); 113149111Smarius if (OF_getprop(options, "output-device", dev, devsz) == -1) 114127825Smarcel return (-1); 115149111Smarius output = OF_finddevice(dev); 116149111Smarius if (input == -1 || output == -1 || 117149111Smarius OF_getproplen(input, "keyboard") >= 0) { 118127825Smarcel if ((chosen = OF_finddevice("/chosen")) == -1) 119127825Smarcel return (-1); 120149111Smarius if (OF_getprop(chosen, "stdin", &inst, sizeof(inst)) == -1) 121127825Smarcel return (-1); 122149111Smarius if ((input = OF_instance_to_package(inst)) == -1) 123127825Smarcel return (-1); 124149111Smarius if (OF_getprop(chosen, "stdout", &inst, sizeof(inst)) == -1) 125127825Smarcel return (-1); 126149111Smarius if ((output = OF_instance_to_package(inst)) == -1) 127127825Smarcel return (-1); 128127825Smarcel snprintf(dev, devsz, "ttya"); 129143468Smarius } 130149111Smarius if (input != output) 131149111Smarius return (-1); 132127741Smarcel if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 133127741Smarcel return (-1); 134127741Smarcel if (strcmp(buf, "serial") != 0) 135127741Smarcel return (-1); 136127741Smarcel return (input); 137127741Smarcel} 138127741Smarcel 139127741Smarcel/* 140138157Smarius * Get the package handle of the UART that's selected as the debug port. 141138157Smarius * Since there's no place for this in the OF, we use the kernel environment 142127741Smarcel * variable "hw.uart.dbgport". Note however that the variable is not a 143127741Smarcel * list of attributes. It's single device name or alias, as known by 144127741Smarcel * the OF. 145127741Smarcel */ 146127741Smarcelstatic phandle_t 147149111Smariusuart_cpu_getdev_dbgport(char *dev, size_t devsz) 148127741Smarcel{ 149149111Smarius char buf[sizeof("serial")]; 150127741Smarcel phandle_t input; 151127741Smarcel 152127741Smarcel if (!getenv_string("hw.uart.dbgport", dev, devsz)) 153127741Smarcel return (-1); 154127741Smarcel if ((input = OF_finddevice(dev)) == -1) 155127741Smarcel return (-1); 156127741Smarcel if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 157127741Smarcel return (-1); 158127741Smarcel if (strcmp(buf, "serial") != 0) 159127741Smarcel return (-1); 160127741Smarcel return (input); 161127741Smarcel} 162127741Smarcel 163138157Smarius/* 164146972Smarius * Get the package handle of the UART that is selected as the keyboard port, 165146972Smarius * if it's actually used to connect the keyboard according to the OF. I.e. 166146972Smarius * this will return the UART used to connect the keyboard regardless whether 167146972Smarius * it's stdin or not, however not in case the user or the OF gave preference 168146972Smarius * to e.g. a PS/2 keyboard by setting /aliases/keyboard accordingly. 169138157Smarius */ 170127741Smarcelstatic phandle_t 171146972Smariusuart_cpu_getdev_keyboard(char *dev, size_t devsz) 172127741Smarcel{ 173149111Smarius char buf[sizeof("serial")]; 174146972Smarius phandle_t input; 175127741Smarcel 176146972Smarius if ((input = OF_finddevice("keyboard")) == -1) 177146972Smarius return (-1); 178146972Smarius if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1) 179146972Smarius return (-1); 180146972Smarius if (strcmp(buf, "serial") != 0) 181146972Smarius return (-1); 182146972Smarius if (OF_getprop(input, "name", dev, devsz) == -1) 183146972Smarius return (-1); 184146972Smarius /* 185146972Smarius * So far this also matched PS/2 keyboard nodes so make sure it's 186146972Smarius * one of the SCCs/UARTs known to be used to connect keyboards. 187146972Smarius */ 188146972Smarius if (strcmp(dev, "su") && strcmp(dev, "su_pnp") && strcmp(dev, "zs")) 189146972Smarius return (-1); 190146972Smarius return (input); 191122466Sjake} 192122466Sjake 193119866Smarcelint 194119815Smarceluart_cpu_getdev(int devtype, struct uart_devinfo *di) 195119815Smarcel{ 196149111Smarius char buf[32], compat[32], dev[64]; 197168281Smarcel struct uart_class *class; 198127741Smarcel phandle_t input, options; 199119815Smarcel bus_addr_t addr; 200168281Smarcel int baud, bits, error, range, space, stop; 201119815Smarcel char flag, par; 202119815Smarcel 203127741Smarcel if ((options = OF_finddevice("/options")) == -1) 204127741Smarcel return (ENXIO); 205127741Smarcel switch (devtype) { 206127741Smarcel case UART_DEV_CONSOLE: 207127741Smarcel input = uart_cpu_getdev_console(options, dev, sizeof(dev)); 208127741Smarcel break; 209127741Smarcel case UART_DEV_DBGPORT: 210149111Smarius input = uart_cpu_getdev_dbgport(dev, sizeof(dev)); 211127741Smarcel break; 212127741Smarcel case UART_DEV_KEYBOARD: 213146972Smarius input = uart_cpu_getdev_keyboard(dev, sizeof(dev)); 214127741Smarcel break; 215127741Smarcel default: 216127741Smarcel input = -1; 217127741Smarcel break; 218127741Smarcel } 219127741Smarcel if (input == -1) 220127741Smarcel return (ENXIO); 221141753Smarius error = OF_decode_addr(input, 0, &space, &addr); 222119815Smarcel if (error) 223119815Smarcel return (error); 224119815Smarcel 225119815Smarcel /* Get the device class. */ 226119815Smarcel if (OF_getprop(input, "name", buf, sizeof(buf)) == -1) 227119815Smarcel return (ENXIO); 228120009Stmm if (OF_getprop(input, "compatible", compat, sizeof(compat)) == -1) 229120009Stmm compat[0] = '\0'; 230119815Smarcel di->bas.regshft = 0; 231119815Smarcel di->bas.rclk = 0; 232168281Smarcel class = NULL; 233148824Smarius if (!strcmp(buf, "se") || !strcmp(compat, "sab82532")) { 234168281Smarcel class = &uart_sab82532_class; 235138157Smarius /* SAB82532 are only known to be used for TTYs. */ 236138157Smarius if ((di->bas.chan = uart_cpu_channel(dev)) == 0) 237138157Smarius return (ENXIO); 238168281Smarcel addr += uart_getrange(class) * (di->bas.chan - 1); 239119815Smarcel } else if (!strcmp(buf, "zs")) { 240168281Smarcel class = &uart_z8530_class; 241138157Smarius if ((di->bas.chan = uart_cpu_channel(dev)) == 0) { 242138157Smarius /* 243138157Smarius * There's no way to determine from OF which 244138157Smarius * channel has the keyboard. Should always be 245138157Smarius * on channel 1 however. 246138157Smarius */ 247138157Smarius if (devtype == UART_DEV_KEYBOARD) 248138157Smarius di->bas.chan = 1; 249138157Smarius else 250138157Smarius return (ENXIO); 251138157Smarius } 252119815Smarcel di->bas.regshft = 1; 253168281Smarcel range = uart_getrange(class) << di->bas.regshft; 254168281Smarcel addr += range - range * (di->bas.chan - 1); 255155322Smarius } else if (!strcmp(buf, "lom-console") || !strcmp(buf, "su") || 256155322Smarius !strcmp(buf, "su_pnp") || !strcmp(compat, "rsc-console") || 257200926Smarius !strcmp(compat, "su") || !strcmp(compat, "su16550") || 258200926Smarius !strcmp(compat, "su16552")) { 259168281Smarcel class = &uart_ns8250_class; 260120452Smarcel di->bas.chan = 0; 261168281Smarcel } 262168281Smarcel if (class == NULL) 263119815Smarcel return (ENXIO); 264119815Smarcel 265119815Smarcel /* Fill in the device info. */ 266168281Smarcel di->ops = uart_getops(class); 267119815Smarcel di->bas.bst = &bst_store[devtype]; 268119815Smarcel di->bas.bsh = sparc64_fake_bustag(space, addr, di->bas.bst); 269119815Smarcel 270119815Smarcel /* Get the line settings. */ 271120545Sjake if (devtype == UART_DEV_KEYBOARD) 272120545Sjake di->baudrate = 1200; 273155322Smarius else if (!strcmp(compat, "rsc-console")) 274155322Smarius di->baudrate = 115200; 275120545Sjake else 276120545Sjake di->baudrate = 9600; 277119815Smarcel di->databits = 8; 278119815Smarcel di->stopbits = 1; 279119815Smarcel di->parity = UART_PARITY_NONE; 280119815Smarcel snprintf(buf, sizeof(buf), "%s-mode", dev); 281155322Smarius if (OF_getprop(options, buf, buf, sizeof(buf)) == -1 && 282155322Smarius OF_getprop(input, "ssp-console-modes", buf, sizeof(buf)) == -1) 283119815Smarcel return (0); 284119815Smarcel if (sscanf(buf, "%d,%d,%c,%d,%c", &baud, &bits, &par, &stop, &flag) 285119815Smarcel != 5) 286119815Smarcel return (0); 287119815Smarcel di->baudrate = baud; 288119815Smarcel di->databits = bits; 289119815Smarcel di->stopbits = stop; 290119815Smarcel di->parity = (par == 'n') ? UART_PARITY_NONE : 291119815Smarcel (par == 'o') ? UART_PARITY_ODD : UART_PARITY_EVEN; 292119815Smarcel return (0); 293119815Smarcel} 294