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

Cache object: 6bc73f3966a7e412ecb43ff1b8cae681


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