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/sparc64/pci/sbbc.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 /*      $OpenBSD: sbbc.c,v 1.7 2009/11/09 17:53:39 nicm Exp $   */
    2 /*-
    3  * SPDX-License-Identifier: (ISC AND BSD-2-Clause-FreeBSD)
    4  *
    5  * Copyright (c) 2008 Mark Kettenis
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 /*-
   20  * Copyright (c) 2010 Marius Strobl <marius@FreeBSD.org>
   21  * All rights reserved.
   22  *
   23  * Redistribution and use in source and binary forms, with or without
   24  * modification, are permitted provided that the following conditions
   25  * are met:
   26  * 1. Redistributions of source code must retain the above copyright
   27  *    notice, this list of conditions and the following disclaimer.
   28  * 2. Redistributions in binary form must reproduce the above copyright
   29  *    notice, this list of conditions and the following disclaimer in the
   30  *    documentation and/or other materials provided with the distribution.
   31  *
   32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   42  * SUCH DAMAGE.
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __FBSDID("$FreeBSD$");
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/bus.h>
   51 #include <sys/clock.h>
   52 #include <sys/endian.h>
   53 #include <sys/kernel.h>
   54 #include <sys/lock.h>
   55 #include <sys/module.h>
   56 #include <sys/mutex.h>
   57 #include <sys/resource.h>
   58 #include <sys/rman.h>
   59 
   60 #include <dev/ofw/ofw_bus.h>
   61 #include <dev/ofw/openfirm.h>
   62 
   63 #include <machine/bus.h>
   64 #include <machine/cpu.h>
   65 #include <machine/resource.h>
   66 
   67 #include <dev/pci/pcireg.h>
   68 #include <dev/pci/pcivar.h>
   69 #include <dev/uart/uart.h>
   70 #include <dev/uart/uart_cpu.h>
   71 #include <dev/uart/uart_bus.h>
   72 
   73 #include "clock_if.h"
   74 #include "uart_if.h"
   75 
   76 #define SBBC_PCI_BAR            PCIR_BAR(0)
   77 #define SBBC_PCI_VENDOR         0x108e
   78 #define SBBC_PCI_PRODUCT        0xc416
   79 
   80 #define SBBC_REGS_OFFSET        0x800000
   81 #define SBBC_REGS_SIZE          0x6230
   82 #define SBBC_EPLD_OFFSET        0x8e0000
   83 #define SBBC_EPLD_SIZE          0x20
   84 #define SBBC_SRAM_OFFSET        0x900000
   85 #define SBBC_SRAM_SIZE          0x20000 /* 128KB SRAM */
   86 
   87 #define SBBC_PCI_INT_STATUS     0x2320
   88 #define SBBC_PCI_INT_ENABLE     0x2330
   89 #define SBBC_PCI_ENABLE_INT_A   0x11
   90 
   91 #define SBBC_EPLD_INTERRUPT     0x13
   92 #define SBBC_EPLD_INTERRUPT_ON  0x01
   93 
   94 #define SBBC_SRAM_CONS_IN               0x00000001
   95 #define SBBC_SRAM_CONS_OUT              0x00000002
   96 #define SBBC_SRAM_CONS_BRK              0x00000004
   97 #define SBBC_SRAM_CONS_SPACE_IN         0x00000008
   98 #define SBBC_SRAM_CONS_SPACE_OUT        0x00000010
   99 
  100 #define SBBC_TAG_KEY_SIZE       8
  101 #define SBBC_TAG_KEY_SCSOLIE    "SCSOLIE"       /* SC -> OS int. enable */
  102 #define SBBC_TAG_KEY_SCSOLIR    "SCSOLIR"       /* SC -> OS int. reason */
  103 #define SBBC_TAG_KEY_SOLCONS    "SOLCONS"       /* OS console buffer */
  104 #define SBBC_TAG_KEY_SOLSCIE    "SOLSCIE"       /* OS -> SC int. enable */
  105 #define SBBC_TAG_KEY_SOLSCIR    "SOLSCIR"       /* OS -> SC int. reason */
  106 #define SBBC_TAG_KEY_TODDATA    "TODDATA"       /* OS TOD struct */
  107 #define SBBC_TAG_OFF(x)         offsetof(struct sbbc_sram_tag, x)
  108 
  109 struct sbbc_sram_tag {
  110         char            tag_key[SBBC_TAG_KEY_SIZE];
  111         uint32_t        tag_size;
  112         uint32_t        tag_offset;
  113 } __packed;
  114 
  115 #define SBBC_TOC_MAGIC          "TOCSRAM"
  116 #define SBBC_TOC_MAGIC_SIZE     8
  117 #define SBBC_TOC_TAGS_MAX       32
  118 #define SBBC_TOC_OFF(x)         offsetof(struct sbbc_sram_toc, x)
  119 
  120 struct sbbc_sram_toc {
  121         char                    toc_magic[SBBC_TOC_MAGIC_SIZE];
  122         uint8_t                 toc_reserved;
  123         uint8_t                 toc_type;
  124         uint16_t                toc_version;
  125         uint32_t                toc_ntags;
  126         struct sbbc_sram_tag    toc_tag[SBBC_TOC_TAGS_MAX];
  127 } __packed;
  128 
  129 #define SBBC_TOD_MAGIC          0x54443100      /* "TD1" */
  130 #define SBBC_TOD_VERSION        1
  131 #define SBBC_TOD_OFF(x)         offsetof(struct sbbc_sram_tod, x)
  132 
  133 struct sbbc_sram_tod {
  134         uint32_t        tod_magic;
  135         uint32_t        tod_version;
  136         uint64_t        tod_time;
  137         uint64_t        tod_skew;
  138         uint32_t        tod_reserved;
  139         uint32_t        tod_heartbeat;
  140         uint32_t        tod_timeout;
  141 } __packed;
  142 
  143 #define SBBC_CONS_MAGIC         0x434f4e00      /* "CON" */
  144 #define SBBC_CONS_VERSION       1
  145 #define SBBC_CONS_OFF(x)        offsetof(struct sbbc_sram_cons, x)
  146 
  147 struct sbbc_sram_cons {
  148         uint32_t cons_magic;
  149         uint32_t cons_version;
  150         uint32_t cons_size;
  151 
  152         uint32_t cons_in_begin;
  153         uint32_t cons_in_end;
  154         uint32_t cons_in_rdptr;
  155         uint32_t cons_in_wrptr;
  156 
  157         uint32_t cons_out_begin;
  158         uint32_t cons_out_end;
  159         uint32_t cons_out_rdptr;
  160         uint32_t cons_out_wrptr;
  161 } __packed;
  162 
  163 struct sbbc_softc {
  164         struct resource *sc_res;
  165 };
  166 
  167 #define SBBC_READ_N(wdth, offs)                                         \
  168         bus_space_read_ ## wdth((bst), (bsh), (offs))
  169 #define SBBC_WRITE_N(wdth, offs, val)                                   \
  170         bus_space_write_ ## wdth((bst), (bsh), (offs), (val))
  171 
  172 #define SBBC_READ_1(offs)                                               \
  173         SBBC_READ_N(1, (offs))
  174 #define SBBC_READ_2(offs)                                               \
  175         bswap16(SBBC_READ_N(2, (offs)))
  176 #define SBBC_READ_4(offs)                                               \
  177         bswap32(SBBC_READ_N(4, (offs)))
  178 #define SBBC_READ_8(offs)                                               \
  179         bswap64(SBBC_READ_N(8, (offs)))
  180 #define SBBC_WRITE_1(offs, val)                                         \
  181         SBBC_WRITE_N(1, (offs), (val))
  182 #define SBBC_WRITE_2(offs, val)                                         \
  183         SBBC_WRITE_N(2, (offs), bswap16(val))
  184 #define SBBC_WRITE_4(offs, val)                                         \
  185         SBBC_WRITE_N(4, (offs), bswap32(val))
  186 #define SBBC_WRITE_8(offs, val)                                         \
  187         SBBC_WRITE_N(8, (offs), bswap64(val))
  188 
  189 #define SBBC_REGS_READ_1(offs)                                          \
  190         SBBC_READ_1((offs) + SBBC_REGS_OFFSET)
  191 #define SBBC_REGS_READ_2(offs)                                          \
  192         SBBC_READ_2((offs) + SBBC_REGS_OFFSET)
  193 #define SBBC_REGS_READ_4(offs)                                          \
  194         SBBC_READ_4((offs) + SBBC_REGS_OFFSET)
  195 #define SBBC_REGS_READ_8(offs)                                          \
  196         SBBC_READ_8((offs) + SBBC_REGS_OFFSET)
  197 #define SBBC_REGS_WRITE_1(offs, val)                                    \
  198         SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val))
  199 #define SBBC_REGS_WRITE_2(offs, val)                                    \
  200         SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val))
  201 #define SBBC_REGS_WRITE_4(offs, val)                                    \
  202         SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val))
  203 #define SBBC_REGS_WRITE_8(offs, val)                                    \
  204         SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val))
  205 
  206 #define SBBC_EPLD_READ_1(offs)                                          \
  207         SBBC_READ_1((offs) + SBBC_EPLD_OFFSET)
  208 #define SBBC_EPLD_READ_2(offs)                                          \
  209         SBBC_READ_2((offs) + SBBC_EPLD_OFFSET)
  210 #define SBBC_EPLD_READ_4(offs)                                          \
  211         SBBC_READ_4((offs) + SBBC_EPLD_OFFSET)
  212 #define SBBC_EPLD_READ_8(offs)                                          \
  213         SBBC_READ_8((offs) + SBBC_EPLD_OFFSET)
  214 #define SBBC_EPLD_WRITE_1(offs, val)                                    \
  215         SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val))
  216 #define SBBC_EPLD_WRITE_2(offs, val)                                    \
  217         SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val))
  218 #define SBBC_EPLD_WRITE_4(offs, val)                                    \
  219         SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val))
  220 #define SBBC_EPLD_WRITE_8(offs, val)                                    \
  221         SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val))
  222 
  223 #define SBBC_SRAM_READ_1(offs)                                          \
  224         SBBC_READ_1((offs) + SBBC_SRAM_OFFSET)
  225 #define SBBC_SRAM_READ_2(offs)                                          \
  226         SBBC_READ_2((offs) + SBBC_SRAM_OFFSET)
  227 #define SBBC_SRAM_READ_4(offs)                                          \
  228         SBBC_READ_4((offs) + SBBC_SRAM_OFFSET)
  229 #define SBBC_SRAM_READ_8(offs)                                          \
  230         SBBC_READ_8((offs) + SBBC_SRAM_OFFSET)
  231 #define SBBC_SRAM_WRITE_1(offs, val)                                    \
  232         SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val))
  233 #define SBBC_SRAM_WRITE_2(offs, val)                                    \
  234         SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val))
  235 #define SBBC_SRAM_WRITE_4(offs, val)                                    \
  236         SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val))
  237 #define SBBC_SRAM_WRITE_8(offs, val)                                    \
  238         SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val))
  239 
  240 #define SUNW_SETCONSINPUT       "SUNW,set-console-input"
  241 #define SUNW_SETCONSINPUT_CLNT  "CON_CLNT"
  242 #define SUNW_SETCONSINPUT_OBP   "CON_OBP"
  243 
  244 static u_int sbbc_console;
  245 
  246 static uint32_t sbbc_scsolie;
  247 static uint32_t sbbc_scsolir;
  248 static uint32_t sbbc_solcons;
  249 static uint32_t sbbc_solscie;
  250 static uint32_t sbbc_solscir;
  251 static uint32_t sbbc_toddata;
  252 
  253 /*
  254  * internal helpers
  255  */
  256 static int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh);
  257 static inline void sbbc_send_intr(bus_space_tag_t bst,
  258     bus_space_handle_t bsh);
  259 static const char *sbbc_serengeti_set_console_input(char *new);
  260 
  261 /*
  262  * SBBC PCI interface
  263  */
  264 static bus_activate_resource_t sbbc_bus_activate_resource;
  265 static bus_adjust_resource_t sbbc_bus_adjust_resource;
  266 static bus_deactivate_resource_t sbbc_bus_deactivate_resource;
  267 static bus_alloc_resource_t sbbc_bus_alloc_resource;
  268 static bus_release_resource_t sbbc_bus_release_resource;
  269 static bus_get_resource_list_t sbbc_bus_get_resource_list;
  270 static bus_setup_intr_t sbbc_bus_setup_intr;
  271 static bus_teardown_intr_t sbbc_bus_teardown_intr;
  272 
  273 static device_attach_t sbbc_pci_attach;
  274 static device_probe_t sbbc_pci_probe;
  275 
  276 static clock_gettime_t sbbc_tod_gettime;
  277 static clock_settime_t sbbc_tod_settime;
  278 
  279 static device_method_t sbbc_pci_methods[] = {
  280         /* Device interface */
  281         DEVMETHOD(device_probe,         sbbc_pci_probe),
  282         DEVMETHOD(device_attach,        sbbc_pci_attach),
  283 
  284         DEVMETHOD(bus_alloc_resource,   sbbc_bus_alloc_resource),
  285         DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource),
  286         DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource),
  287         DEVMETHOD(bus_adjust_resource,  sbbc_bus_adjust_resource),
  288         DEVMETHOD(bus_release_resource, sbbc_bus_release_resource),
  289         DEVMETHOD(bus_setup_intr,       sbbc_bus_setup_intr),
  290         DEVMETHOD(bus_teardown_intr,    sbbc_bus_teardown_intr),
  291         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  292         DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list),
  293 
  294         /* clock interface */
  295         DEVMETHOD(clock_gettime,        sbbc_tod_gettime),
  296         DEVMETHOD(clock_settime,        sbbc_tod_settime),
  297 
  298         DEVMETHOD_END
  299 };
  300 
  301 static devclass_t sbbc_devclass;
  302 
  303 DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc));
  304 DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL);
  305 
  306 static int
  307 sbbc_pci_probe(device_t dev)
  308 {
  309 
  310         if (pci_get_vendor(dev) == SBBC_PCI_VENDOR &&
  311             pci_get_device(dev) == SBBC_PCI_PRODUCT) {
  312                 device_set_desc(dev, "Sun BootBus controller");
  313                 return (BUS_PROBE_DEFAULT);
  314         }
  315         return (ENXIO);
  316 }
  317 
  318 static int
  319 sbbc_pci_attach(device_t dev)
  320 {
  321         struct sbbc_softc *sc;
  322         struct timespec ts;
  323         device_t child;
  324         bus_space_tag_t bst;
  325         bus_space_handle_t bsh;
  326         phandle_t node;
  327         int error, rid;
  328         uint32_t val;
  329 
  330         /* Nothing to do if we're not the chosen one. */
  331         if ((node = OF_finddevice("/chosen")) == -1) {
  332                 device_printf(dev, "failed to find /chosen\n");
  333                 return (ENXIO);
  334         }
  335         if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) {
  336                 device_printf(dev, "failed to get iosram\n");
  337                 return (ENXIO);
  338         }
  339         if (node != ofw_bus_get_node(dev))
  340                 return (0);
  341 
  342         sc = device_get_softc(dev);
  343         rid = SBBC_PCI_BAR;
  344         sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  345             RF_ACTIVE);
  346         if (sc->sc_res == NULL) {
  347                 device_printf(dev, "failed to allocate resources\n");
  348                 return (ENXIO);
  349         }
  350         bst = rman_get_bustag(sc->sc_res);
  351         bsh = rman_get_bushandle(sc->sc_res);
  352         if (sbbc_console != 0) {
  353                 /* Once again the interrupt pin isn't set. */
  354                 if (pci_get_intpin(dev) == 0)
  355                         pci_set_intpin(dev, 1);
  356                 child = device_add_child(dev, NULL, -1);
  357                 if (child == NULL)
  358                         device_printf(dev, "failed to add UART device\n");
  359                 error = bus_generic_attach(dev);
  360                 if (error != 0)
  361                         device_printf(dev, "failed to attach UART device\n");
  362         } else {
  363                 error = sbbc_parse_toc(bst, bsh);
  364                 if (error != 0) {
  365                         device_printf(dev, "failed to parse TOC\n");
  366                         if (sbbc_console != 0) {
  367                                 bus_release_resource(dev, SYS_RES_MEMORY, rid,
  368                                     sc->sc_res);
  369                                 return (error);
  370                         }
  371                 }
  372         }
  373         if (sbbc_toddata != 0) {
  374                 if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
  375                     SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC)
  376                         device_printf(dev, "invalid TOD magic %#x\n", val);
  377                 else if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
  378                     SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION)
  379                         device_printf(dev, "invalid TOD version %#x\n", val);
  380                 else {
  381                         clock_register(dev, 1000000); /* 1 sec. resolution */
  382                         if (bootverbose) {
  383                                 sbbc_tod_gettime(dev, &ts);
  384                                 device_printf(dev,
  385                                     "current time: %ld.%09ld\n",
  386                                     (long)ts.tv_sec, ts.tv_nsec);
  387                         }
  388                 }
  389         }
  390         return (0);
  391 }
  392 
  393 /*
  394  * Note that the bus methods don't pass-through the uart(4) requests but act
  395  * as if they would come from sbbc(4) in order to avoid complications with
  396  * pci(4) (actually, uart(4) isn't a real child but rather a function of
  397  * sbbc(4) anyway).
  398  */
  399 
  400 static struct resource *
  401 sbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type,
  402     int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  403 {
  404         struct sbbc_softc *sc;
  405 
  406         sc = device_get_softc(dev);
  407         switch (type) {
  408         case SYS_RES_IRQ:
  409                 return (bus_generic_alloc_resource(dev, dev, type, rid, start,
  410                     end, count, flags));
  411         case SYS_RES_MEMORY:
  412                 return (sc->sc_res);
  413         default:
  414                 return (NULL);
  415         }
  416 }
  417 
  418 static int
  419 sbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid,
  420     struct resource *res)
  421 {
  422 
  423         if (type == SYS_RES_MEMORY)
  424                 return (0);
  425         return (bus_generic_activate_resource(bus, child, type, rid, res));
  426 }
  427 
  428 static int
  429 sbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid,
  430     struct resource *res)
  431 {
  432 
  433         if (type == SYS_RES_MEMORY)
  434                 return (0);
  435         return (bus_generic_deactivate_resource(bus, child, type, rid, res));
  436 }
  437 
  438 static int
  439 sbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused,
  440     int type __unused, struct resource *res __unused, rman_res_t start __unused,
  441     rman_res_t end __unused)
  442 {
  443 
  444         return (ENXIO);
  445 }
  446 
  447 static int
  448 sbbc_bus_release_resource(device_t dev, device_t child __unused, int type,
  449     int rid, struct resource *res)
  450 {
  451 
  452         if (type == SYS_RES_IRQ)
  453                 return (bus_generic_release_resource(dev, dev, type, rid,
  454                     res));
  455         return (0);
  456 }
  457 
  458 static struct resource_list *
  459 sbbc_bus_get_resource_list(device_t dev, device_t child __unused)
  460 {
  461 
  462         return (bus_generic_get_resource_list(dev, dev));
  463 }
  464 
  465 static int
  466 sbbc_bus_setup_intr(device_t dev, device_t child __unused,
  467     struct resource *res, int flags, driver_filter_t *filt,
  468     driver_intr_t *intr, void *arg, void **cookiep)
  469 {
  470 
  471         return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg,
  472             cookiep));
  473 }
  474 
  475 static int
  476 sbbc_bus_teardown_intr(device_t dev, device_t child __unused,
  477     struct resource *res, void *cookie)
  478 {
  479 
  480         return (bus_generic_teardown_intr(dev, dev, res, cookie));
  481 }
  482 
  483 /*
  484  * internal helpers
  485  */
  486 static int
  487 sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh)
  488 {
  489         char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)];
  490         bus_size_t tag;
  491         phandle_t node;
  492         uint32_t off, sram_toc;
  493         u_int i, tags;
  494 
  495         if ((node = OF_finddevice("/chosen")) == -1)
  496                 return (ENXIO);
  497         /* SRAM TOC offset defaults to 0. */
  498         if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0)
  499                 sram_toc = 0;
  500 
  501         bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc +
  502             SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE);
  503         buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0';
  504         if (strcmp(buf, SBBC_TOC_MAGIC) != 0)
  505                 return (ENXIO);
  506 
  507         tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags));
  508         for (i = 0; i < tags; i++) {
  509                 tag = sram_toc + SBBC_TOC_OFF(toc_tag) +
  510                     i * sizeof(struct sbbc_sram_tag);
  511                 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag +
  512                     SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE);
  513                 buf[SBBC_TAG_KEY_SIZE - 1] = '\0';
  514                 off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset));
  515                 if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0)
  516                         sbbc_scsolie = off;
  517                 else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0)
  518                         sbbc_scsolir = off;
  519                 else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0)
  520                         sbbc_solcons = off;
  521                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0)
  522                         sbbc_solscie = off;
  523                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0)
  524                         sbbc_solscir = off;
  525                 else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0)
  526                         sbbc_toddata = off;
  527         }
  528         return (0);
  529 }
  530 
  531 static const char *
  532 sbbc_serengeti_set_console_input(char *new)
  533 {
  534         struct {
  535                 cell_t name;
  536                 cell_t nargs;
  537                 cell_t nreturns;
  538                 cell_t new;
  539                 cell_t old;
  540         } args = {
  541                 (cell_t)SUNW_SETCONSINPUT,
  542                 1,
  543                 1,
  544         };
  545 
  546         args.new = (cell_t)new;
  547         if (ofw_entry(&args) == -1)
  548                 return (NULL);
  549         return ((const char *)args.old);
  550 }
  551 
  552 static inline void
  553 sbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh)
  554 {
  555 
  556         SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
  557         bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1,
  558             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
  559 }
  560 
  561 /*
  562  * TOD interface
  563  */
  564 static int
  565 sbbc_tod_gettime(device_t dev, struct timespec *ts)
  566 {
  567         struct sbbc_softc *sc;
  568         bus_space_tag_t bst;
  569         bus_space_handle_t bsh;
  570 
  571         sc = device_get_softc(dev);
  572         bst = rman_get_bustag(sc->sc_res);
  573         bsh = rman_get_bushandle(sc->sc_res);
  574 
  575         ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) +
  576             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew));
  577         ts->tv_nsec = 0;
  578         return (0);
  579 }
  580 
  581 static int
  582 sbbc_tod_settime(device_t dev, struct timespec *ts)
  583 {
  584         struct sbbc_softc *sc;
  585         bus_space_tag_t bst;
  586         bus_space_handle_t bsh;
  587 
  588         sc = device_get_softc(dev);
  589         bst = rman_get_bustag(sc->sc_res);
  590         bsh = rman_get_bushandle(sc->sc_res);
  591 
  592         SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec -
  593             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)));
  594         return (0);
  595 }
  596 
  597 /*
  598  * UART bus front-end
  599  */
  600 static device_probe_t sbbc_uart_sbbc_probe;
  601 
  602 static device_method_t sbbc_uart_sbbc_methods[] = {
  603         /* Device interface */
  604         DEVMETHOD(device_probe,         sbbc_uart_sbbc_probe),
  605         DEVMETHOD(device_attach,        uart_bus_attach),
  606         DEVMETHOD(device_detach,        uart_bus_detach),
  607 
  608         DEVMETHOD_END
  609 };
  610 
  611 DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods,
  612     sizeof(struct uart_softc));
  613 DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL);
  614 
  615 static int
  616 sbbc_uart_sbbc_probe(device_t dev)
  617 {
  618         struct uart_softc *sc;
  619 
  620         sc = device_get_softc(dev);
  621         sc->sc_class = &uart_sbbc_class;
  622         device_set_desc(dev, "Serengeti console");
  623         return (uart_bus_probe(dev, 0, 0, 0, SBBC_PCI_BAR, 0, 0));
  624 }
  625 
  626 /*
  627  * Low-level UART interface
  628  */
  629 static int sbbc_uart_probe(struct uart_bas *bas);
  630 static void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits,
  631     int stopbits, int parity);
  632 static void sbbc_uart_term(struct uart_bas *bas);
  633 static void sbbc_uart_putc(struct uart_bas *bas, int c);
  634 static int sbbc_uart_rxready(struct uart_bas *bas);
  635 static int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx);
  636 
  637 static struct uart_ops sbbc_uart_ops = {
  638         .probe = sbbc_uart_probe,
  639         .init = sbbc_uart_init,
  640         .term = sbbc_uart_term,
  641         .putc = sbbc_uart_putc,
  642         .rxready = sbbc_uart_rxready,
  643         .getc = sbbc_uart_getc,
  644 };
  645 
  646 static int
  647 sbbc_uart_probe(struct uart_bas *bas)
  648 {
  649         bus_space_tag_t bst;
  650         bus_space_handle_t bsh;
  651         int error;
  652 
  653         sbbc_console = 1;
  654         bst = bas->bst;
  655         bsh = bas->bsh;
  656         error = sbbc_parse_toc(bst, bsh);
  657         if (error != 0)
  658                 return (error);
  659 
  660         if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 ||
  661             sbbc_solscie == 0 || sbbc_solscir == 0)
  662                 return (ENXIO);
  663 
  664         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) !=
  665             SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons +
  666             SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION)
  667                 return (ENXIO);
  668         return (0);
  669 }
  670 
  671 static void
  672 sbbc_uart_init(struct uart_bas *bas, int baudrate __unused,
  673     int databits __unused, int stopbits __unused, int parity __unused)
  674 {
  675         bus_space_tag_t bst;
  676         bus_space_handle_t bsh;
  677 
  678         bst = bas->bst;
  679         bsh = bas->bsh;
  680 
  681         /* Enable output to and space in from the SC interrupts. */
  682         SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) |
  683             SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN);
  684         uart_barrier(bas);
  685 
  686         /* Take over the console input. */
  687         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT);
  688 }
  689 
  690 static void
  691 sbbc_uart_term(struct uart_bas *bas __unused)
  692 {
  693 
  694         /* Give back the console input. */
  695         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
  696 }
  697 
  698 static void
  699 sbbc_uart_putc(struct uart_bas *bas, int c)
  700 {
  701         bus_space_tag_t bst;
  702         bus_space_handle_t bsh;
  703         uint32_t wrptr;
  704 
  705         bst = bas->bst;
  706         bsh = bas->bsh;
  707 
  708         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  709             SBBC_CONS_OFF(cons_out_wrptr));
  710         SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c);
  711         uart_barrier(bas);
  712         if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons +
  713             SBBC_CONS_OFF(cons_out_end)))
  714                 wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  715                     SBBC_CONS_OFF(cons_out_begin));
  716         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
  717             wrptr);
  718         uart_barrier(bas);
  719 
  720         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
  721             SBBC_SRAM_CONS_OUT);
  722         uart_barrier(bas);
  723         sbbc_send_intr(bst, bsh);
  724 }
  725 
  726 static int
  727 sbbc_uart_rxready(struct uart_bas *bas)
  728 {
  729         bus_space_tag_t bst;
  730         bus_space_handle_t bsh;
  731 
  732         bst = bas->bst;
  733         bsh = bas->bsh;
  734 
  735         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) ==
  736             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr)))
  737                 return (0);
  738         return (1);
  739 }
  740 
  741 static int
  742 sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
  743 {
  744         bus_space_tag_t bst;
  745         bus_space_handle_t bsh;
  746         int c;
  747         uint32_t rdptr;
  748 
  749         bst = bas->bst;
  750         bsh = bas->bsh;
  751 
  752         uart_lock(hwmtx);
  753 
  754         while (sbbc_uart_rxready(bas) == 0) {
  755                 uart_unlock(hwmtx);
  756                 DELAY(4);
  757                 uart_lock(hwmtx);
  758         }
  759 
  760         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
  761         c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
  762         uart_barrier(bas);
  763         if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons +
  764             SBBC_CONS_OFF(cons_in_end)))
  765                 rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
  766                     SBBC_CONS_OFF(cons_in_begin));
  767         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
  768             rdptr);
  769         uart_barrier(bas);
  770         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
  771             SBBC_SRAM_CONS_SPACE_IN);
  772         uart_barrier(bas);
  773         sbbc_send_intr(bst, bsh);
  774 
  775         uart_unlock(hwmtx);
  776         return (c);
  777 }
  778 
  779 /*
  780  * High-level UART interface
  781  */
  782 static int sbbc_uart_bus_attach(struct uart_softc *sc);
  783 static int sbbc_uart_bus_detach(struct uart_softc *sc);
  784 static int sbbc_uart_bus_flush(struct uart_softc *sc, int what);
  785 static int sbbc_uart_bus_getsig(struct uart_softc *sc);
  786 static int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request,
  787     intptr_t data);
  788 static int sbbc_uart_bus_ipend(struct uart_softc *sc);
  789 static int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate,
  790     int databits, int stopbits, int parity);
  791 static int sbbc_uart_bus_probe(struct uart_softc *sc);
  792 static int sbbc_uart_bus_receive(struct uart_softc *sc);
  793 static int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig);
  794 static int sbbc_uart_bus_transmit(struct uart_softc *sc);
  795 
  796 static kobj_method_t sbbc_uart_methods[] = {
  797         KOBJMETHOD(uart_attach,         sbbc_uart_bus_attach),
  798         KOBJMETHOD(uart_detach,         sbbc_uart_bus_detach),
  799         KOBJMETHOD(uart_flush,          sbbc_uart_bus_flush),
  800         KOBJMETHOD(uart_getsig,         sbbc_uart_bus_getsig),
  801         KOBJMETHOD(uart_ioctl,          sbbc_uart_bus_ioctl),
  802         KOBJMETHOD(uart_ipend,          sbbc_uart_bus_ipend),
  803         KOBJMETHOD(uart_param,          sbbc_uart_bus_param),
  804         KOBJMETHOD(uart_probe,          sbbc_uart_bus_probe),
  805         KOBJMETHOD(uart_receive,        sbbc_uart_bus_receive),
  806         KOBJMETHOD(uart_setsig,         sbbc_uart_bus_setsig),
  807         KOBJMETHOD(uart_transmit,       sbbc_uart_bus_transmit),
  808 
  809         DEVMETHOD_END
  810 };
  811 
  812 struct uart_class uart_sbbc_class = {
  813         "sbbc",
  814         sbbc_uart_methods,
  815         sizeof(struct uart_softc),
  816         .uc_ops = &sbbc_uart_ops,
  817         .uc_range = 1,
  818         .uc_rclk = 0x5bbc,      /* arbitrary */
  819         .uc_rshift = 0
  820 };
  821 
  822 #define SIGCHG(c, i, s, d)                                              \
  823         if ((c) != 0) {                                                 \
  824                 i |= (((i) & (s)) != 0) ? (s) : (s) | (d);              \
  825         } else {                                                        \
  826                 i = (((i) & (s)) != 0) ? ((i) & ~(s)) | (d) : (i);      \
  827         }
  828 
  829 static int
  830 sbbc_uart_bus_attach(struct uart_softc *sc)
  831 {
  832         struct uart_bas *bas;
  833         bus_space_tag_t bst;
  834         bus_space_handle_t bsh;
  835         uint32_t wrptr;
  836 
  837         bas = &sc->sc_bas;
  838         bst = bas->bst;
  839         bsh = bas->bsh;
  840 
  841         uart_lock(sc->sc_hwmtx);
  842 
  843         /*
  844          * Let the current output drain before enabling interrupts.  Not
  845          * doing so tends to cause lost output when turning them on.
  846          */
  847         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  848             SBBC_CONS_OFF(cons_out_wrptr));
  849         while (SBBC_SRAM_READ_4(sbbc_solcons +
  850             SBBC_CONS_OFF(cons_out_rdptr)) != wrptr);
  851                 cpu_spinwait();
  852 
  853         /* Clear and acknowledge possibly outstanding interrupts. */
  854         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
  855         uart_barrier(bas);
  856         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS,
  857             SBBC_SRAM_READ_4(sbbc_scsolir));
  858         uart_barrier(bas);
  859         /* Enable PCI interrupts. */
  860         SBBC_REGS_WRITE_4(SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
  861         uart_barrier(bas);
  862         /* Enable input from and output to SC as well as break interrupts. */
  863         SBBC_SRAM_WRITE_4(sbbc_scsolie, SBBC_SRAM_READ_4(sbbc_scsolie) |
  864             SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK |
  865             SBBC_SRAM_CONS_SPACE_OUT);
  866         uart_barrier(bas);
  867 
  868         uart_unlock(sc->sc_hwmtx);
  869         return (0);
  870 }
  871 
  872 static int
  873 sbbc_uart_bus_detach(struct uart_softc *sc)
  874 {
  875 
  876         /* Give back the console input. */
  877         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
  878         return (0);
  879 }
  880 
  881 static int
  882 sbbc_uart_bus_flush(struct uart_softc *sc, int what)
  883 {
  884         struct uart_bas *bas;
  885         bus_space_tag_t bst;
  886         bus_space_handle_t bsh;
  887 
  888         bas = &sc->sc_bas;
  889         bst = bas->bst;
  890         bsh = bas->bsh;
  891 
  892         if ((what & UART_FLUSH_TRANSMITTER) != 0)
  893                 return (ENODEV);
  894         if ((what & UART_FLUSH_RECEIVER) != 0) {
  895                 SBBC_SRAM_WRITE_4(sbbc_solcons +
  896                     SBBC_CONS_OFF(cons_in_rdptr),
  897                     SBBC_SRAM_READ_4(sbbc_solcons +
  898                     SBBC_CONS_OFF(cons_in_wrptr)));
  899                 uart_barrier(bas);
  900         }
  901         return (0);
  902 }
  903 
  904 static int
  905 sbbc_uart_bus_getsig(struct uart_softc *sc)
  906 {
  907         uint32_t dummy, new, old, sig;
  908 
  909         do {
  910                 old = sc->sc_hwsig;
  911                 sig = old;
  912                 dummy = 0;
  913                 SIGCHG(dummy, sig, SER_CTS, SER_DCTS);
  914                 SIGCHG(dummy, sig, SER_DCD, SER_DDCD);
  915                 SIGCHG(dummy, sig, SER_DSR, SER_DDSR);
  916                 new = sig & ~SER_MASK_DELTA;
  917         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  918         return (sig);
  919 }
  920 
  921 static int
  922 sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  923 {
  924         int error;
  925 
  926         error = 0;
  927         uart_lock(sc->sc_hwmtx);
  928         switch (request) {
  929         case UART_IOCTL_BAUD:
  930                 *(int*)data = 9600;     /* arbitrary */
  931                 break;
  932         default:
  933                 error = EINVAL;
  934                 break;
  935         }
  936         uart_unlock(sc->sc_hwmtx);
  937         return (error);
  938 }
  939 
  940 static int
  941 sbbc_uart_bus_ipend(struct uart_softc *sc)
  942 {
  943         struct uart_bas *bas;
  944         bus_space_tag_t bst;
  945         bus_space_handle_t bsh;
  946         int ipend;
  947         uint32_t reason, status;
  948 
  949         bas = &sc->sc_bas;
  950         bst = bas->bst;
  951         bsh = bas->bsh;
  952 
  953         uart_lock(sc->sc_hwmtx);
  954         status = SBBC_REGS_READ_4(SBBC_PCI_INT_STATUS);
  955         if (status == 0) {
  956                 uart_unlock(sc->sc_hwmtx);
  957                 return (0);
  958         }
  959 
  960         /*
  961          * Unfortunately, we can't use compare and swap for non-cachable
  962          * memory.
  963          */
  964         reason = SBBC_SRAM_READ_4(sbbc_scsolir);
  965         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
  966         uart_barrier(bas);
  967         /* Acknowledge the interrupt. */
  968         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, status);
  969         uart_barrier(bas);
  970 
  971         uart_unlock(sc->sc_hwmtx);
  972 
  973         ipend = 0;
  974         if ((reason & SBBC_SRAM_CONS_IN) != 0)
  975                 ipend |= SER_INT_RXREADY;
  976         if ((reason & SBBC_SRAM_CONS_BRK) != 0)
  977                 ipend |= SER_INT_BREAK;
  978         if ((reason & SBBC_SRAM_CONS_SPACE_OUT) != 0 &&
  979             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_rdptr)) ==
  980             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr)))
  981                 ipend |= SER_INT_TXIDLE;
  982         return (ipend);
  983 }
  984 
  985 static int
  986 sbbc_uart_bus_param(struct uart_softc *sc __unused, int baudrate __unused,
  987     int databits __unused, int stopbits __unused, int parity __unused)
  988 {
  989 
  990         return (0);
  991 }
  992 
  993 static int
  994 sbbc_uart_bus_probe(struct uart_softc *sc)
  995 {
  996         struct uart_bas *bas;
  997         bus_space_tag_t bst;
  998         bus_space_handle_t bsh;
  999 
 1000         if (sbbc_console != 0) {
 1001                 bas = &sc->sc_bas;
 1002                 bst = bas->bst;
 1003                 bsh = bas->bsh;
 1004                 sc->sc_rxfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
 1005                     SBBC_CONS_OFF(cons_in_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
 1006                     SBBC_CONS_OFF(cons_in_begin)) - 1;
 1007                 sc->sc_txfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
 1008                     SBBC_CONS_OFF(cons_out_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
 1009                     SBBC_CONS_OFF(cons_out_begin)) - 1;
 1010                 return (0);
 1011         }
 1012         return (ENXIO);
 1013 }
 1014 
 1015 static int
 1016 sbbc_uart_bus_receive(struct uart_softc *sc)
 1017 {
 1018         struct uart_bas *bas;
 1019         bus_space_tag_t bst;
 1020         bus_space_handle_t bsh;
 1021         int c;
 1022         uint32_t end, rdptr, wrptr;
 1023 
 1024         bas = &sc->sc_bas;
 1025         bst = bas->bst;
 1026         bsh = bas->bsh;
 1027 
 1028         uart_lock(sc->sc_hwmtx);
 1029 
 1030         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_end));
 1031         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
 1032         wrptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr));
 1033         while (rdptr != wrptr) {
 1034                 if (uart_rx_full(sc) != 0) {
 1035                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
 1036                         break;
 1037                 }
 1038                 c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
 1039                 uart_rx_put(sc, c);
 1040                 if (++rdptr == end)
 1041                         rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1042                             SBBC_CONS_OFF(cons_in_begin));
 1043         }
 1044         uart_barrier(bas);
 1045         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
 1046             rdptr);
 1047         uart_barrier(bas);
 1048         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
 1049             SBBC_SRAM_CONS_SPACE_IN);
 1050         uart_barrier(bas);
 1051         sbbc_send_intr(bst, bsh);
 1052 
 1053         uart_unlock(sc->sc_hwmtx);
 1054         return (0);
 1055 }
 1056 
 1057 static int
 1058 sbbc_uart_bus_setsig(struct uart_softc *sc, int sig)
 1059 {
 1060         struct uart_bas *bas;
 1061         uint32_t new, old;
 1062 
 1063         bas = &sc->sc_bas;
 1064         do {
 1065                 old = sc->sc_hwsig;
 1066                 new = old;
 1067                 if ((sig & SER_DDTR) != 0) {
 1068                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
 1069                 }
 1070                 if ((sig & SER_DRTS) != 0) {
 1071                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
 1072                 }
 1073         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
 1074         return (0);
 1075 }
 1076 
 1077 static int
 1078 sbbc_uart_bus_transmit(struct uart_softc *sc)
 1079 {
 1080         struct uart_bas *bas;
 1081         bus_space_tag_t bst;
 1082         bus_space_handle_t bsh;
 1083         int i;
 1084         uint32_t end, wrptr;
 1085 
 1086         bas = &sc->sc_bas;
 1087         bst = bas->bst;
 1088         bsh = bas->bsh;
 1089 
 1090         uart_lock(sc->sc_hwmtx);
 1091 
 1092         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_end));
 1093         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1094             SBBC_CONS_OFF(cons_out_wrptr));
 1095         for (i = 0; i < sc->sc_txdatasz; i++) {
 1096                 SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, sc->sc_txbuf[i]);
 1097                 if (++wrptr == end)
 1098                         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1099                             SBBC_CONS_OFF(cons_out_begin));
 1100         }
 1101         uart_barrier(bas);
 1102         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
 1103             wrptr);
 1104         uart_barrier(bas);
 1105         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
 1106             SBBC_SRAM_CONS_OUT);
 1107         uart_barrier(bas);
 1108         sbbc_send_intr(bst, bsh);
 1109         sc->sc_txbusy = 1;
 1110 
 1111         uart_unlock(sc->sc_hwmtx);
 1112         return (0);
 1113 }

Cache object: b214cd8e1be0b86b1793ff3aa3ce4e42


[ 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.