The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/uart/uart_cpu_sparc64.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003, 2004 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_isa.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 
   35 #include <machine/bus.h>
   36 #include <machine/bus_private.h>
   37 #include <machine/resource.h>
   38 
   39 #include <dev/ofw/ofw_bus.h>
   40 #include <dev/ofw/openfirm.h>
   41 #include <machine/ofw_machdep.h>
   42 
   43 #include <isa/isavar.h>
   44 
   45 #include <dev/uart/uart.h>
   46 #include <dev/uart/uart_bus.h>
   47 #include <dev/uart/uart_cpu.h>
   48 
   49 #include <sparc64/pci/ofw_pci.h>
   50 #include <sparc64/isa/ofw_isa.h>
   51 
   52 bus_space_tag_t uart_bus_space_io;
   53 bus_space_tag_t uart_bus_space_mem;
   54 
   55 static struct bus_space_tag bst_store[3];
   56 
   57 /*
   58  * Determine which channel of a SCC a device referenced by an alias is.
   59  * The information present in the OF device tree only allows to do this
   60  * for "ttyX" aliases. If a device is a channel of a SCC its property
   61  * in the /aliases node looks like one of these:
   62  * ttya:  '/central/fhc/zs@0,902000:a'
   63  * ttyc:  '/pci@1f,0/pci@1,1/ebus@1/se@14,400000:a'
   64  */
   65 static int
   66 uart_cpu_channel(char *dev)
   67 {
   68         char alias[64];
   69         phandle_t aliases;
   70         int len;
   71 
   72         strcpy(alias, dev);
   73         if ((aliases = OF_finddevice("/aliases")) != -1)
   74                 OF_getprop(aliases, dev, alias, sizeof(alias));
   75         len = strlen(alias);
   76         if (len < 2 || alias[len - 2] != ':' || alias[len - 1] < 'a' ||
   77             alias[len - 1] > 'b')
   78                 return (0);
   79         return (alias[len - 1] - 'a' + 1);
   80 }
   81 
   82 int
   83 uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
   84 {
   85 
   86         return ((b1->bsh == b2->bsh) ? 1 : 0);
   87 }
   88 
   89 /*
   90  * Get the package handle of the UART that is selected as the console, if
   91  * the console is an UART of course. Note that we enforce that both stdin
   92  * and stdout are selected.
   93  * Note that the currently active console (i.e. /chosen/stdout and
   94  * /chosen/stdin) may not be the same as the device selected in the
   95  * environment (ie /options/output-device and /options/input-device) because
   96  * keyboard and screen were selected but the keyboard was unplugged or the
   97  * user has changed the environment. In the latter case I would assume that
   98  * the user expects that FreeBSD uses the new console setting.
   99  * For weirder configurations, use ofw_console(4).
  100  */
  101 static phandle_t
  102 uart_cpu_getdev_console(phandle_t options, char *dev, size_t devsz)
  103 {
  104         char buf[32];
  105         ihandle_t stdin, stdout;
  106         phandle_t chosen, input;
  107 
  108         if (OF_getprop(options, "input-device", dev, devsz) == -1)
  109                 return (-1);
  110         if (OF_getprop(options, "output-device", buf, sizeof(buf)) == -1)
  111                 return (-1);
  112         if (!strcmp(dev, "keyboard") && !strcmp(buf, "screen")) {
  113                 if ((chosen = OF_finddevice("/chosen")) == -1)
  114                         return (-1);
  115                 if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1)
  116                         return (-1);
  117                 if ((input = OF_instance_to_package(stdin)) == -1)
  118                         return (-1);
  119                 if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1)
  120                         return (-1);
  121                 if (OF_instance_to_package(stdout) != input)
  122                         return (-1);
  123                 snprintf(dev, devsz, "ttya");
  124         } else {
  125                 if ((input = OF_finddevice(dev)) == -1)
  126                         return (-1);
  127                 if (OF_finddevice(buf) != input)
  128                         return (-1);
  129         }
  130         if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1)
  131                 return (-1);
  132         if (strcmp(buf, "serial") != 0)
  133                 return (-1);
  134         return (input);
  135 }
  136 
  137 /*
  138  * Get the package handle of the UART that's selected as the debug port.
  139  * Since there's no place for this in the OF, we use the kernel environment
  140  * variable "hw.uart.dbgport". Note however that the variable is not a
  141  * list of attributes. It's single device name or alias, as known by
  142  * the OF.
  143  */
  144 static phandle_t
  145 uart_cpu_getdev_dbgport(phandle_t options, char *dev, size_t devsz)
  146 {
  147         char buf[32];
  148         phandle_t input;
  149 
  150         if (!getenv_string("hw.uart.dbgport", dev, devsz))
  151                 return (-1);
  152         if ((input = OF_finddevice(dev)) == -1)
  153                 return (-1);
  154         if (OF_getprop(input, "device_type", buf, sizeof(buf)) == -1)
  155                 return (-1);
  156         if (strcmp(buf, "serial") != 0)
  157                 return (-1);
  158         return (input);
  159 }
  160 
  161 /*
  162  * Get the package handle of the device that is selected as the keyboard
  163  * port.
  164  * XXX this also matches PS/2 keyboard controllers and most likely also
  165  * USB keyboards.
  166  */
  167 static phandle_t
  168 uart_cpu_getdev_keyboard(phandle_t root, char *dev, size_t devsz)
  169 {
  170         char buf[32];
  171         phandle_t child, node;
  172 
  173         child = OF_child(root);
  174         while (child != 0 && child != -1) {
  175                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) != -1 &&
  176                     !strcmp(buf, "serial") &&
  177                     OF_getprop(child, "keyboard", buf, sizeof(buf)) != -1) {
  178                         OF_getprop(child, "name", dev, devsz);
  179                         return (child);
  180                 }
  181                 if ((node = uart_cpu_getdev_keyboard(child, dev, devsz)) != -1)
  182                         return (node);
  183                 child = OF_peer(child);
  184         }
  185         return (-1);
  186 }
  187 
  188 int
  189 uart_cpu_getdev(int devtype, struct uart_devinfo *di)
  190 {
  191         char buf[32], dev[32], compat[32];
  192         phandle_t input, options;
  193         bus_addr_t addr;
  194         int baud, bits, error, space, stop;
  195         char flag, par;
  196 
  197         if ((options = OF_finddevice("/options")) == -1)
  198                 return (ENXIO);
  199         switch (devtype) {
  200         case UART_DEV_CONSOLE:
  201                 input = uart_cpu_getdev_console(options, dev, sizeof(dev));
  202                 break;
  203         case UART_DEV_DBGPORT:
  204                 input = uart_cpu_getdev_dbgport(options, dev, sizeof(dev));
  205                 break;
  206         case UART_DEV_KEYBOARD:
  207                 input = uart_cpu_getdev_keyboard(OF_peer(0), dev, sizeof(dev));
  208                 break;
  209         default:
  210                 input = -1;
  211                 break;
  212         }
  213         if (input == -1)
  214                 return (ENXIO);
  215         error = OF_decode_addr(input, &space, &addr);
  216         if (error)
  217                 return (error);
  218 
  219         /* Get the device class. */
  220         if (OF_getprop(input, "name", buf, sizeof(buf)) == -1)
  221                 return (ENXIO);
  222         if (OF_getprop(input, "compatible", compat, sizeof(compat)) == -1)
  223                 compat[0] = '\0';
  224         di->bas.regshft = 0;
  225         di->bas.rclk = 0;
  226         if (!strcmp(buf, "se")) {
  227                 di->ops = uart_sab82532_ops;
  228                 /* SAB82532 are only known to be used for TTYs. */
  229                 if ((di->bas.chan = uart_cpu_channel(dev)) == 0)
  230                         return (ENXIO);
  231                 addr += 64 * (di->bas.chan - 1);
  232         } else if (!strcmp(buf, "zs")) {
  233                 di->ops = uart_z8530_ops;
  234                 if ((di->bas.chan = uart_cpu_channel(dev)) == 0) {
  235                         /*
  236                          * There's no way to determine from OF which
  237                          * channel has the keyboard. Should always be
  238                          * on channel 1 however.
  239                          */
  240                         if (devtype == UART_DEV_KEYBOARD)
  241                                 di->bas.chan = 1;
  242                         else
  243                                 return (ENXIO);
  244                 }
  245                 di->bas.regshft = 1;
  246                 addr += 4 - 4 * (di->bas.chan - 1);
  247         } else if (!strcmp(buf, "su") || !strcmp(buf, "su_pnp") ||
  248             !strcmp(compat, "su") || !strcmp(compat, "su16550")) {
  249                 di->ops = uart_ns8250_ops;
  250                 di->bas.chan = 0;
  251         } else
  252                 return (ENXIO);
  253 
  254         /* Fill in the device info. */
  255         di->bas.bst = &bst_store[devtype];
  256         di->bas.bsh = sparc64_fake_bustag(space, addr, di->bas.bst);
  257 
  258         /* Get the line settings. */
  259         if (devtype == UART_DEV_KEYBOARD)
  260                 di->baudrate = 1200;
  261         else
  262                 di->baudrate = 9600;
  263         di->databits = 8;
  264         di->stopbits = 1;
  265         di->parity = UART_PARITY_NONE;
  266         snprintf(buf, sizeof(buf), "%s-mode", dev);
  267         if (OF_getprop(options, buf, buf, sizeof(buf)) == -1)
  268                 return (0);
  269         if (sscanf(buf, "%d,%d,%c,%d,%c", &baud, &bits, &par, &stop, &flag)
  270             != 5)
  271                 return (0);
  272         di->baudrate = baud;
  273         di->databits = bits;
  274         di->stopbits = stop;
  275         di->parity = (par == 'n') ? UART_PARITY_NONE :
  276             (par == 'o') ? UART_PARITY_ODD : UART_PARITY_EVEN;
  277         return (0);
  278 }
  279 
  280 void
  281 uart_cpu_identify(driver_t *driver, device_t parent)
  282 {
  283 #ifdef DEV_ISA
  284         char buf[32];
  285         struct isa_regs reg;
  286         device_t child;
  287         phandle_t node;
  288         ofw_isa_intr_t intr;
  289 #endif
  290 
  291 #ifdef DEV_ISA
  292         if (strcmp(device_get_name(parent), "isa") == 0) {
  293                 if ((node = ofw_bus_get_node(device_get_parent(parent))) == 0)
  294                         return;
  295                 for (node = OF_child(node); node != 0; node = OF_peer(node)) {
  296                         if (OF_getprop(node, "name", buf, sizeof(buf)) == -1)
  297                                 continue;
  298                         if (strcmp(buf, "serial") != 0)
  299                                 continue;
  300                         if ((OF_getprop(node, "reg", &reg,
  301                             sizeof(reg)) == -1) ||
  302                             (OF_getprop(node, "interrupts", &intr,
  303                             sizeof(intr)) == -1))
  304                                 continue;
  305                         if ((child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE,
  306                             uart_driver_name, -1)) == NULL)
  307                                 return;
  308                         bus_set_resource(child, SYS_RES_IOPORT, 0,
  309                             ISA_REG_PHYS(&reg), reg.size);
  310                         bus_set_resource(child, SYS_RES_IRQ, 0, intr, 1);
  311                 }
  312         }
  313 #endif
  314 }

Cache object: 64907a63421eb5c8837550d199b0fe43


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.