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/quicc/quicc_core.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  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright 2006 by Juniper Networks.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/conf.h>
   38 #include <sys/endian.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/queue.h>
   42 #include <sys/serial.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/resource.h>
   46 #include <sys/rman.h>
   47 
   48 #include <dev/ic/quicc.h>
   49 
   50 #include <dev/quicc/quicc_bfe.h>
   51 #include <dev/quicc/quicc_bus.h>
   52 
   53 #define quicc_read2(r, o)       \
   54         bus_space_read_2((r)->r_bustag, (r)->r_bushandle, o)
   55 #define quicc_read4(r, o)       \
   56         bus_space_read_4((r)->r_bustag, (r)->r_bushandle, o)
   57 
   58 #define quicc_write2(r, o, v)   \
   59         bus_space_write_2((r)->r_bustag, (r)->r_bushandle, o, v)
   60 #define quicc_write4(r, o, v)   \
   61         bus_space_write_4((r)->r_bustag, (r)->r_bushandle, o, v)
   62 
   63 char quicc_driver_name[] = "quicc";
   64 
   65 static MALLOC_DEFINE(M_QUICC, "QUICC", "QUICC driver");
   66 
   67 struct quicc_device {
   68         struct rman     *qd_rman;
   69         struct resource_list qd_rlist;
   70         device_t        qd_dev;
   71         int             qd_devtype;
   72 
   73         driver_filter_t *qd_ih;
   74         void            *qd_ih_arg;
   75 };
   76 
   77 static int
   78 quicc_bfe_intr(void *arg)
   79 {
   80         struct quicc_device *qd;
   81         struct quicc_softc *sc = arg;
   82         uint32_t sipnr;
   83 
   84         sipnr = quicc_read4(sc->sc_rres, QUICC_REG_SIPNR_L);
   85         if (sipnr & 0x00f00000)
   86                 qd = sc->sc_device;
   87         else
   88                 qd = NULL;
   89 
   90         if (qd == NULL || qd->qd_ih == NULL) {
   91                 device_printf(sc->sc_dev, "Stray interrupt %08x\n", sipnr);
   92                 return (FILTER_STRAY);
   93         }
   94 
   95         return ((*qd->qd_ih)(qd->qd_ih_arg));
   96 }
   97 
   98 int
   99 quicc_bfe_attach(device_t dev)
  100 {
  101         struct quicc_device *qd;
  102         struct quicc_softc *sc;
  103         struct resource_list_entry *rle;
  104         const char *sep;
  105         rman_res_t size, start;
  106         int error;
  107 
  108         sc = device_get_softc(dev);
  109 
  110         /*
  111          * Re-allocate. We expect that the softc contains the information
  112          * collected by quicc_bfe_probe() intact.
  113          */
  114         sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
  115             RF_ACTIVE);
  116         if (sc->sc_rres == NULL)
  117                 return (ENXIO);
  118 
  119         start = rman_get_start(sc->sc_rres);
  120         size = rman_get_size(sc->sc_rres);
  121 
  122         sc->sc_rman.rm_start = start;
  123         sc->sc_rman.rm_end = start + size - 1;
  124         sc->sc_rman.rm_type = RMAN_ARRAY;
  125         sc->sc_rman.rm_descr = "QUICC resources";
  126         error = rman_init(&sc->sc_rman);
  127         if (!error)
  128                 error = rman_manage_region(&sc->sc_rman, start,
  129                     start + size - 1);
  130         if (error) {
  131                 bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid,
  132                     sc->sc_rres);
  133                 return (error);
  134         }
  135 
  136         /*
  137          * Allocate interrupt resource.
  138          */
  139         sc->sc_irid = 0;
  140         sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
  141             RF_ACTIVE | RF_SHAREABLE);
  142 
  143         if (sc->sc_ires != NULL) {
  144                 error = bus_setup_intr(dev, sc->sc_ires,
  145                     INTR_TYPE_TTY, quicc_bfe_intr, NULL, sc, &sc->sc_icookie);
  146                 if (error) {
  147                         error = bus_setup_intr(dev, sc->sc_ires,
  148                             INTR_TYPE_TTY | INTR_MPSAFE, NULL,
  149                             (driver_intr_t *)quicc_bfe_intr, sc,
  150                             &sc->sc_icookie);
  151                 } else
  152                         sc->sc_fastintr = 1;
  153                 if (error) {
  154                         device_printf(dev, "could not activate interrupt\n");
  155                         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
  156                             sc->sc_ires);
  157                         sc->sc_ires = NULL;
  158                 }
  159         }
  160 
  161         if (sc->sc_ires == NULL)
  162                 sc->sc_polled = 1;
  163 
  164         if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
  165                 sep = "";
  166                 device_print_prettyname(dev);
  167                 if (sc->sc_fastintr) {
  168                         printf("%sfast interrupt", sep);
  169                         sep = ", ";
  170                 }
  171                 if (sc->sc_polled) {
  172                         printf("%spolled mode", sep);
  173                         sep = ", ";
  174                 }
  175                 printf("\n");
  176         }
  177 
  178         sc->sc_device = qd = malloc(sizeof(struct quicc_device), M_QUICC,
  179             M_WAITOK | M_ZERO);
  180 
  181         qd->qd_devtype = QUICC_DEVTYPE_SCC;
  182         qd->qd_rman = &sc->sc_rman;
  183         resource_list_init(&qd->qd_rlist);
  184 
  185         resource_list_add(&qd->qd_rlist, sc->sc_rtype, 0, start,
  186             start + size - 1, size);
  187 
  188         resource_list_add(&qd->qd_rlist, SYS_RES_IRQ, 0, 0xf00, 0xf00, 1);
  189         rle = resource_list_find(&qd->qd_rlist, SYS_RES_IRQ, 0);
  190         rle->res = sc->sc_ires;
  191 
  192         qd->qd_dev = device_add_child(dev, NULL, -1);
  193         device_set_ivars(qd->qd_dev, (void *)qd);
  194         error = device_probe_and_attach(qd->qd_dev);
  195 
  196         /* Enable all SCC interrupts. */
  197         quicc_write4(sc->sc_rres, QUICC_REG_SIMR_L, 0x00f00000);
  198 
  199         /* Clear all pending interrupts. */
  200         quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_H, ~0);
  201         quicc_write4(sc->sc_rres, QUICC_REG_SIPNR_L, ~0);
  202         return (error);
  203 }
  204 
  205 int
  206 quicc_bfe_detach(device_t dev)
  207 {
  208         struct quicc_softc *sc;
  209 
  210         sc = device_get_softc(dev);
  211 
  212         bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  213         bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires);
  214         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  215         return (0);
  216 }
  217 
  218 int
  219 quicc_bfe_probe(device_t dev, u_int clock)
  220 {
  221         struct quicc_softc *sc;
  222         uint16_t rev;
  223 
  224         sc = device_get_softc(dev);
  225         sc->sc_dev = dev;
  226         if (device_get_desc(dev) == NULL)
  227                 device_set_desc(dev,
  228                     "Quad integrated communications controller");
  229 
  230         sc->sc_rrid = 0;
  231         sc->sc_rtype = SYS_RES_MEMORY;
  232         sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
  233             RF_ACTIVE);
  234         if (sc->sc_rres == NULL) {
  235                 sc->sc_rrid = 0;
  236                 sc->sc_rtype = SYS_RES_IOPORT;
  237                 sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype,
  238                     &sc->sc_rrid, RF_ACTIVE);
  239                 if (sc->sc_rres == NULL)
  240                         return (ENXIO);
  241         }
  242 
  243         sc->sc_clock = clock;
  244 
  245         /*
  246          * Check that the microcode revision is 0x00e8, as documented
  247          * in the MPC8555E PowerQUICC III Integrated Processor Family
  248          * Reference Manual.
  249          */
  250         rev = quicc_read2(sc->sc_rres, QUICC_PRAM_REV_NUM);
  251 
  252         bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
  253         return ((rev == 0x00e8) ? BUS_PROBE_DEFAULT : ENXIO);
  254 }
  255 
  256 struct resource *
  257 quicc_bus_alloc_resource(device_t dev, device_t child, int type, int *rid,
  258     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  259 {
  260         struct quicc_device *qd;
  261         struct resource_list_entry *rle;
  262 
  263         if (device_get_parent(child) != dev)
  264                 return (NULL);
  265 
  266         /* We only support default allocations. */
  267         if (!RMAN_IS_DEFAULT_RANGE(start, end))
  268                 return (NULL);
  269 
  270         qd = device_get_ivars(child);
  271         rle = resource_list_find(&qd->qd_rlist, type, *rid);
  272         if (rle == NULL)
  273                 return (NULL);
  274 
  275         if (rle->res == NULL) {
  276                 rle->res = rman_reserve_resource(qd->qd_rman, rle->start,
  277                     rle->start + rle->count - 1, rle->count, flags, child);
  278                 if (rle->res != NULL) {
  279                         rman_set_bustag(rle->res, &bs_be_tag);
  280                         rman_set_bushandle(rle->res, rle->start);
  281                 }
  282         }
  283         return (rle->res);
  284 }
  285 
  286 int
  287 quicc_bus_get_resource(device_t dev, device_t child, int type, int rid,
  288     rman_res_t *startp, rman_res_t *countp)
  289 {
  290         struct quicc_device *qd;
  291         struct resource_list_entry *rle;
  292 
  293         if (device_get_parent(child) != dev)
  294                 return (EINVAL);
  295 
  296         qd = device_get_ivars(child);
  297         rle = resource_list_find(&qd->qd_rlist, type, rid);
  298         if (rle == NULL)
  299                 return (EINVAL);
  300 
  301         if (startp != NULL)
  302                 *startp = rle->start;
  303         if (countp != NULL)
  304                 *countp = rle->count;
  305         return (0);
  306 }
  307 
  308 int
  309 quicc_bus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
  310 {
  311         struct quicc_device *qd;
  312         struct quicc_softc *sc;
  313         uint32_t sccr;
  314 
  315         if (device_get_parent(child) != dev)
  316                 return (EINVAL);
  317 
  318         sc = device_get_softc(dev);
  319         qd = device_get_ivars(child);
  320 
  321         switch (index) {
  322         case QUICC_IVAR_CLOCK:
  323                 *result = sc->sc_clock;
  324                 break;
  325         case QUICC_IVAR_BRGCLK:
  326                 sccr = quicc_read4(sc->sc_rres, QUICC_REG_SCCR) & 3;
  327                 *result = sc->sc_clock / ((1 << (sccr + 1)) << sccr);
  328                 break;
  329         case QUICC_IVAR_DEVTYPE:
  330                 *result = qd->qd_devtype;
  331                 break;
  332         default:
  333                 return (EINVAL);
  334         }
  335         return (0);
  336 }
  337 
  338 int
  339 quicc_bus_release_resource(device_t dev, device_t child, int type, int rid,
  340     struct resource *res)
  341 {
  342         struct quicc_device *qd;
  343         struct resource_list_entry *rle;
  344 
  345         if (device_get_parent(child) != dev)
  346                 return (EINVAL);
  347 
  348         qd = device_get_ivars(child);
  349         rle = resource_list_find(&qd->qd_rlist, type, rid);
  350         return ((rle == NULL) ? EINVAL : 0);
  351 }
  352 
  353 int
  354 quicc_bus_setup_intr(device_t dev, device_t child, struct resource *r,
  355     int flags, driver_filter_t *filt, void (*ihand)(void *), void *arg,
  356     void **cookiep)
  357 {
  358         struct quicc_device *qd;
  359         struct quicc_softc *sc;
  360 
  361         if (device_get_parent(child) != dev)
  362                 return (EINVAL);
  363 
  364         /* Interrupt handlers must be FAST or MPSAFE. */
  365         if (filt == NULL && !(flags & INTR_MPSAFE))
  366                 return (EINVAL);
  367 
  368         sc = device_get_softc(dev);
  369         if (sc->sc_polled)
  370                 return (ENXIO);
  371 
  372         if (sc->sc_fastintr && filt == NULL) {
  373                 sc->sc_fastintr = 0;
  374                 bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
  375                 bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE,
  376                     NULL, (driver_intr_t *)quicc_bfe_intr, sc, &sc->sc_icookie);
  377         }
  378 
  379         qd = device_get_ivars(child);
  380         qd->qd_ih = (filt != NULL) ? filt : (driver_filter_t *)ihand;
  381         qd->qd_ih_arg = arg;
  382         *cookiep = ihand;
  383         return (0);
  384 }
  385 
  386 int
  387 quicc_bus_teardown_intr(device_t dev, device_t child, struct resource *r,
  388     void *cookie)
  389 {
  390         struct quicc_device *qd;
  391 
  392         if (device_get_parent(child) != dev)
  393                 return (EINVAL);
  394 
  395         qd = device_get_ivars(child);
  396         if (qd->qd_ih != cookie)
  397                 return (EINVAL);
  398 
  399         qd->qd_ih = NULL;
  400         qd->qd_ih_arg = NULL;
  401         return (0);
  402 }

Cache object: 530552523f013988532e0a16da25f1dd


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