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/sbus/stp4020.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 /*      $NetBSD: stp4020.c,v 1.35.2.1 2004/05/20 09:47:49 tron Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Paul Kranenburg.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * STP4020: SBus/PCMCIA bridge supporting two Type-3 PCMCIA cards.
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: stp4020.c,v 1.35.2.1 2004/05/20 09:47:49 tron Exp $");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/errno.h>
   49 #include <sys/malloc.h>
   50 #include <sys/extent.h>
   51 #include <sys/proc.h>
   52 #include <sys/kernel.h>
   53 #include <sys/kthread.h>
   54 #include <sys/device.h>
   55 
   56 #include <dev/pcmcia/pcmciareg.h>
   57 #include <dev/pcmcia/pcmciavar.h>
   58 #include <dev/pcmcia/pcmciachip.h>
   59 
   60 #include <machine/bus.h>
   61 #include <machine/intr.h>
   62 
   63 #include <dev/sbus/sbusvar.h>
   64 #include <dev/sbus/stp4020reg.h>
   65 
   66 #define STP4020_DEBUG 1 /* XXX-temp */
   67 
   68 /*
   69  * We use the three available windows per socket in a simple, fixed
   70  * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
   71  * spaces into sbus space.
   72  */
   73 #define STP_WIN_ATTR    0       /* index of the attribute memory space window */
   74 #define STP_WIN_MEM     1       /* index of the common memory space window */
   75 #define STP_WIN_IO      2       /* index of the io space window */
   76 
   77 
   78 #if defined(STP4020_DEBUG)
   79 int stp4020_debug = 0;
   80 #define DPRINTF(x)      do { if (stp4020_debug) printf x; } while(0)
   81 #else
   82 #define DPRINTF(x)
   83 #endif
   84 
   85 /*
   86  * Event queue; events detected in an interrupt context go here
   87  * awaiting attention from our event handling thread.
   88  */
   89 struct stp4020_event {
   90         SIMPLEQ_ENTRY(stp4020_event) se_q;
   91         int     se_type;
   92         int     se_sock;
   93 };
   94 /* Defined event types */
   95 #define STP4020_EVENT_INSERTION 0
   96 #define STP4020_EVENT_REMOVAL   1
   97 
   98 /*
   99  * Per socket data.
  100  */
  101 struct stp4020_socket {
  102         struct stp4020_softc    *sc;    /* Back link */
  103         int             flags;
  104 #define STP4020_SOCKET_BUSY     0x0001
  105         int             sock;           /* Socket number (0 or 1) */
  106         int             sbus_intno;     /* Do we use first (0) or second (1)
  107                                            interrupt? */
  108         int             int_enable;     /* ICR0 value for interrupt enabled */
  109         int             int_disable;    /* ICR0 value for interrupt disabled */
  110         bus_space_tag_t tag;            /* socket control io    */
  111         bus_space_handle_t      regs;   /*  space               */
  112         bus_space_tag_t pcmciat;        /* io space for pcmcia  */
  113         struct device   *pcmcia;        /* Associated PCMCIA device */
  114         int             (*intrhandler)  /* Card driver interrupt handler */
  115                             __P((void *));
  116         void            *intrarg;       /* Card interrupt handler argument */
  117         void            *softint;       /* cookie for the softintr */
  118 
  119         struct {
  120                 bus_space_handle_t      winaddr;/* this window's address */
  121         } windows[STP4020_NWIN];
  122 
  123 };
  124 
  125 struct stp4020_softc {
  126         struct device   sc_dev;         /* Base device */
  127         struct sbusdev  sc_sd;          /* SBus device */
  128         bus_space_tag_t sc_bustag;
  129         pcmcia_chipset_tag_t    sc_pct; /* Chipset methods */
  130 
  131         struct proc     *event_thread;          /* event handling thread */
  132         SIMPLEQ_HEAD(, stp4020_event)   events; /* Pending events for thread */
  133 
  134         struct stp4020_socket sc_socks[STP4020_NSOCK];
  135 };
  136 
  137 
  138 static int      stp4020print    __P((void *, const char *));
  139 static int      stp4020match    __P((struct device *, struct cfdata *, void *));
  140 static void     stp4020attach   __P((struct device *, struct device *, void *));
  141 static int      stp4020_intr    __P((void *));
  142 static void     stp4020_map_window(struct stp4020_socket *h, int win, int speed);
  143 static void     stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay);
  144 static void     stp4020_intr_dispatch(void *arg);
  145 
  146 CFATTACH_DECL(nell, sizeof(struct stp4020_softc),
  147     stp4020match, stp4020attach, NULL, NULL);
  148 
  149 #ifdef STP4020_DEBUG
  150 static void     stp4020_dump_regs __P((struct stp4020_socket *));
  151 #endif
  152 
  153 static int      stp4020_rd_sockctl __P((struct stp4020_socket *, int));
  154 static void     stp4020_wr_sockctl __P((struct stp4020_socket *, int, int));
  155 static int      stp4020_rd_winctl __P((struct stp4020_socket *, int, int));
  156 static void     stp4020_wr_winctl __P((struct stp4020_socket *, int, int, int));
  157 
  158 void    stp4020_delay __P((unsigned int));
  159 void    stp4020_attach_socket __P((struct stp4020_socket *, int));
  160 void    stp4020_create_event_thread __P((void *));
  161 void    stp4020_event_thread __P((void *));
  162 void    stp4020_queue_event __P((struct stp4020_softc *, int, int));
  163 
  164 int     stp4020_chip_mem_alloc __P((pcmcia_chipset_handle_t, bus_size_t,
  165                                     struct pcmcia_mem_handle *));
  166 void    stp4020_chip_mem_free __P((pcmcia_chipset_handle_t,
  167                                    struct pcmcia_mem_handle *));
  168 int     stp4020_chip_mem_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
  169                                   bus_size_t, struct pcmcia_mem_handle *,
  170                                   bus_size_t *, int *));
  171 void    stp4020_chip_mem_unmap __P((pcmcia_chipset_handle_t, int));
  172 
  173 int     stp4020_chip_io_alloc __P((pcmcia_chipset_handle_t,
  174                                    bus_addr_t, bus_size_t, bus_size_t,
  175                                    struct pcmcia_io_handle *));
  176 void    stp4020_chip_io_free __P((pcmcia_chipset_handle_t,
  177                                   struct pcmcia_io_handle *));
  178 int     stp4020_chip_io_map __P((pcmcia_chipset_handle_t, int, bus_addr_t,
  179                                  bus_size_t, struct pcmcia_io_handle *, int *));
  180 void    stp4020_chip_io_unmap __P((pcmcia_chipset_handle_t, int));
  181 
  182 void    stp4020_chip_socket_enable __P((pcmcia_chipset_handle_t));
  183 void    stp4020_chip_socket_disable __P((pcmcia_chipset_handle_t));
  184 void    *stp4020_chip_intr_establish __P((pcmcia_chipset_handle_t,
  185                                           struct pcmcia_function *, int,
  186                                           int (*) __P((void *)), void *));
  187 void    stp4020_chip_intr_disestablish __P((pcmcia_chipset_handle_t, void *));
  188 
  189 /* Our PCMCIA chipset methods */
  190 static struct pcmcia_chip_functions stp4020_functions = {
  191         stp4020_chip_mem_alloc,
  192         stp4020_chip_mem_free,
  193         stp4020_chip_mem_map,
  194         stp4020_chip_mem_unmap,
  195 
  196         stp4020_chip_io_alloc,
  197         stp4020_chip_io_free,
  198         stp4020_chip_io_map,
  199         stp4020_chip_io_unmap,
  200 
  201         stp4020_chip_intr_establish,
  202         stp4020_chip_intr_disestablish,
  203 
  204         stp4020_chip_socket_enable,
  205         stp4020_chip_socket_disable
  206 };
  207 
  208 
  209 static __inline__ int
  210 stp4020_rd_sockctl(h, idx)
  211         struct stp4020_socket *h;
  212         int idx;
  213 {
  214         int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
  215         return (bus_space_read_2(h->tag, h->regs, o));
  216 }
  217 
  218 static __inline__ void
  219 stp4020_wr_sockctl(h, idx, v)
  220         struct stp4020_socket *h;
  221         int idx;
  222         int v;
  223 {
  224         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
  225         bus_space_write_2(h->tag, h->regs, o, v);
  226 }
  227 
  228 static __inline__ int
  229 stp4020_rd_winctl(h, win, idx)
  230         struct stp4020_socket *h;
  231         int win;
  232         int idx;
  233 {
  234         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
  235                 (STP4020_WINREGS_SIZE * win) + idx;
  236         return (bus_space_read_2(h->tag, h->regs, o));
  237 }
  238 
  239 static __inline__ void
  240 stp4020_wr_winctl(h, win, idx, v)
  241         struct stp4020_socket *h;
  242         int win;
  243         int idx;
  244         int v;
  245 {
  246         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
  247                 (STP4020_WINREGS_SIZE * win) + idx;
  248 
  249         bus_space_write_2(h->tag, h->regs, o, v);
  250 }
  251 
  252 #ifndef SUN4U   /* XXX - move to SBUS machdep function? */
  253 
  254 #if !__FULL_SPARC_BUS_SPACE
  255 #error "stp4020 (nell) needs __FULL_SPARC_BUS_SPACE defined as well"
  256 #else
  257 static  u_int16_t stp4020_read_2(bus_space_tag_t,
  258                                  bus_space_handle_t,
  259                                  bus_size_t);
  260 static  u_int32_t stp4020_read_4(bus_space_tag_t,
  261                                  bus_space_handle_t,
  262                                  bus_size_t);
  263 static  u_int64_t stp4020_read_8(bus_space_tag_t,
  264                                  bus_space_handle_t,
  265                                  bus_size_t);
  266 static  void    stp4020_write_2(bus_space_tag_t,
  267                                 bus_space_handle_t,
  268                                 bus_size_t,
  269                                 u_int16_t);
  270 static  void    stp4020_write_4(bus_space_tag_t,
  271                                 bus_space_handle_t,
  272                                 bus_size_t,
  273                                 u_int32_t);
  274 static  void    stp4020_write_8(bus_space_tag_t,
  275                                 bus_space_handle_t,
  276                                 bus_size_t,
  277                                 u_int64_t);
  278 
  279 static u_int16_t
  280 stp4020_read_2(space, handle, offset)
  281         bus_space_tag_t space;
  282         bus_space_handle_t handle;
  283         bus_size_t offset;
  284 {
  285         return (le16toh(*(volatile u_int16_t *)(handle + offset)));
  286 }
  287 
  288 static u_int32_t
  289 stp4020_read_4(space, handle, offset)
  290         bus_space_tag_t space;
  291         bus_space_handle_t handle;
  292         bus_size_t offset;
  293 {
  294         return (le32toh(*(volatile u_int32_t *)(handle + offset)));
  295 }
  296 
  297 static u_int64_t
  298 stp4020_read_8(space, handle, offset)
  299         bus_space_tag_t space;
  300         bus_space_handle_t handle;
  301         bus_size_t offset;
  302 {
  303         return (le64toh(*(volatile u_int64_t *)(handle + offset)));
  304 }
  305 
  306 static void
  307 stp4020_write_2(space, handle, offset, value)
  308         bus_space_tag_t space;
  309         bus_space_handle_t handle;
  310         bus_size_t offset;
  311         u_int16_t value;
  312 {
  313         (*(volatile u_int16_t *)(handle + offset)) = htole16(value);
  314 }
  315 
  316 static void
  317 stp4020_write_4(space, handle, offset, value)
  318         bus_space_tag_t space;
  319         bus_space_handle_t handle;
  320         bus_size_t offset;
  321         u_int32_t value;
  322 {
  323         (*(volatile u_int32_t *)(handle + offset)) = htole32(value);
  324 }
  325 
  326 static void
  327 stp4020_write_8(space, handle, offset, value)
  328         bus_space_tag_t space;
  329         bus_space_handle_t handle;
  330         bus_size_t offset;
  331         u_int64_t value;
  332 {
  333         (*(volatile u_int64_t *)(handle + offset)) = htole64(value);
  334 }
  335 #endif  /* __FULL_SPARC_BUS_SPACE */
  336 #endif  /* SUN4U */
  337 
  338 int
  339 stp4020print(aux, busname)
  340         void *aux;
  341         const char *busname;
  342 {
  343         struct pcmciabus_attach_args *paa = aux;
  344         struct stp4020_socket *h = paa->pch;
  345 
  346         aprint_normal(" socket %d", h->sock);
  347         return (UNCONF);
  348 }
  349 
  350 int
  351 stp4020match(parent, cf, aux)
  352         struct device *parent;
  353         struct cfdata *cf;
  354         void *aux;
  355 {
  356         struct sbus_attach_args *sa = aux;
  357 
  358         return (strcmp("SUNW,pcmcia", sa->sa_name) == 0);
  359 }
  360 
  361 /*
  362  * Attach all the sub-devices we can find
  363  */
  364 void
  365 stp4020attach(parent, self, aux)
  366         struct device *parent, *self;
  367         void *aux;
  368 {
  369         struct sbus_attach_args *sa = aux;
  370         struct stp4020_softc *sc = (void *)self;
  371         bus_space_tag_t tag;
  372         int rev;
  373         int i, sbus_intno;
  374         bus_space_handle_t bh;
  375 
  376         /* lsb of our config flags decides which interrupt we use */
  377         sbus_intno = sc->sc_dev.dv_cfdata->cf_flags & 1;
  378 
  379         /* Transfer bus tags */
  380 #if __FULL_SPARC_BUS_SPACE
  381         tag = (bus_space_tag_t)
  382             malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
  383         *tag = *sa->sa_bustag;
  384         tag->sparc_read_2 = stp4020_read_2;
  385         tag->sparc_read_4 = stp4020_read_4;
  386         tag->sparc_read_8 = stp4020_read_8;
  387         tag->sparc_write_2 = stp4020_write_2;
  388         tag->sparc_write_4 = stp4020_write_4;
  389         tag->sparc_write_8 = stp4020_write_8;
  390 #else
  391         tag = sa->sa_bustag;
  392 #endif  /* __FULL_SPARC_BUS_SPACE */
  393         sc->sc_bustag = tag;
  394 
  395         /* Set up per-socket static initialization */
  396         sc->sc_socks[0].sc = sc->sc_socks[1].sc = sc;
  397         sc->sc_socks[0].tag = sc->sc_socks[1].tag = sa->sa_bustag;
  398         /*
  399          * XXX we rely on "tag" accepting the same handle-domain
  400          * as sa->sa_bustag.
  401          */
  402         sc->sc_socks[0].pcmciat = sc->sc_socks[1].pcmciat = tag;
  403         sc->sc_socks[0].sbus_intno =
  404                 sc->sc_socks[1].sbus_intno = sbus_intno;
  405 
  406         if (sa->sa_nreg < 8) {
  407                 printf("%s: only %d register sets\n",
  408                         self->dv_xname, sa->sa_nreg);
  409                 return;
  410         }
  411 
  412         if (sa->sa_nintr != 2) {
  413                 printf("%s: expect 2 interrupt Sbus levels; got %d\n",
  414                         self->dv_xname, sa->sa_nintr);
  415                 return;
  416         }
  417 
  418 #define STP4020_BANK_PROM       0
  419 #define STP4020_BANK_CTRL       4
  420         for (i = 0; i < 8; i++) {
  421 
  422                 /*
  423                  * STP4020 Register address map:
  424                  *      bank  0:   Forth PROM
  425                  *      banks 1-3: socket 0, windows 0-2
  426                  *      bank  4:   control registers
  427                  *      banks 5-7: socket 1, windows 0-2
  428                  */
  429 
  430                 if (i == STP4020_BANK_PROM)
  431                         /* Skip the PROM */
  432                         continue;
  433 
  434                 if (sbus_bus_map(sa->sa_bustag,
  435                                  sa->sa_reg[i].oa_space,
  436                                  sa->sa_reg[i].oa_base,
  437                                  sa->sa_reg[i].oa_size,
  438                                  0, &bh) != 0) {
  439                         printf("%s: attach: cannot map registers\n",
  440                                 self->dv_xname);
  441                         return;
  442                 }               
  443 
  444                 if (i == STP4020_BANK_CTRL) {
  445                         /*
  446                          * Copy tag and handle to both socket structures
  447                          * for easy access in control/status IO functions.
  448                          */
  449                         sc->sc_socks[0].regs = sc->sc_socks[1].regs = bh;
  450                 } else if (i < STP4020_BANK_CTRL) {
  451                         /* banks 1-3 */
  452                         sc->sc_socks[0].windows[i-1].winaddr = bh;
  453                 } else {
  454                         /* banks 5-7 */
  455                         sc->sc_socks[1].windows[i-5].winaddr = bh;
  456                 }
  457         }
  458 
  459         sbus_establish(&sc->sc_sd, &sc->sc_dev);
  460 
  461         /* We only use one interrupt level. */
  462         if (sa->sa_nintr > sbus_intno) {
  463                 bus_intr_establish(sa->sa_bustag,
  464                     sa->sa_intr[sbus_intno].oi_pri,
  465                     IPL_NONE, stp4020_intr, sc);
  466         }
  467 
  468         rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
  469                 STP4020_ISR1_REV_M;
  470         printf(": rev %x\n", rev);
  471 
  472         sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
  473 
  474         /*
  475          * Arrange that a kernel thread be created to handle
  476          * insert/removal events.
  477          */
  478         SIMPLEQ_INIT(&sc->events);
  479         kthread_create(stp4020_create_event_thread, sc);
  480 
  481         for (i = 0; i < STP4020_NSOCK; i++) {
  482                 struct stp4020_socket *h = &sc->sc_socks[i];
  483                 h->sock = i;
  484                 h->sc = sc;
  485 #ifdef STP4020_DEBUG
  486                 if (stp4020_debug)
  487                         stp4020_dump_regs(h);
  488 #endif
  489                 stp4020_attach_socket(h, sa->sa_frequency);
  490         }
  491 }
  492 
  493 void
  494 stp4020_attach_socket(h, speed)
  495         struct stp4020_socket *h;
  496         int speed;
  497 {
  498         struct pcmciabus_attach_args paa;
  499         int v;
  500 
  501         /* no interrupt handlers yet */
  502         h->intrhandler = NULL;
  503         h->intrarg = NULL;
  504         h->softint = NULL;
  505         h->int_enable = 0;
  506         h->int_disable = 0;
  507 
  508         /* Map all three windows */
  509         stp4020_map_window(h, STP_WIN_ATTR, speed);
  510         stp4020_map_window(h, STP_WIN_MEM, speed);
  511         stp4020_map_window(h, STP_WIN_IO, speed);
  512 
  513         /* Configure one pcmcia device per socket */
  514         paa.paa_busname = "pcmcia";
  515         paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
  516         paa.pch = (pcmcia_chipset_handle_t)h;
  517         paa.iobase = 0;
  518         paa.iosize = STP4020_WINDOW_SIZE;
  519 
  520         h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
  521 
  522         if (h->pcmcia == NULL)
  523                 return;
  524 
  525         /*
  526          * There's actually a pcmcia bus attached; initialize the slot.
  527          */
  528 
  529         /*
  530          * Clear things up before we enable status change interrupts.
  531          * This seems to not be fully initialized by the PROM.
  532          */
  533         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
  534         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
  535         stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
  536         stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
  537 
  538         /*
  539          * Enable socket status change interrupts.
  540          * We only use one common interrupt for status change
  541          * and IO, to avoid locking issues.
  542          */
  543         v = STP4020_ICR0_ALL_STATUS_IE
  544             | (h->sbus_intno ? STP4020_ICR0_SCILVL_SB1
  545                              : STP4020_ICR0_SCILVL_SB0);
  546         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
  547 
  548         /* Get live status bits from ISR0 and clear pending interrupts */
  549         v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  550         stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
  551 
  552         if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0)
  553                 return;
  554 
  555         pcmcia_card_attach(h->pcmcia);
  556         h->flags |= STP4020_SOCKET_BUSY;
  557 }
  558 
  559 
  560 /*
  561  * Deferred thread creation callback.
  562  */
  563 void
  564 stp4020_create_event_thread(arg)
  565         void *arg;
  566 {
  567         struct stp4020_softc *sc = arg;
  568         const char *name = sc->sc_dev.dv_xname;
  569 
  570         if (kthread_create1(stp4020_event_thread, sc, &sc->event_thread,
  571                            "%s", name)) {
  572                 panic("%s: unable to create event thread", name);
  573         }
  574 }
  575 
  576 /*
  577  * The actual event handling thread.
  578  */
  579 void
  580 stp4020_event_thread(arg)
  581         void *arg;
  582 {
  583         struct stp4020_softc *sc = arg;
  584         struct stp4020_event *e;
  585         int s;
  586 
  587         while (1) {
  588                 struct stp4020_socket *h;
  589                 int n;
  590 
  591                 s = splhigh();
  592                 if ((e = SIMPLEQ_FIRST(&sc->events)) == NULL) {
  593                         splx(s);
  594                         (void)tsleep(&sc->events, PWAIT, "pcicev", 0);
  595                         continue;
  596                 }
  597                 SIMPLEQ_REMOVE_HEAD(&sc->events, se_q);
  598                 splx(s);
  599 
  600                 n = e->se_sock;
  601                 if (n < 0 || n >= STP4020_NSOCK)
  602                         panic("stp4020_event_thread: wayward socket number %d",
  603                               n);
  604 
  605                 h = &sc->sc_socks[n];
  606                 switch (e->se_type) {
  607                 case STP4020_EVENT_INSERTION:
  608                         pcmcia_card_attach(h->pcmcia);
  609                         break;
  610                 case STP4020_EVENT_REMOVAL:
  611                         pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
  612                         break;
  613                 default:
  614                         panic("stp4020_event_thread: unknown event type %d",
  615                               e->se_type);
  616                 }
  617                 free(e, M_TEMP);
  618         }
  619 }
  620 
  621 void
  622 stp4020_queue_event(sc, sock, event)
  623         struct stp4020_softc *sc;
  624         int sock, event;
  625 {
  626         struct stp4020_event *e;
  627         int s;
  628 
  629         e = malloc(sizeof(*e), M_TEMP, M_NOWAIT);
  630         if (e == NULL)
  631                 panic("stp4020_queue_event: can't allocate event");
  632 
  633         e->se_type = event;
  634         e->se_sock = sock;
  635         s = splhigh();
  636         SIMPLEQ_INSERT_TAIL(&sc->events, e, se_q);
  637         splx(s);
  638         wakeup(&sc->events);
  639 }
  640 
  641 /*
  642  * Softinterrupt called to invoke the real driver interrupt handler.
  643  */
  644 static void
  645 stp4020_intr_dispatch(arg)
  646         void *arg;
  647 {
  648         struct stp4020_socket *h = arg;
  649         int s;
  650 
  651         /* invoke driver handler */
  652         h->intrhandler(h->intrarg);
  653 
  654         /* enable SBUS interrupts for pcmcia interrupts again */
  655         s = splhigh();
  656         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_enable);
  657         splx(s);
  658 }
  659 
  660 int
  661 stp4020_intr(arg)
  662         void *arg;
  663 {
  664         struct stp4020_softc *sc = arg;
  665         int i, s, r = 0, cd_change = 0;
  666 
  667 
  668         /* protect hardware access by splhigh against softint */
  669         s = splhigh();
  670 
  671         /*
  672          * Check each socket for pending requests.
  673          */
  674         for (i = 0 ; i < STP4020_NSOCK; i++) {
  675                 struct stp4020_socket *h;
  676                 int v;
  677 
  678                 h = &sc->sc_socks[i];
  679 
  680                 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  681 
  682                 /* Ack all interrupts at once. */
  683                 stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
  684 
  685 #ifdef STP4020_DEBUG
  686                 if (stp4020_debug != 0) {
  687                         char bits[64];
  688                         bitmask_snprintf(v, STP4020_ISR0_IOBITS,
  689                                          bits, sizeof(bits));
  690                         printf("stp4020_statintr: ISR0=%s\n", bits);
  691                 }
  692 #endif
  693 
  694                 if ((v & STP4020_ISR0_CDCHG) != 0) {
  695                         /*
  696                          * Card status change detect
  697                          */
  698                         cd_change = 1;
  699                         r = 1;
  700                         if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)){
  701                                 if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
  702                                         stp4020_queue_event(sc, i,
  703                                                 STP4020_EVENT_INSERTION);
  704                                         h->flags |= STP4020_SOCKET_BUSY;
  705                                 }
  706                         }
  707                         if ((v & (STP4020_ISR0_CD1ST|STP4020_ISR0_CD2ST)) == 0){
  708                                 if ((h->flags & STP4020_SOCKET_BUSY) != 0) {
  709                                         stp4020_queue_event(sc, i,
  710                                                 STP4020_EVENT_REMOVAL);
  711                                         h->flags &= ~STP4020_SOCKET_BUSY;
  712                                 }
  713                         }
  714                 }
  715                 
  716                 if ((v & STP4020_ISR0_IOINT) != 0) {
  717                         /* we can not deny this is ours, no matter what the
  718                            card driver says. */
  719                         r = 1;
  720 
  721                         /* It's a card interrupt */
  722                         if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
  723                                 printf("stp4020[%d]: spurious interrupt?\n",
  724                                         h->sock);
  725                                 continue;
  726                         }
  727 
  728                         /*
  729                          * Schedule softint to invoke driver interrupt 
  730                          * handler
  731                          */
  732                         if (h->softint != NULL)
  733                                 softintr_schedule(h->softint);
  734                         /*
  735                          * Disable this sbus interrupt, until the soft-int
  736                          * handler had a chance to run
  737                          */
  738                         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, h->int_disable);
  739                 }
  740 
  741                 /* informational messages */
  742                 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
  743                         /* ignore if this is caused by insert or removal */
  744                         if (!cd_change)
  745                                 printf("stp4020[%d]: Battery change 1\n", h->sock);
  746                         r = 1;
  747                 }
  748 
  749                 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
  750                         /* ignore if this is caused by insert or removal */
  751                         if (!cd_change)
  752                                 printf("stp4020[%d]: Battery change 2\n", h->sock);
  753                         r = 1;
  754                 }
  755 
  756                 if ((v & STP4020_ISR0_SCINT) != 0) {
  757                         DPRINTF(("stp4020[%d]: status change\n", h->sock));
  758                         r = 1;
  759                 }
  760 
  761                 if ((v & STP4020_ISR0_RDYCHG) != 0) {
  762                         DPRINTF(("stp4020[%d]: Ready/Busy change\n", h->sock));
  763                         r = 1;
  764                 }
  765 
  766                 if ((v & STP4020_ISR0_WPCHG) != 0) {
  767                         DPRINTF(("stp4020[%d]: Write protect change\n", h->sock));
  768                         r = 1;
  769                 }
  770 
  771                 if ((v & STP4020_ISR0_PCTO) != 0) {
  772                         DPRINTF(("stp4020[%d]: Card access timeout\n", h->sock));
  773                         r = 1;
  774                 }
  775 
  776                 if ((v & ~STP4020_ISR0_LIVE) && r == 0)
  777                         printf("stp4020[%d]: unhandled interrupt: 0x%x\n", h->sock, v);
  778 
  779         }
  780         splx(s);
  781 
  782         return (r);
  783 }
  784 
  785 /*
  786  * The function gets the sbus speed and a access time and calculates
  787  * values for the CMDLNG and CMDDLAY registers.
  788  */
  789 static void
  790 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
  791 {
  792         int result;
  793 
  794         if (ns < STP4020_MEM_SPEED_MIN)
  795                 ns = STP4020_MEM_SPEED_MIN;
  796         else if (ns > STP4020_MEM_SPEED_MAX)
  797                 ns = STP4020_MEM_SPEED_MAX;
  798         result = ns*(bus_speed/1000);
  799         if (result % 1000000)
  800                 result = result/1000000 + 1;
  801         else
  802                 result /= 1000000;
  803         *length = result;
  804 
  805         /* the sbus frequency range is limited, so we can keep this simple */
  806         *delay = ns <= STP4020_MEM_SPEED_MIN? 1 : 2;
  807 }
  808 
  809 static void
  810 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
  811 {
  812         int v, length, delay;
  813 
  814         /*
  815          * According to the PC Card standard 300ns access timing should be
  816          * used for attribute memory access. Our pcmcia framework does not
  817          * seem to propagate timing information, so we use that
  818          * everywhere.
  819          */
  820         stp4020_calc_speed(speed, (win==STP_WIN_ATTR)? 300 : 100, &length, &delay);
  821 
  822         /*
  823          * Fill in the Address Space Select and Base Address
  824          * fields of this windows control register 0.
  825          */
  826         v = ((delay << STP4020_WCR0_CMDDLY_S)&STP4020_WCR0_CMDDLY_M)
  827             | ((length << STP4020_WCR0_CMDLNG_S)&STP4020_WCR0_CMDLNG_M);
  828         switch (win) {
  829         case STP_WIN_ATTR:
  830                 v |= STP4020_WCR0_ASPSEL_AM;
  831                 break;
  832         case STP_WIN_MEM:
  833                 v |= STP4020_WCR0_ASPSEL_CM;
  834                 break;
  835         case STP_WIN_IO:
  836                 v |= STP4020_WCR0_ASPSEL_IO;
  837                 break;
  838         }
  839         v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
  840         stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
  841         stp4020_wr_winctl(h, win, STP4020_WCR1_IDX, 1<<STP4020_WCR1_WAITREQ_S);
  842 }
  843 
  844 int
  845 stp4020_chip_mem_alloc(pch, size, pcmhp)
  846         pcmcia_chipset_handle_t pch;
  847         bus_size_t size;
  848         struct pcmcia_mem_handle *pcmhp;
  849 {
  850         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  851 
  852         /* we can not do much here, defere work to _mem_map */
  853         pcmhp->memt = h->pcmciat;
  854         pcmhp->size = size;
  855         pcmhp->addr = 0;
  856         pcmhp->mhandle = 0;
  857         pcmhp->realsize = size;
  858 
  859         return (0);
  860 }
  861 
  862 void
  863 stp4020_chip_mem_free(pch, pcmhp)
  864         pcmcia_chipset_handle_t pch;
  865         struct pcmcia_mem_handle *pcmhp;
  866 {
  867 }
  868 
  869 int
  870 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
  871         pcmcia_chipset_handle_t pch;
  872         int kind;
  873         bus_addr_t card_addr;
  874         bus_size_t size;
  875         struct pcmcia_mem_handle *pcmhp;
  876         bus_size_t *offsetp;
  877         int *windowp;
  878 {
  879         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  880         int win = (kind&PCMCIA_MEM_ATTR)? STP_WIN_ATTR : STP_WIN_MEM;
  881 
  882         pcmhp->memt = h->pcmciat;
  883         bus_space_subregion(h->pcmciat, h->windows[win].winaddr, card_addr, size, &pcmhp->memh);
  884 #ifdef SUN4U
  885         if ((u_int8_t)pcmhp->memh._asi == ASI_PHYS_NON_CACHED)
  886                 pcmhp->memh._asi = ASI_PHYS_NON_CACHED_LITTLE;
  887         else if ((u_int8_t)pcmhp->memh._asi == ASI_PRIMARY)
  888                 pcmhp->memh._asi = ASI_PRIMARY_LITTLE;
  889 #endif
  890         pcmhp->size = size;
  891         pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
  892         *offsetp = 0;
  893         *windowp = 0;
  894 
  895         return (0);
  896 }
  897 
  898 void
  899 stp4020_chip_mem_unmap(pch, win)
  900         pcmcia_chipset_handle_t pch;
  901         int win;
  902 {
  903 }
  904 
  905 int
  906 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
  907         pcmcia_chipset_handle_t pch;
  908         bus_addr_t start;
  909         bus_size_t size;
  910         bus_size_t align;
  911         struct pcmcia_io_handle *pcihp;
  912 {
  913         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  914 
  915         pcihp->iot = h->pcmciat;
  916         pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
  917         return 0;
  918 }
  919 
  920 void
  921 stp4020_chip_io_free(pch, pcihp)
  922         pcmcia_chipset_handle_t pch;
  923         struct pcmcia_io_handle *pcihp;
  924 {
  925 }
  926 
  927 int
  928 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
  929         pcmcia_chipset_handle_t pch;
  930         int width;
  931         bus_addr_t offset;
  932         bus_size_t size;
  933         struct pcmcia_io_handle *pcihp;
  934         int *windowp;
  935 {
  936         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  937 
  938         pcihp->iot = h->pcmciat;
  939         bus_space_subregion(h->pcmciat, h->windows[STP_WIN_IO].winaddr, offset, size, &pcihp->ioh);
  940 #ifdef SUN4U
  941         if ((u_int8_t)pcihp->ioh._asi == ASI_PHYS_NON_CACHED)
  942                 pcihp->ioh._asi = ASI_PHYS_NON_CACHED_LITTLE;
  943         else if ((u_int8_t)pcihp->ioh._asi == ASI_PRIMARY)
  944                 pcihp->ioh._asi = ASI_PRIMARY_LITTLE;
  945 #endif
  946         *windowp = 0;
  947         return 0;
  948 }
  949 
  950 void
  951 stp4020_chip_io_unmap(pch, win)
  952         pcmcia_chipset_handle_t pch;
  953         int win;
  954 {
  955 }
  956 
  957 void
  958 stp4020_chip_socket_enable(pch)
  959         pcmcia_chipset_handle_t pch;
  960 {
  961         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  962         int i, v;
  963 
  964         /* this bit is mostly stolen from pcic_attach_card */
  965 
  966         /* Power down the socket to reset it, clear the card reset pin */
  967         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
  968 
  969         /*
  970          * wait 300ms until power fails (Tpf).  Then, wait 100ms since
  971          * we are changing Vcc (Toff).
  972          */
  973         stp4020_delay((300 + 100) * 1000);
  974 
  975         /* Power up the socket */
  976         v = STP4020_ICR1_MSTPWR;
  977         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
  978 
  979         /*
  980          * wait 100ms until power raise (Tpr) and 20ms to become
  981          * stable (Tsu(Vcc)).
  982          */
  983         stp4020_delay((100 + 20) * 1000);
  984 
  985         v |= STP4020_ICR1_PCIFOE|STP4020_ICR1_VPP1_VCC;
  986         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
  987 
  988         /*
  989          * hold RESET at least 10us.
  990          */
  991         delay(10);
  992 
  993         /* Clear reset flag */
  994         v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
  995         v &= ~STP4020_ICR0_RESET;
  996         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
  997 
  998         /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
  999         stp4020_delay(20000);
 1000 
 1001         /* Wait for the chip to finish initializing (5 seconds max) */
 1002         for (i = 10000; i > 0; i--) {
 1003                 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
 1004                 if ((v & STP4020_ISR0_RDYST) != 0)
 1005                         break;
 1006                 delay(500);
 1007         }
 1008         if (i <= 0) {
 1009                 char bits[64];
 1010                 bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
 1011                                  STP4020_ISR0_IOBITS, bits, sizeof(bits));
 1012                 printf("stp4020_chip_socket_enable: not ready: status %s\n",
 1013                         bits);
 1014                 return;
 1015         }
 1016 
 1017         v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
 1018 
 1019         /*
 1020          * Check the card type.
 1021          * Enable socket I/O interrupts for IO cards.
 1022          */
 1023         if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
 1024                 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE);
 1025                 v |= STP4020_ICR0_IFTYPE_IO|STP4020_ICR0_IOIE
 1026                     |STP4020_ICR0_SPKREN;
 1027                 v |= h->sbus_intno ? STP4020_ICR0_IOILVL_SB1
 1028                                    : STP4020_ICR0_IOILVL_SB0;
 1029                 h->int_enable = v;
 1030                 h->int_disable = v & ~STP4020_ICR0_IOIE;
 1031                 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
 1032         } else {
 1033                 v &= ~(STP4020_ICR0_IOILVL|STP4020_ICR0_IFTYPE
 1034                     |STP4020_ICR0_SPKREN);
 1035                 v |= STP4020_ICR0_IFTYPE_MEM;
 1036                 h->int_enable = h->int_disable = v;
 1037                 DPRINTF(("%s: configuring card for IO useage\n", h->sc->sc_dev.dv_xname));
 1038                 DPRINTF(("%s: configuring card for MEM ONLY useage\n", h->sc->sc_dev.dv_xname));
 1039         }
 1040         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
 1041 }
 1042 
 1043 void
 1044 stp4020_chip_socket_disable(pch)
 1045         pcmcia_chipset_handle_t pch;
 1046 {
 1047         struct stp4020_socket *h = (struct stp4020_socket *)pch;
 1048         int v;
 1049 
 1050         /*
 1051          * Disable socket I/O interrupts.
 1052          */
 1053         v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
 1054         v &= ~(STP4020_ICR0_IOIE | STP4020_ICR0_IOILVL);
 1055         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
 1056 
 1057         /* Power down the socket */
 1058         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
 1059 
 1060         /*
 1061          * wait 300ms until power fails (Tpf).
 1062          */
 1063         stp4020_delay(300 * 1000);
 1064 }
 1065 
 1066 void *
 1067 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg)
 1068         pcmcia_chipset_handle_t pch;
 1069         struct pcmcia_function *pf;
 1070         int ipl;
 1071         int (*handler) __P((void *));
 1072         void *arg;
 1073 {
 1074         struct stp4020_socket *h = (struct stp4020_socket *)pch;
 1075 
 1076         /* only one interrupt handler per slot */
 1077         if (h->intrhandler != NULL) return NULL;
 1078 
 1079         h->intrhandler = handler;
 1080         h->intrarg = arg;
 1081         h->softint = softintr_establish(ipl, stp4020_intr_dispatch, h);
 1082         return h->softint;
 1083 }
 1084 
 1085 void
 1086 stp4020_chip_intr_disestablish(pch, ih)
 1087         pcmcia_chipset_handle_t pch;
 1088         void *ih;
 1089 {
 1090         struct stp4020_socket *h = (struct stp4020_socket *)pch;
 1091 
 1092         h->intrhandler = NULL;
 1093         h->intrarg = NULL;
 1094         if (h->softint) {
 1095                 softintr_disestablish(h->softint);
 1096                 h->softint = NULL;
 1097         }
 1098 }
 1099 
 1100 /*
 1101  * Delay and possibly yield CPU.
 1102  * XXX - assumes a context
 1103  */
 1104 void
 1105 stp4020_delay(ms)
 1106         unsigned int ms;
 1107 {
 1108         unsigned int ticks;
 1109 
 1110         /* Convert to ticks */
 1111         ticks = (ms * hz ) / 1000000;
 1112 
 1113         if (cold || ticks == 0) {
 1114                 delay(ms);
 1115                 return;
 1116         }
 1117 
 1118 #ifdef DIAGNOSTIC
 1119         if (ticks > 60*hz)
 1120                 panic("stp4020: preposterous delay: %u", ticks);
 1121 #endif
 1122         tsleep(&ticks, 0, "stp4020_delay", ticks);
 1123 }
 1124 
 1125 #ifdef STP4020_DEBUG
 1126 void
 1127 stp4020_dump_regs(h)
 1128         struct stp4020_socket *h;
 1129 {
 1130         char bits[64];
 1131         /*
 1132          * Dump control and status registers.
 1133          */
 1134         printf("socket[%d] registers:\n", h->sock);
 1135         bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR0_IDX),
 1136                          STP4020_ICR0_BITS, bits, sizeof(bits));
 1137         printf("\tICR0=%s\n", bits);
 1138 
 1139         bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ICR1_IDX),
 1140                          STP4020_ICR1_BITS, bits, sizeof(bits));
 1141         printf("\tICR1=%s\n", bits);
 1142 
 1143         bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR0_IDX),
 1144                          STP4020_ISR0_IOBITS, bits, sizeof(bits));
 1145         printf("\tISR0=%s\n", bits);
 1146 
 1147         bitmask_snprintf(stp4020_rd_sockctl(h, STP4020_ISR1_IDX),
 1148                          STP4020_ISR1_BITS, bits, sizeof(bits));
 1149         printf("\tISR1=%s\n", bits);
 1150 }
 1151 #endif /* STP4020_DEBUG */

Cache object: dc058e92cd51554184a7979e622fc75e


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