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/arm/ti/ti_pruss.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-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2013 Rui Paulo <rpaulo@FreeBSD.org>
    5  * Copyright (c) 2017 Manuel Stuehn
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27  * POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/poll.h>
   33 #include <sys/time.h>
   34 #include <sys/uio.h>
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/fcntl.h>
   38 #include <sys/bus.h>
   39 #include <sys/conf.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/module.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mutex.h>
   45 #include <sys/rman.h>
   46 #include <sys/types.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/event.h>
   49 #include <sys/selinfo.h>
   50 #include <machine/bus.h>
   51 #include <machine/cpu.h>
   52 #include <machine/frame.h>
   53 #include <machine/intr.h>
   54 #include <machine/atomic.h>
   55 
   56 #include <dev/ofw/openfirm.h>
   57 #include <dev/ofw/ofw_bus.h>
   58 #include <dev/ofw/ofw_bus_subr.h>
   59 
   60 #include <dev/extres/clk/clk.h>
   61 
   62 #include <arm/ti/ti_sysc.h>
   63 #include <arm/ti/ti_pruss.h>
   64 #include <arm/ti/ti_prm.h>
   65 
   66 #ifdef DEBUG
   67 #define DPRINTF(fmt, ...)       do {    \
   68         printf("%s: ", __func__);       \
   69         printf(fmt, __VA_ARGS__);       \
   70 } while (0)
   71 #else
   72 #define DPRINTF(fmt, ...)
   73 #endif
   74 
   75 static d_open_t                 ti_pruss_irq_open;
   76 static d_read_t                 ti_pruss_irq_read;
   77 static d_poll_t                 ti_pruss_irq_poll;
   78 
   79 static device_probe_t           ti_pruss_probe;
   80 static device_attach_t          ti_pruss_attach;
   81 static device_detach_t          ti_pruss_detach;
   82 static void                     ti_pruss_intr(void *);
   83 static d_open_t                 ti_pruss_open;
   84 static d_mmap_t                 ti_pruss_mmap;
   85 static void                     ti_pruss_irq_kqread_detach(struct knote *);
   86 static int                      ti_pruss_irq_kqevent(struct knote *, long);
   87 static d_kqfilter_t             ti_pruss_irq_kqfilter;
   88 static void                     ti_pruss_privdtor(void *data);
   89 
   90 #define TI_PRUSS_PRU_IRQS 2
   91 #define TI_PRUSS_HOST_IRQS 8
   92 #define TI_PRUSS_IRQS (TI_PRUSS_HOST_IRQS+TI_PRUSS_PRU_IRQS)
   93 #define TI_PRUSS_EVENTS 64
   94 #define NOT_SET_STR "NONE"
   95 #define TI_TS_ARRAY 16
   96 
   97 struct ctl
   98 {
   99         size_t cnt;
  100         size_t idx;
  101 };
  102 
  103 struct ts_ring_buf
  104 {
  105         struct ctl ctl;
  106         uint64_t ts[TI_TS_ARRAY];
  107 };
  108 
  109 struct ti_pruss_irqsc
  110 {
  111         struct mtx              sc_mtx;
  112         struct cdev             *sc_pdev;
  113         struct selinfo          sc_selinfo;
  114         int8_t                  channel;
  115         int8_t                  last;
  116         int8_t                  event;
  117         bool                    enable;
  118         struct ts_ring_buf      tstamps;
  119 };
  120 
  121 static struct cdevsw ti_pruss_cdevirq = {
  122         .d_version =    D_VERSION,
  123         .d_name =       "ti_pruss_irq",
  124         .d_open =       ti_pruss_irq_open,
  125         .d_read =       ti_pruss_irq_read,
  126         .d_poll =       ti_pruss_irq_poll,
  127         .d_kqfilter =   ti_pruss_irq_kqfilter,
  128 };
  129 
  130 struct ti_pruss_softc {
  131         struct mtx              sc_mtx;
  132         struct resource         *sc_mem_res;
  133         struct resource         *sc_irq_res[TI_PRUSS_HOST_IRQS];
  134         void                    *sc_intr[TI_PRUSS_HOST_IRQS];
  135         struct ti_pruss_irqsc   sc_irq_devs[TI_PRUSS_IRQS];
  136         bus_space_tag_t         sc_bt;
  137         bus_space_handle_t      sc_bh;
  138         struct cdev             *sc_pdev;
  139         struct selinfo          sc_selinfo;
  140         bool                    sc_glob_irqen;
  141 };
  142 
  143 static struct cdevsw ti_pruss_cdevsw = {
  144         .d_version =    D_VERSION,
  145         .d_name =       "ti_pruss",
  146         .d_open =       ti_pruss_open,
  147         .d_mmap =       ti_pruss_mmap,
  148 };
  149 
  150 static device_method_t ti_pruss_methods[] = {
  151         DEVMETHOD(device_probe,         ti_pruss_probe),
  152         DEVMETHOD(device_attach,        ti_pruss_attach),
  153         DEVMETHOD(device_detach,        ti_pruss_detach),
  154 
  155         DEVMETHOD_END
  156 };
  157 
  158 static driver_t ti_pruss_driver = {
  159         "ti_pruss",
  160         ti_pruss_methods,
  161         sizeof(struct ti_pruss_softc)
  162 };
  163 
  164 DRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, 0, 0);
  165 MODULE_DEPEND(ti_pruss, ti_sysc, 1, 1, 1);
  166 MODULE_DEPEND(ti_pruss, ti_prm, 1, 1, 1);
  167 
  168 static struct resource_spec ti_pruss_irq_spec[] = {
  169         { SYS_RES_IRQ,      0,  RF_ACTIVE },
  170         { SYS_RES_IRQ,      1,  RF_ACTIVE },
  171         { SYS_RES_IRQ,      2,  RF_ACTIVE },
  172         { SYS_RES_IRQ,      3,  RF_ACTIVE },
  173         { SYS_RES_IRQ,      4,  RF_ACTIVE },
  174         { SYS_RES_IRQ,      5,  RF_ACTIVE },
  175         { SYS_RES_IRQ,      6,  RF_ACTIVE },
  176         { SYS_RES_IRQ,      7,  RF_ACTIVE },
  177         { -1,               0,  0 }
  178 };
  179 CTASSERT(TI_PRUSS_HOST_IRQS == nitems(ti_pruss_irq_spec) - 1);
  180 
  181 static int
  182 ti_pruss_irq_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  183 {
  184         struct ctl* irqs;
  185         struct ti_pruss_irqsc *sc;
  186         sc = dev->si_drv1;
  187 
  188         irqs = malloc(sizeof(struct ctl), M_DEVBUF, M_WAITOK);
  189         if (!irqs)
  190             return (ENOMEM);
  191 
  192         irqs->cnt = sc->tstamps.ctl.cnt;
  193         irqs->idx = sc->tstamps.ctl.idx;
  194 
  195         return devfs_set_cdevpriv(irqs, ti_pruss_privdtor);
  196 }
  197 
  198 static void
  199 ti_pruss_privdtor(void *data)
  200 {
  201     free(data, M_DEVBUF);
  202 }
  203 
  204 static int
  205 ti_pruss_irq_poll(struct cdev *dev, int events, struct thread *td)
  206 {
  207         struct ctl* irqs;
  208         struct ti_pruss_irqsc *sc;
  209         sc = dev->si_drv1;
  210 
  211         devfs_get_cdevpriv((void**)&irqs);
  212 
  213         if (events & (POLLIN | POLLRDNORM)) {
  214                 if (sc->tstamps.ctl.cnt != irqs->cnt)
  215                         return events & (POLLIN | POLLRDNORM);
  216                 else
  217                         selrecord(td, &sc->sc_selinfo);
  218         }
  219         return 0;
  220 }
  221 
  222 static int
  223 ti_pruss_irq_read(struct cdev *cdev, struct uio *uio, int ioflag)
  224 {
  225         const size_t ts_len = sizeof(uint64_t);
  226         struct ti_pruss_irqsc* irq;
  227         struct ctl* priv;
  228         int error = 0;
  229         size_t idx;
  230         ssize_t level;
  231 
  232         irq = cdev->si_drv1;
  233 
  234         if (uio->uio_resid < ts_len)
  235                 return (EINVAL);
  236 
  237         error = devfs_get_cdevpriv((void**)&priv);
  238         if (error)
  239             return (error);
  240 
  241         mtx_lock(&irq->sc_mtx);
  242 
  243         if (irq->tstamps.ctl.cnt - priv->cnt > TI_TS_ARRAY)
  244         {
  245                 priv->cnt = irq->tstamps.ctl.cnt;
  246                 priv->idx = irq->tstamps.ctl.idx;
  247                 mtx_unlock(&irq->sc_mtx);
  248                 return (ENXIO);
  249         }
  250 
  251         do {
  252                 idx = priv->idx;
  253                 level = irq->tstamps.ctl.idx - idx;
  254                 if (level < 0)
  255                         level += TI_TS_ARRAY;
  256 
  257                 if (level == 0) {
  258                         if (ioflag & O_NONBLOCK) {
  259                                 mtx_unlock(&irq->sc_mtx);
  260                                 return (EWOULDBLOCK);
  261                         }
  262 
  263                         error = msleep(irq, &irq->sc_mtx, PCATCH | PDROP,
  264                                 "pruirq", 0);
  265                         if (error)
  266                                 return error;
  267 
  268                         mtx_lock(&irq->sc_mtx);
  269                 }
  270         }while(level == 0);
  271 
  272         mtx_unlock(&irq->sc_mtx);
  273 
  274         error = uiomove(&irq->tstamps.ts[idx], ts_len, uio);
  275 
  276         if (++idx == TI_TS_ARRAY)
  277                 idx = 0;
  278         priv->idx = idx;
  279 
  280         atomic_add_32(&priv->cnt, 1);
  281 
  282         return (error);
  283 }
  284 
  285 static struct ti_pruss_irq_arg {
  286         int                    irq;
  287         struct ti_pruss_softc *sc;
  288 } ti_pruss_irq_args[TI_PRUSS_IRQS];
  289 
  290 static __inline uint32_t
  291 ti_pruss_reg_read(struct ti_pruss_softc *sc, uint32_t reg)
  292 {
  293         return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
  294 }
  295 
  296 static __inline void
  297 ti_pruss_reg_write(struct ti_pruss_softc *sc, uint32_t reg, uint32_t val)
  298 {
  299         bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
  300 }
  301 
  302 static __inline void
  303 ti_pruss_interrupts_clear(struct ti_pruss_softc *sc)
  304 {
  305         /* disable global interrupt */
  306         ti_pruss_reg_write(sc, PRUSS_INTC_GER, 0 );
  307 
  308         /* clear all events */
  309         ti_pruss_reg_write(sc, PRUSS_INTC_SECR0, 0xFFFFFFFF);
  310         ti_pruss_reg_write(sc, PRUSS_INTC_SECR1, 0xFFFFFFFF);
  311 
  312         /* disable all host interrupts */
  313         ti_pruss_reg_write(sc, PRUSS_INTC_HIER, 0);
  314 }
  315 
  316 static __inline int
  317 ti_pruss_interrupts_enable(struct ti_pruss_softc *sc, int8_t irq, bool enable)
  318 {
  319         if (enable && ((sc->sc_irq_devs[irq].channel == -1) ||
  320             (sc->sc_irq_devs[irq].event== -1)))
  321         {
  322                 device_printf( sc->sc_pdev->si_drv1,
  323                         "Interrupt chain not fully configured, not possible to enable\n" );
  324                 return (EINVAL);
  325         }
  326 
  327         sc->sc_irq_devs[irq].enable = enable;
  328 
  329         if (sc->sc_irq_devs[irq].sc_pdev) {
  330                 destroy_dev(sc->sc_irq_devs[irq].sc_pdev);
  331                 sc->sc_irq_devs[irq].sc_pdev = NULL;
  332         }
  333 
  334         if (enable) {
  335                 sc->sc_irq_devs[irq].sc_pdev = make_dev(&ti_pruss_cdevirq, 0, UID_ROOT, GID_WHEEL,
  336                     0600, "pruss%d.irq%d", device_get_unit(sc->sc_pdev->si_drv1), irq);
  337                 sc->sc_irq_devs[irq].sc_pdev->si_drv1 = &sc->sc_irq_devs[irq];
  338 
  339                 sc->sc_irq_devs[irq].tstamps.ctl.idx = 0;
  340         }
  341 
  342         uint32_t reg = enable ? PRUSS_INTC_HIEISR : PRUSS_INTC_HIDISR;
  343         ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].channel);
  344 
  345         reg = enable ? PRUSS_INTC_EISR : PRUSS_INTC_EICR;
  346         ti_pruss_reg_write(sc, reg, sc->sc_irq_devs[irq].event );
  347 
  348         return (0);
  349 }
  350 
  351 static __inline void
  352 ti_pruss_map_write(struct ti_pruss_softc *sc, uint32_t basereg, uint8_t index, uint8_t content)
  353 {
  354         const size_t regadr = basereg + index & ~0x03;
  355         const size_t bitpos = (index & 0x03) * 8;
  356         uint32_t rmw = ti_pruss_reg_read(sc, regadr);
  357         rmw = (rmw & ~( 0xF << bitpos)) | ( (content & 0xF) << bitpos);
  358         ti_pruss_reg_write(sc, regadr, rmw);
  359 }
  360 
  361 static int
  362 ti_pruss_event_map( SYSCTL_HANDLER_ARGS )
  363 {
  364         struct ti_pruss_softc *sc;
  365         const int8_t irq = arg2;
  366         int err;
  367         char event[sizeof(NOT_SET_STR)];
  368 
  369         sc = arg1;
  370 
  371         if(sc->sc_irq_devs[irq].event == -1)
  372                 bcopy(NOT_SET_STR, event, sizeof(event));
  373         else
  374                 snprintf(event, sizeof(event), "%d", sc->sc_irq_devs[irq].event);
  375 
  376         err = sysctl_handle_string(oidp, event, sizeof(event), req);
  377         if(err != 0)
  378                 return (err);
  379 
  380         if (req->newptr) {  // write event
  381                 if (strcmp(NOT_SET_STR, event) == 0) {
  382                         ti_pruss_interrupts_enable(sc, irq, false);
  383                         sc->sc_irq_devs[irq].event = -1;
  384                 } else {
  385                         if (sc->sc_irq_devs[irq].channel == -1) {
  386                                 device_printf( sc->sc_pdev->si_drv1,
  387                                         "corresponding channel not configured\n");
  388                                 return (ENXIO);
  389                         }
  390 
  391                         const int8_t channelnr = sc->sc_irq_devs[irq].channel;
  392                         const int8_t eventnr = strtol( event, NULL, 10 ); // TODO: check if strol is valid
  393                         if (eventnr > TI_PRUSS_EVENTS || eventnr < 0) {
  394                                 device_printf( sc->sc_pdev->si_drv1,
  395                                         "Event number %d not valid (0 - %d)",
  396                                         channelnr, TI_PRUSS_EVENTS -1);
  397                                 return (EINVAL);
  398                         }
  399 
  400                         sc->sc_irq_devs[irq].channel = channelnr;
  401                         sc->sc_irq_devs[irq].event = eventnr;
  402 
  403                         // event[nr] <= channel
  404                         ti_pruss_map_write(sc, PRUSS_INTC_CMR_BASE,
  405                             eventnr, channelnr);
  406                 }
  407         }
  408         return (err);
  409 }
  410 
  411 static int
  412 ti_pruss_channel_map(SYSCTL_HANDLER_ARGS)
  413 {
  414         struct ti_pruss_softc *sc;
  415         int err;
  416         char channel[sizeof(NOT_SET_STR)];
  417         const int8_t irq = arg2;
  418 
  419         sc = arg1;
  420 
  421         if (sc->sc_irq_devs[irq].channel == -1)
  422                 bcopy(NOT_SET_STR, channel, sizeof(channel));
  423         else
  424                 snprintf(channel, sizeof(channel), "%d", sc->sc_irq_devs[irq].channel);
  425 
  426         err = sysctl_handle_string(oidp, channel, sizeof(channel), req);
  427         if (err != 0)
  428                 return (err);
  429 
  430         if (req->newptr) { // write event
  431                 if (strcmp(NOT_SET_STR, channel) == 0) {
  432                         ti_pruss_interrupts_enable(sc, irq, false);
  433                         ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR,
  434                             sc->sc_irq_devs[irq].channel);
  435                         sc->sc_irq_devs[irq].channel = -1;
  436                 } else {
  437                         const int8_t channelnr = strtol(channel, NULL, 10); // TODO: check if strol is valid
  438                         if (channelnr > TI_PRUSS_IRQS || channelnr < 0)
  439                         {
  440                                 device_printf(sc->sc_pdev->si_drv1,
  441                                         "Channel number %d not valid (0 - %d)",
  442                                         channelnr, TI_PRUSS_IRQS-1);
  443                                 return (EINVAL);
  444                         }
  445 
  446                         sc->sc_irq_devs[irq].channel = channelnr;
  447                         sc->sc_irq_devs[irq].last = -1;
  448 
  449                         // channel[nr] <= irqnr
  450                         ti_pruss_map_write(sc, PRUSS_INTC_HMR_BASE,
  451                                 irq, channelnr);
  452                 }
  453         }
  454 
  455         return (err);
  456 }
  457 
  458 static int
  459 ti_pruss_interrupt_enable(SYSCTL_HANDLER_ARGS)
  460 {
  461         struct ti_pruss_softc *sc;
  462         int err;
  463         bool irqenable;
  464         const int8_t irq = arg2;
  465 
  466         sc = arg1;
  467         irqenable = sc->sc_irq_devs[arg2].enable;
  468 
  469         err = sysctl_handle_bool(oidp, &irqenable, arg2, req);
  470         if (err != 0)
  471                 return (err);
  472 
  473         if (req->newptr) // write enable
  474                 return ti_pruss_interrupts_enable(sc, irq, irqenable);
  475 
  476         return (err);
  477 }
  478 
  479 static int
  480 ti_pruss_global_interrupt_enable(SYSCTL_HANDLER_ARGS)
  481 {
  482         struct ti_pruss_softc *sc;
  483         int err;
  484         bool glob_irqen;
  485 
  486         sc = arg1;
  487         glob_irqen = sc->sc_glob_irqen;
  488 
  489         err = sysctl_handle_bool(oidp, &glob_irqen, arg2, req);
  490         if (err != 0)
  491                 return (err);
  492 
  493         if (req->newptr) {
  494                 sc->sc_glob_irqen = glob_irqen;
  495                 ti_pruss_reg_write(sc, PRUSS_INTC_GER, glob_irqen);
  496         }
  497 
  498         return (err);
  499 }
  500 static int
  501 ti_pruss_probe(device_t dev)
  502 {
  503 
  504         if (!ofw_bus_status_okay(dev))
  505                 return (ENXIO);
  506 
  507         if (ofw_bus_is_compatible(dev, "ti,pruss-v1") ||
  508             ofw_bus_is_compatible(dev, "ti,pruss-v2")) {
  509                 device_set_desc(dev, "TI Programmable Realtime Unit Subsystem");
  510                 return (BUS_PROBE_DEFAULT);
  511         }
  512 
  513         return (ENXIO);
  514 }
  515 
  516 static int
  517 ti_pruss_attach(device_t dev)
  518 {
  519         struct ti_pruss_softc *sc;
  520         int rid, i, err, ncells;
  521         phandle_t node;
  522         clk_t l3_gclk, pruss_ocp_gclk;
  523         phandle_t ti_prm_ref, *cells;
  524         device_t ti_prm_dev;
  525 
  526         rid = 0;
  527         sc = device_get_softc(dev);
  528         node = ofw_bus_get_node(device_get_parent(dev));
  529         if (node <= 0) {
  530                 device_printf(dev, "Cant get ofw node\n");
  531                 return (ENXIO);
  532         }
  533 
  534         /*
  535          * Follow activate pattern from sys/arm/ti/am335x/am335x_prcm.c
  536          * by Damjan Marion
  537          */
  538 
  539         /* Set MODULEMODE to ENABLE(2) */
  540         /* Wait for MODULEMODE to become ENABLE(2) */
  541         if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) {
  542                 device_printf(dev, "Could not enable PRUSS clock\n");
  543                 return (ENXIO);
  544         }
  545 
  546         /* Set CLKTRCTRL to SW_WKUP(2) */
  547         /* Wait for the 200 MHz OCP clock to become active */
  548         /* Wait for the 200 MHz IEP clock to become active */
  549         /* Wait for the 192 MHz UART clock to become active */
  550         /*
  551          * At the moment there is no reference to CM_PER_PRU_ICSS_CLKSTCTRL@140
  552          * in the devicetree. The register reset state are SW_WKUP(2) as default
  553          * so at the moment ignore setting this register.
  554          */
  555 
  556         /* Select L3F as OCP clock */
  557         /* Get the clock and set the parent */
  558         err = clk_get_by_name(dev, "l3_gclk", &l3_gclk);
  559         if (err) {
  560                 device_printf(dev, "Cant get l3_gclk err %d\n", err);
  561                 return (ENXIO);
  562         }
  563 
  564         err = clk_get_by_name(dev, "pruss_ocp_gclk@530", &pruss_ocp_gclk);
  565         if (err) {
  566                 device_printf(dev, "Cant get pruss_ocp_gclk@530 err %d\n", err);
  567                 return (ENXIO);
  568         }
  569 
  570         err = clk_set_parent_by_clk(pruss_ocp_gclk, l3_gclk);
  571         if (err) {
  572                 device_printf(dev,
  573                     "Cant set pruss_ocp_gclk parent to l3_gclk err %d\n", err);
  574                 return (ENXIO);
  575         }
  576 
  577         /* Clear the RESET bit */
  578         /* Find the ti_prm */
  579         /* #reset-cells should not been used in this way but... */
  580         err = ofw_bus_parse_xref_list_alloc(node, "resets", "#reset-cells", 0,
  581             &ti_prm_ref, &ncells, &cells);
  582         OF_prop_free(cells);
  583         if (err) {
  584                 device_printf(dev,
  585                     "Cant fetch \"resets\" reference %x\n", err);
  586                 return (ENXIO);
  587         }
  588 
  589         ti_prm_dev = OF_device_from_xref(ti_prm_ref);
  590         if (ti_prm_dev == NULL) {
  591                 device_printf(dev, "Cant get device from \"resets\"\n");
  592                 return (ENXIO);
  593         }
  594 
  595         err = ti_prm_reset(ti_prm_dev);
  596         if (err) {
  597                 device_printf(dev, "ti_prm_reset failed %d\n", err);
  598                 return (ENXIO);
  599         }
  600         /* End of clock activation */
  601 
  602         mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF);
  603         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  604             RF_ACTIVE);
  605         if (sc->sc_mem_res == NULL) {
  606                 device_printf(dev, "could not allocate memory resource\n");
  607                 return (ENXIO);
  608         }
  609 
  610         struct sysctl_ctx_list *clist = device_get_sysctl_ctx(dev);
  611         if (!clist)
  612                 return (EINVAL);
  613 
  614         struct sysctl_oid *poid;
  615         poid = device_get_sysctl_tree( dev );
  616         if (!poid)
  617                 return (EINVAL);
  618 
  619         sc->sc_glob_irqen = false;
  620         struct sysctl_oid *irq_root = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(poid),
  621             OID_AUTO, "irq", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
  622             "PRUSS Host Interrupts");
  623         SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(poid), OID_AUTO,
  624             "global_interrupt_enable",
  625             CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
  626             sc, 0, ti_pruss_global_interrupt_enable,
  627             "CU", "Global interrupt enable");
  628 
  629         sc->sc_bt = rman_get_bustag(sc->sc_mem_res);
  630         sc->sc_bh = rman_get_bushandle(sc->sc_mem_res);
  631         if (bus_alloc_resources(dev, ti_pruss_irq_spec, sc->sc_irq_res) != 0) {
  632                 device_printf(dev, "could not allocate interrupt resource\n");
  633                 ti_pruss_detach(dev);
  634                 return (ENXIO);
  635         }
  636 
  637         ti_pruss_interrupts_clear(sc);
  638 
  639         for (i = 0; i < TI_PRUSS_IRQS; i++) {
  640                 char name[8];
  641                 snprintf(name, sizeof(name), "%d", i);
  642 
  643                 struct sysctl_oid *irq_nodes = SYSCTL_ADD_NODE(clist, SYSCTL_CHILDREN(irq_root),
  644                     OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
  645                     "PRUSS Interrupts");
  646                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
  647                     "channel", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
  648                     sc, i, ti_pruss_channel_map,
  649                     "A", "Channel attached to this irq");
  650                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
  651                     "event", CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT,
  652                     sc, i, ti_pruss_event_map,
  653                     "A", "Event attached to this irq");
  654                 SYSCTL_ADD_PROC(clist, SYSCTL_CHILDREN(irq_nodes), OID_AUTO,
  655                     "enable", CTLFLAG_RW | CTLTYPE_U8 | CTLFLAG_NEEDGIANT,
  656                     sc, i, ti_pruss_interrupt_enable,
  657                     "CU", "Enable/Disable interrupt");
  658 
  659                 sc->sc_irq_devs[i].event = -1;
  660                 sc->sc_irq_devs[i].channel = -1;
  661                 sc->sc_irq_devs[i].tstamps.ctl.idx = 0;
  662 
  663                 if (i < TI_PRUSS_HOST_IRQS) {
  664                         ti_pruss_irq_args[i].irq = i;
  665                         ti_pruss_irq_args[i].sc = sc;
  666                         if (bus_setup_intr(dev, sc->sc_irq_res[i],
  667                             INTR_MPSAFE | INTR_TYPE_MISC,
  668                             NULL, ti_pruss_intr, &ti_pruss_irq_args[i],
  669                             &sc->sc_intr[i]) != 0) {
  670                                 device_printf(dev,
  671                                     "unable to setup the interrupt handler\n");
  672                                 ti_pruss_detach(dev);
  673 
  674                                 return (ENXIO);
  675                         }
  676                         mtx_init(&sc->sc_irq_devs[i].sc_mtx, "TI PRUSS IRQ", NULL, MTX_DEF);
  677                         knlist_init_mtx(&sc->sc_irq_devs[i].sc_selinfo.si_note, &sc->sc_irq_devs[i].sc_mtx);
  678                 }
  679         }
  680 
  681         if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV)
  682                 device_printf(dev, "AM33xx PRU-ICSS\n");
  683 
  684         sc->sc_pdev = make_dev(&ti_pruss_cdevsw, 0, UID_ROOT, GID_WHEEL,
  685             0600, "pruss%d", device_get_unit(dev));
  686         sc->sc_pdev->si_drv1 = dev;
  687 
  688         /*  Acc. to datasheet always write 1 to polarity registers */
  689         ti_pruss_reg_write(sc, PRUSS_INTC_SIPR0, 0xFFFFFFFF);
  690         ti_pruss_reg_write(sc, PRUSS_INTC_SIPR1, 0xFFFFFFFF);
  691 
  692         /* Acc. to datasheet always write 0 to event type registers */
  693         ti_pruss_reg_write(sc, PRUSS_INTC_SITR0, 0);
  694         ti_pruss_reg_write(sc, PRUSS_INTC_SITR1, 0);
  695 
  696         return (0);
  697 }
  698 
  699 static int
  700 ti_pruss_detach(device_t dev)
  701 {
  702         struct ti_pruss_softc *sc = device_get_softc(dev);
  703 
  704         ti_pruss_interrupts_clear(sc);
  705 
  706         for (int i = 0; i < TI_PRUSS_HOST_IRQS; i++) {
  707                 ti_pruss_interrupts_enable( sc, i, false );
  708 
  709                 if (sc->sc_intr[i])
  710                         bus_teardown_intr(dev, sc->sc_irq_res[i], sc->sc_intr[i]);
  711                 if (sc->sc_irq_res[i])
  712                         bus_release_resource(dev, SYS_RES_IRQ,
  713                             rman_get_rid(sc->sc_irq_res[i]),
  714                             sc->sc_irq_res[i]);
  715                 knlist_clear(&sc->sc_irq_devs[i].sc_selinfo.si_note, 0);
  716                 mtx_lock(&sc->sc_irq_devs[i].sc_mtx);
  717                 if (!knlist_empty(&sc->sc_irq_devs[i].sc_selinfo.si_note))
  718                         printf("IRQ %d KQueue not empty!\n", i );
  719                 mtx_unlock(&sc->sc_irq_devs[i].sc_mtx);
  720                 knlist_destroy(&sc->sc_irq_devs[i].sc_selinfo.si_note);
  721                 mtx_destroy(&sc->sc_irq_devs[i].sc_mtx);
  722         }
  723 
  724         mtx_destroy(&sc->sc_mtx);
  725         if (sc->sc_mem_res)
  726                 bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res),
  727                     sc->sc_mem_res);
  728         if (sc->sc_pdev)
  729                 destroy_dev(sc->sc_pdev);
  730 
  731         return (0);
  732 }
  733 
  734 static void
  735 ti_pruss_intr(void *arg)
  736 {
  737         int val;
  738         struct ti_pruss_irq_arg *iap = arg;
  739         struct ti_pruss_softc *sc = iap->sc;
  740         /*
  741          * Interrupts pr1_host_intr[0:7] are mapped to
  742          * Host-2 to Host-9 of PRU-ICSS IRQ-controller.
  743          */
  744         const int pru_int = iap->irq + TI_PRUSS_PRU_IRQS;
  745         const int pru_int_mask = (1 << pru_int);
  746         const int pru_channel = sc->sc_irq_devs[pru_int].channel;
  747         const int pru_event = sc->sc_irq_devs[pru_channel].event;
  748 
  749         val = ti_pruss_reg_read(sc, PRUSS_INTC_HIER);
  750         if (!(val & pru_int_mask))
  751                 return;
  752 
  753         ti_pruss_reg_write(sc, PRUSS_INTC_HIDISR, pru_int);
  754         ti_pruss_reg_write(sc, PRUSS_INTC_SICR, pru_event);
  755         ti_pruss_reg_write(sc, PRUSS_INTC_HIEISR, pru_int);
  756 
  757         struct ti_pruss_irqsc* irq = &sc->sc_irq_devs[pru_channel];
  758         size_t wr = irq->tstamps.ctl.idx;
  759 
  760         struct timespec ts;
  761         nanouptime(&ts);
  762         irq->tstamps.ts[wr] = ts.tv_sec * 1000000000 + ts.tv_nsec;
  763 
  764         if (++wr == TI_TS_ARRAY)
  765                 wr = 0;
  766         atomic_add_32(&irq->tstamps.ctl.cnt, 1);
  767 
  768         irq->tstamps.ctl.idx = wr;
  769 
  770         KNOTE_UNLOCKED(&irq->sc_selinfo.si_note, pru_int);
  771         wakeup(irq);
  772         selwakeup(&irq->sc_selinfo);
  773 }
  774 
  775 static int
  776 ti_pruss_open(struct cdev *cdev __unused, int oflags __unused,
  777     int devtype __unused, struct thread *td __unused)
  778 {
  779         return (0);
  780 }
  781 
  782 static int
  783 ti_pruss_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
  784     int nprot, vm_memattr_t *memattr)
  785 {
  786         device_t dev = cdev->si_drv1;
  787         struct ti_pruss_softc *sc = device_get_softc(dev);
  788 
  789         if (offset >= rman_get_size(sc->sc_mem_res))
  790                 return (ENOSPC);
  791         *paddr = rman_get_start(sc->sc_mem_res) + offset;
  792         *memattr = VM_MEMATTR_UNCACHEABLE;
  793 
  794         return (0);
  795 }
  796 
  797 static struct filterops ti_pruss_kq_read = {
  798         .f_isfd = 1,
  799         .f_detach = ti_pruss_irq_kqread_detach,
  800         .f_event = ti_pruss_irq_kqevent,
  801 };
  802 
  803 static void
  804 ti_pruss_irq_kqread_detach(struct knote *kn)
  805 {
  806         struct ti_pruss_irqsc *sc = kn->kn_hook;
  807 
  808         knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
  809 }
  810 
  811 static int
  812 ti_pruss_irq_kqevent(struct knote *kn, long hint)
  813 {
  814     struct ti_pruss_irqsc* irq_sc;
  815     int notify;
  816 
  817     irq_sc = kn->kn_hook;
  818 
  819     if (hint > 0)
  820         kn->kn_data = hint - 2;
  821 
  822     if (hint > 0 || irq_sc->last > 0)
  823         notify = 1;
  824     else
  825         notify = 0;
  826 
  827     irq_sc->last = hint;
  828 
  829     return (notify);
  830 }
  831 
  832 static int
  833 ti_pruss_irq_kqfilter(struct cdev *cdev, struct knote *kn)
  834 {
  835         struct ti_pruss_irqsc *sc = cdev->si_drv1;
  836 
  837         switch (kn->kn_filter) {
  838         case EVFILT_READ:
  839                 kn->kn_hook = sc;
  840                 kn->kn_fop = &ti_pruss_kq_read;
  841                 knlist_add(&sc->sc_selinfo.si_note, kn, 0);
  842                 break;
  843         default:
  844                 return (EINVAL);
  845         }
  846 
  847         return (0);
  848 }

Cache object: 76f36e3c9bf143781d16c53acfb53f51


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