root/dev/sbus/stp4020.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. stp4020_rd_sockctl
  2. stp4020_wr_sockctl
  3. stp4020_rd_winctl
  4. stp4020_wr_winctl
  5. stp4020print
  6. stpattach_common
  7. stp4020_attach_socket
  8. stp4020_create_event_thread
  9. stp4020_event_thread
  10. stp4020_queue_event
  11. stp4020_statintr
  12. stp4020_iointr
  13. stp4020_calc_speed
  14. stp4020_map_window
  15. stp4020_chip_mem_alloc
  16. stp4020_chip_mem_free
  17. stp4020_chip_mem_map
  18. stp4020_chip_mem_unmap
  19. stp4020_chip_io_alloc
  20. stp4020_chip_io_free
  21. stp4020_chip_io_map
  22. stp4020_chip_io_unmap
  23. stp4020_chip_socket_enable
  24. stp4020_chip_socket_disable
  25. stp4020_chip_intr_establish
  26. stp4020_chip_intr_disestablish
  27. stp4020_chip_intr_string
  28. stp4020_delay
  29. stp4020_dump_regs

    1 /*      $OpenBSD: stp4020.c,v 1.14 2005/11/23 11:39:37 mickey Exp $     */
    2 /*      $NetBSD: stp4020.c,v 1.23 2002/06/01 23:51:03 lukem Exp $       */
    3 
    4 /*-
    5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Paul Kranenburg.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * STP4020: SBus/PCMCIA bridge supporting one Type-3 PCMCIA card, or up to
   42  * two Type-1 and Type-2 PCMCIA cards..
   43  */
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/errno.h>
   48 #include <sys/extent.h>
   49 #include <sys/proc.h>
   50 #include <sys/kernel.h>
   51 #include <sys/kthread.h>
   52 #include <sys/device.h>
   53 
   54 #include <dev/pcmcia/pcmciareg.h>
   55 #include <dev/pcmcia/pcmciavar.h>
   56 #include <dev/pcmcia/pcmciachip.h>
   57 
   58 #include <machine/bus.h>
   59 
   60 #include <dev/sbus/stp4020reg.h>
   61 #include <dev/sbus/stp4020var.h>
   62 
   63 /*
   64  * We use the three available windows per socket in a simple, fixed
   65  * arrangement. Each window maps (at full 1 MB size) one of the pcmcia
   66  * spaces into sbus space.
   67  */
   68 #define STP_WIN_ATTR    0       /* index of the attribute memory space window */
   69 #define STP_WIN_MEM     1       /* index of the common memory space window */
   70 #define STP_WIN_IO      2       /* index of the io space window */
   71 
   72 #ifdef STP4020_DEBUG
   73 int stp4020_debug = 0;
   74 #define DPRINTF(x)      do { if (stp4020_debug) printf x; } while(0)
   75 #else
   76 #define DPRINTF(x)
   77 #endif
   78 
   79 int     stp4020print(void *, const char *);
   80 void    stp4020_map_window(struct stp4020_socket *, int, int);
   81 void    stp4020_calc_speed(int, int, int *, int *);
   82 
   83 struct  cfdriver stp_cd = {
   84         NULL, "stp", DV_DULL
   85 };
   86 
   87 #ifdef STP4020_DEBUG
   88 static void     stp4020_dump_regs(struct stp4020_socket *);
   89 #endif
   90 
   91 static u_int16_t stp4020_rd_sockctl(struct stp4020_socket *, int);
   92 static void     stp4020_wr_sockctl(struct stp4020_socket *, int, u_int16_t);
   93 static u_int16_t stp4020_rd_winctl(struct stp4020_socket *, int, int);
   94 static void     stp4020_wr_winctl(struct stp4020_socket *, int, int, u_int16_t);
   95 
   96 void    stp4020_delay(unsigned int);
   97 void    stp4020_attach_socket(struct stp4020_socket *, int);
   98 void    stp4020_create_event_thread(void *);
   99 void    stp4020_event_thread(void *);
  100 void    stp4020_queue_event(struct stp4020_softc *, int);
  101 
  102 int     stp4020_chip_mem_alloc(pcmcia_chipset_handle_t, bus_size_t,
  103             struct pcmcia_mem_handle *);
  104 void    stp4020_chip_mem_free(pcmcia_chipset_handle_t,
  105             struct pcmcia_mem_handle *);
  106 int     stp4020_chip_mem_map(pcmcia_chipset_handle_t, int, bus_addr_t,
  107             bus_size_t, struct pcmcia_mem_handle *, bus_size_t *, int *);
  108 void    stp4020_chip_mem_unmap(pcmcia_chipset_handle_t, int);
  109 
  110 int     stp4020_chip_io_alloc(pcmcia_chipset_handle_t,
  111             bus_addr_t, bus_size_t, bus_size_t, struct pcmcia_io_handle *);
  112 void    stp4020_chip_io_free(pcmcia_chipset_handle_t,
  113             struct pcmcia_io_handle *);
  114 int     stp4020_chip_io_map(pcmcia_chipset_handle_t, int, bus_addr_t,
  115             bus_size_t, struct pcmcia_io_handle *, int *);
  116 void    stp4020_chip_io_unmap(pcmcia_chipset_handle_t, int);
  117 
  118 void    stp4020_chip_socket_enable(pcmcia_chipset_handle_t);
  119 void    stp4020_chip_socket_disable(pcmcia_chipset_handle_t);
  120 void    *stp4020_chip_intr_establish(pcmcia_chipset_handle_t,
  121             struct pcmcia_function *, int, int (*) (void *), void *, char *);
  122 void    stp4020_chip_intr_disestablish(pcmcia_chipset_handle_t, void *);
  123 const char *stp4020_chip_intr_string(pcmcia_chipset_handle_t, void *);
  124 
  125 /* Our PCMCIA chipset methods */
  126 static struct pcmcia_chip_functions stp4020_functions = {
  127         stp4020_chip_mem_alloc,
  128         stp4020_chip_mem_free,
  129         stp4020_chip_mem_map,
  130         stp4020_chip_mem_unmap,
  131 
  132         stp4020_chip_io_alloc,
  133         stp4020_chip_io_free,
  134         stp4020_chip_io_map,
  135         stp4020_chip_io_unmap,
  136 
  137         stp4020_chip_intr_establish,
  138         stp4020_chip_intr_disestablish,
  139         stp4020_chip_intr_string,
  140 
  141         stp4020_chip_socket_enable,
  142         stp4020_chip_socket_disable
  143 };
  144 
  145 
  146 static __inline__ u_int16_t
  147 stp4020_rd_sockctl(h, idx)
  148         struct stp4020_socket *h;
  149         int idx;
  150 {
  151         int o = ((STP4020_SOCKREGS_SIZE * (h->sock)) + idx);
  152         return (bus_space_read_2(h->tag, h->regs, o));
  153 }
  154 
  155 static __inline__ void
  156 stp4020_wr_sockctl(h, idx, v)
  157         struct stp4020_socket *h;
  158         int idx;
  159         u_int16_t v;
  160 {
  161         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) + idx;
  162         bus_space_write_2(h->tag, h->regs, o, v);
  163 }
  164 
  165 static __inline__ u_int16_t
  166 stp4020_rd_winctl(h, win, idx)
  167         struct stp4020_socket *h;
  168         int win;
  169         int idx;
  170 {
  171         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
  172             (STP4020_WINREGS_SIZE * win) + idx;
  173         return (bus_space_read_2(h->tag, h->regs, o));
  174 }
  175 
  176 static __inline__ void
  177 stp4020_wr_winctl(h, win, idx, v)
  178         struct stp4020_socket *h;
  179         int win;
  180         int idx;
  181         u_int16_t v;
  182 {
  183         int o = (STP4020_SOCKREGS_SIZE * (h->sock)) +
  184             (STP4020_WINREGS_SIZE * win) + idx;
  185         bus_space_write_2(h->tag, h->regs, o, v);
  186 }
  187 
  188 
  189 int
  190 stp4020print(aux, busname)
  191         void *aux;
  192         const char *busname;
  193 {
  194         struct pcmciabus_attach_args *paa = aux;
  195         struct stp4020_socket *h = paa->pch;
  196 
  197         printf(" socket %d", h->sock);
  198         return (UNCONF);
  199 }
  200 
  201 /*
  202  * Attach all the sub-devices we can find
  203  */
  204 void
  205 stpattach_common(struct stp4020_softc *sc, int clockfreq)
  206 {
  207         int i, rev;
  208 
  209         rev = stp4020_rd_sockctl(&sc->sc_socks[0], STP4020_ISR1_IDX) &
  210             STP4020_ISR1_REV_M;
  211         printf(": rev %x\n", rev);
  212 
  213         sc->sc_pct = (pcmcia_chipset_tag_t)&stp4020_functions;
  214 
  215         /*
  216          * Arrange that a kernel thread be created to handle
  217          * insert/removal events.
  218          */
  219         sc->events = 0;
  220         kthread_create_deferred(stp4020_create_event_thread, sc);
  221 
  222         for (i = 0; i < STP4020_NSOCK; i++) {
  223                 struct stp4020_socket *h = &sc->sc_socks[i];
  224                 h->sock = i;
  225                 h->sc = sc;
  226 #ifdef STP4020_DEBUG
  227                 if (stp4020_debug)
  228                         stp4020_dump_regs(h);
  229 #endif
  230                 stp4020_attach_socket(h, clockfreq);
  231         }
  232 }
  233 
  234 void
  235 stp4020_attach_socket(h, speed)
  236         struct stp4020_socket *h;
  237         int speed;
  238 {
  239         struct pcmciabus_attach_args paa;
  240         int v;
  241 
  242         /* Map all three windows */
  243         stp4020_map_window(h, STP_WIN_ATTR, speed);
  244         stp4020_map_window(h, STP_WIN_MEM, speed);
  245         stp4020_map_window(h, STP_WIN_IO, speed);
  246 
  247         /* Configure one pcmcia device per socket */
  248         paa.paa_busname = "pcmcia";
  249         paa.pct = (pcmcia_chipset_tag_t)h->sc->sc_pct;
  250         paa.pch = (pcmcia_chipset_handle_t)h;
  251         paa.iobase = 0;
  252         paa.iosize = STP4020_WINDOW_SIZE;
  253 
  254         h->pcmcia = config_found(&h->sc->sc_dev, &paa, stp4020print);
  255 
  256         if (h->pcmcia == NULL)
  257                 return;
  258 
  259         /*
  260          * There's actually a pcmcia bus attached; initialize the slot.
  261          */
  262 
  263         /*
  264          * Clear things up before we enable status change interrupts.
  265          * This seems to not be fully initialized by the PROM.
  266          */
  267         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
  268         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 0);
  269         stp4020_wr_sockctl(h, STP4020_ISR1_IDX, 0x3fff);
  270         stp4020_wr_sockctl(h, STP4020_ISR0_IDX, 0x3fff);
  271 
  272         /*
  273          * Enable socket status change interrupts.
  274          * We use SB_INT[1] for status change interrupts.
  275          */
  276         v = STP4020_ICR0_ALL_STATUS_IE | STP4020_ICR0_SCILVL_SB1;
  277         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
  278 
  279         /* Get live status bits from ISR0 */
  280         v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  281         h->sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
  282         if (h->sense != 0) {
  283                 h->flags |= STP4020_SOCKET_BUSY;
  284                 pcmcia_card_attach(h->pcmcia);
  285         }
  286 }
  287 
  288 
  289 /*
  290  * Deferred thread creation callback.
  291  */
  292 void
  293 stp4020_create_event_thread(arg)
  294         void *arg;
  295 {
  296         struct stp4020_softc *sc = arg;
  297         const char *name = sc->sc_dev.dv_xname;
  298 
  299         if (kthread_create(stp4020_event_thread, sc, &sc->event_thread,
  300             "%s", name)) {
  301                 panic("%s: unable to create event thread", name);
  302         }
  303 }
  304 
  305 /*
  306  * The actual event handling thread.
  307  */
  308 void
  309 stp4020_event_thread(arg)
  310         void *arg;
  311 {
  312         struct stp4020_softc *sc = arg;
  313         int s, sense;
  314         unsigned int socket;
  315 
  316         for (;;) {
  317                 struct stp4020_socket *h;
  318 
  319                 s = splhigh();
  320                 if ((socket = ffs(sc->events)) == 0) {
  321                         splx(s);
  322                         (void)tsleep(&sc->events, PWAIT, "stp4020_ev", 0);
  323                         continue;
  324                 }
  325                 socket--;
  326                 sc->events &= ~(1 << socket);
  327                 splx(s);
  328 
  329                 if (socket >= STP4020_NSOCK) {
  330 #ifdef DEBUG
  331                         printf("stp4020_event_thread: wayward socket number %d\n",
  332                             socket);
  333 #endif
  334                         continue;
  335                 }
  336 
  337                 h = &sc->sc_socks[socket];
  338 
  339                 /* Read socket's ISR0 for the interrupt status bits */
  340                 sense = stp4020_rd_sockctl(h, STP4020_ISR0_IDX) &
  341                     (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
  342 
  343                 if (sense > h->sense) {
  344                         /*
  345                          * If at least one more sensor is asserted, this is
  346                          * a card insertion.
  347                          */
  348                         h->sense = sense;
  349                         if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
  350                                 h->flags |= STP4020_SOCKET_BUSY;
  351                                 pcmcia_card_attach(h->pcmcia);
  352                         }
  353                 } else if (sense < h->sense) {
  354                         /*
  355                          * If at least one less sensor is asserted, this is
  356                          * a card removal.
  357                          */
  358                         h->sense = sense;
  359                         if (h->flags & STP4020_SOCKET_BUSY) {
  360                                 h->flags &= ~STP4020_SOCKET_BUSY;
  361                                 pcmcia_card_detach(h->pcmcia, DETACH_FORCE);
  362                         }
  363                 }
  364         }
  365 }
  366 
  367 void
  368 stp4020_queue_event(sc, sock)
  369         struct stp4020_softc *sc;
  370         int sock;
  371 {
  372         int s;
  373 
  374         s = splhigh();
  375         sc->events |= (1 << sock);
  376         splx(s);
  377         wakeup(&sc->events);
  378 }
  379 
  380 int
  381 stp4020_statintr(arg)
  382         void *arg;
  383 {
  384         struct stp4020_softc *sc = arg;
  385         int i, sense, r = 0;
  386 
  387         /*
  388          * Check each socket for pending requests.
  389          */
  390         for (i = 0 ; i < STP4020_NSOCK; i++) {
  391                 struct stp4020_socket *h;
  392                 int v;
  393 
  394                 h = &sc->sc_socks[i];
  395 
  396                 /* Read socket's ISR0 for the interrupt status bits */
  397                 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  398                 sense = v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST);
  399 
  400 #ifdef STP4020_DEBUG
  401                 if (stp4020_debug != 0)
  402                         printf("stp4020_statintr: ISR0=%b\n",
  403                             v, STP4020_ISR0_IOBITS);
  404 #endif
  405 
  406                 /* Ack all interrupts at once */
  407                 stp4020_wr_sockctl(h, STP4020_ISR0_IDX,
  408                     STP4020_ISR0_ALL_STATUS_IRQ);
  409 
  410                 if ((v & STP4020_ISR0_CDCHG) != 0) {
  411                         r = 1;
  412 
  413                         /*
  414                          * Card detect status changed. In an ideal world,
  415                          * both card detect sensors should be set if a card
  416                          * is in the slot, and clear if it is not.
  417                          *
  418                          * Unfortunately, it turns out that we can get the
  419                          * notification before both sensors are set (or
  420                          * clear).
  421                          *
  422                          * This can be very funny if only one sensor is set.
  423                          * Is this a removal or an insertion operation?
  424                          * Defer appropriate action to the worker thread.
  425                          */
  426                         if (sense != h->sense)
  427                                 stp4020_queue_event(sc, i);
  428 
  429                 }
  430 
  431                 /* informational messages */
  432                 if ((v & STP4020_ISR0_BVD1CHG) != 0) {
  433                         DPRINTF(("stp4020[%d]: Battery change 1\n",
  434                             h->sock));
  435                         r = 1;
  436                 }
  437 
  438                 if ((v & STP4020_ISR0_BVD2CHG) != 0) {
  439                         DPRINTF(("stp4020[%d]: Battery change 2\n",
  440                             h->sock));
  441                         r = 1;
  442                 }
  443 
  444                 if ((v & STP4020_ISR0_RDYCHG) != 0) {
  445                         DPRINTF(("stp4020[%d]: Ready/Busy change\n",
  446                             h->sock));
  447                         r = 1;
  448                 }
  449 
  450                 if ((v & STP4020_ISR0_WPCHG) != 0) {
  451                         DPRINTF(("stp4020[%d]: Write protect change\n",
  452                             h->sock));
  453                         r = 1;
  454                 }
  455 
  456                 if ((v & STP4020_ISR0_PCTO) != 0) {
  457                         DPRINTF(("stp4020[%d]: Card access timeout\n",
  458                             h->sock));
  459                         r = 1;
  460                 }
  461 
  462                 if ((v & STP4020_ISR0_SCINT) != 0) {
  463                         DPRINTF(("stp4020[%d]: Status change\n",
  464                             h->sock));
  465                         r = 1;
  466                 }
  467 
  468                 /*
  469                  * Not interrupts flag per se, but interrupts can occur when
  470                  * they are asserted, at least during our slot enable routine.
  471                  */
  472                 if ((h->flags & STP4020_SOCKET_ENABLING) &&
  473                     (v & (STP4020_ISR0_WAITST | STP4020_ISR0_PWRON)))
  474                         r = 1;
  475         }
  476 
  477         return (r);
  478 }
  479 
  480 int
  481 stp4020_iointr(arg)
  482         void *arg;
  483 {
  484         struct stp4020_softc *sc = arg;
  485         int i, r = 0;
  486 
  487         /*
  488          * Check each socket for pending requests.
  489          */
  490         for (i = 0 ; i < STP4020_NSOCK; i++) {
  491                 struct stp4020_socket *h;
  492                 int v;
  493 
  494                 h = &sc->sc_socks[i];
  495                 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  496 
  497                 if ((v & STP4020_ISR0_IOINT) != 0) {
  498                         /* we can not deny this is ours, no matter what the
  499                            card driver says. */
  500                         r = 1;
  501 
  502                         /* ack interrupt */
  503                         stp4020_wr_sockctl(h, STP4020_ISR0_IDX, v);
  504 
  505                         /* It's a card interrupt */
  506                         if ((h->flags & STP4020_SOCKET_BUSY) == 0) {
  507                                 printf("stp4020[%d]: spurious interrupt?\n",
  508                                     h->sock);
  509                                 continue;
  510                         }
  511                         /* Call card handler, if any */
  512                         if (h->intrhandler != NULL) {
  513                                 /*
  514                                  * We ought to be at an higher ipl level
  515                                  * than the callback, since the first
  516                                  * interrupt of this device is usually
  517                                  * higher than IPL_CLOCK.
  518                                  */
  519                                 splassert(h->ipl);
  520                                 (*h->intrhandler)(h->intrarg);
  521                         }
  522                 }
  523 
  524         }
  525 
  526         return (r);
  527 }
  528 
  529 /*
  530  * The function gets the sbus speed and a access time and calculates
  531  * values for the CMDLNG and CMDDLAY registers.
  532  */
  533 void
  534 stp4020_calc_speed(int bus_speed, int ns, int *length, int *delay)
  535 {
  536         int result;
  537 
  538         if (ns < STP4020_MEM_SPEED_MIN)
  539                 ns = STP4020_MEM_SPEED_MIN;
  540         else if (ns > STP4020_MEM_SPEED_MAX)
  541                 ns = STP4020_MEM_SPEED_MAX;
  542         result = ns * (bus_speed / 1000);
  543         if (result % 1000000)
  544                 result = result / 1000000 + 1;
  545         else
  546                 result /= 1000000;
  547         *length = result;
  548 
  549         /* the sbus frequency range is limited, so we can keep this simple */
  550         *delay = ns <= STP4020_MEM_SPEED_MIN ? 1 : 2;
  551 }
  552 
  553 void
  554 stp4020_map_window(struct stp4020_socket *h, int win, int speed)
  555 {
  556         int v, length, delay;
  557 
  558         /*
  559          * According to the PC Card standard 300ns access timing should be
  560          * used for attribute memory access. Our pcmcia framework does not
  561          * seem to propagate timing information, so we use that
  562          * everywhere.
  563          */
  564         stp4020_calc_speed(speed, 300, &length, &delay);
  565 
  566         /*
  567          * Fill in the Address Space Select and Base Address
  568          * fields of this windows control register 0.
  569          */
  570         v = ((delay << STP4020_WCR0_CMDDLY_S) & STP4020_WCR0_CMDDLY_M) |
  571             ((length << STP4020_WCR0_CMDLNG_S) & STP4020_WCR0_CMDLNG_M);
  572         switch (win) {
  573         case STP_WIN_ATTR:
  574                 v |= STP4020_WCR0_ASPSEL_AM;
  575                 break;
  576         case STP_WIN_MEM:
  577                 v |= STP4020_WCR0_ASPSEL_CM;
  578                 break;
  579         case STP_WIN_IO:
  580                 v |= STP4020_WCR0_ASPSEL_IO;
  581                 break;
  582         }
  583         v |= (STP4020_ADDR2PAGE(0) & STP4020_WCR0_BASE_M);
  584         stp4020_wr_winctl(h, win, STP4020_WCR0_IDX, v);
  585         stp4020_wr_winctl(h, win, STP4020_WCR1_IDX,
  586             1 << STP4020_WCR1_WAITREQ_S);
  587 }
  588 
  589 int
  590 stp4020_chip_mem_alloc(pch, size, pcmhp)
  591         pcmcia_chipset_handle_t pch;
  592         bus_size_t size;
  593         struct pcmcia_mem_handle *pcmhp;
  594 {
  595         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  596 
  597         /* we can not do much here, defere work to _mem_map */
  598         pcmhp->memt = h->wintag;
  599         pcmhp->size = size;
  600         pcmhp->addr = 0;
  601         pcmhp->mhandle = 0;
  602         pcmhp->realsize = size;
  603 
  604         return (0);
  605 }
  606 
  607 void
  608 stp4020_chip_mem_free(pch, pcmhp)
  609         pcmcia_chipset_handle_t pch;
  610         struct pcmcia_mem_handle *pcmhp;
  611 {
  612 }
  613 
  614 int
  615 stp4020_chip_mem_map(pch, kind, card_addr, size, pcmhp, offsetp, windowp)
  616         pcmcia_chipset_handle_t pch;
  617         int kind;
  618         bus_addr_t card_addr;
  619         bus_size_t size;
  620         struct pcmcia_mem_handle *pcmhp;
  621         bus_size_t *offsetp;
  622         int *windowp;
  623 {
  624         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  625         int win = (kind & PCMCIA_MEM_ATTR) ? STP_WIN_ATTR : STP_WIN_MEM;
  626 
  627         pcmhp->memt = h->wintag;
  628         bus_space_subregion(h->wintag, h->windows[win].winaddr,
  629             card_addr, size, &pcmhp->memh);
  630         pcmhp->size = size;
  631         pcmhp->realsize = STP4020_WINDOW_SIZE - card_addr;
  632         *offsetp = 0;
  633         *windowp = win;
  634 
  635         return (0);
  636 }
  637 
  638 void
  639 stp4020_chip_mem_unmap(pch, win)
  640         pcmcia_chipset_handle_t pch;
  641         int win;
  642 {
  643 }
  644 
  645 int
  646 stp4020_chip_io_alloc(pch, start, size, align, pcihp)
  647         pcmcia_chipset_handle_t pch;
  648         bus_addr_t start;
  649         bus_size_t size;
  650         bus_size_t align;
  651         struct pcmcia_io_handle *pcihp;
  652 {
  653         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  654 
  655         pcihp->iot = h->wintag;
  656         pcihp->ioh = h->windows[STP_WIN_IO].winaddr;
  657         pcihp->size = size;
  658         return (0);
  659 }
  660 
  661 void
  662 stp4020_chip_io_free(pch, pcihp)
  663         pcmcia_chipset_handle_t pch;
  664         struct pcmcia_io_handle *pcihp;
  665 {
  666 }
  667 
  668 int
  669 stp4020_chip_io_map(pch, width, offset, size, pcihp, windowp)
  670         pcmcia_chipset_handle_t pch;
  671         int width;
  672         bus_addr_t offset;
  673         bus_size_t size;
  674         struct pcmcia_io_handle *pcihp;
  675         int *windowp;
  676 {
  677         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  678 
  679         pcihp->iot = h->wintag;
  680         bus_space_subregion(h->wintag, h->windows[STP_WIN_IO].winaddr,
  681             offset, size, &pcihp->ioh);
  682         *windowp = 0;
  683         return (0);
  684 }
  685 
  686 void
  687 stp4020_chip_io_unmap(pch, win)
  688         pcmcia_chipset_handle_t pch;
  689         int win;
  690 {
  691 }
  692 
  693 void
  694 stp4020_chip_socket_enable(pch)
  695         pcmcia_chipset_handle_t pch;
  696 {
  697         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  698         int i, v;
  699 
  700         h->flags |= STP4020_SOCKET_ENABLING;
  701 
  702         /* this bit is mostly stolen from pcic_attach_card */
  703 
  704         /* Power down the socket to reset it, clear the card reset pin */
  705         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
  706 
  707         /*
  708          * wait 300ms until power fails (Tpf).  Then, wait 100ms since
  709          * we are changing Vcc (Toff).
  710          */
  711         stp4020_delay((300 + 100) * 1000);
  712 
  713         /* Power up the socket */
  714         v = STP4020_ICR1_MSTPWR;
  715         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
  716 
  717         /*
  718          * wait 100ms until power raise (Tpr) and 20ms to become
  719          * stable (Tsu(Vcc)).
  720          *
  721          * some machines require some more time to be settled
  722          * (another 200ms is added here).
  723          */
  724         stp4020_delay((100 + 20 + 200) * 1000);
  725 
  726         v |= STP4020_ICR1_PCIFOE | STP4020_ICR1_VPP1_VCC;
  727         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, v);
  728 
  729         /*
  730          * hold RESET at least 20us.
  731          */
  732         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, 
  733             stp4020_rd_sockctl(h, STP4020_ICR0_IDX) | STP4020_ICR0_RESET);
  734         delay(20);
  735         stp4020_wr_sockctl(h, STP4020_ICR0_IDX,
  736             stp4020_rd_sockctl(h, STP4020_ICR0_IDX) & ~STP4020_ICR0_RESET);
  737 
  738         /* wait 20ms as per pc card standard (r2.01) section 4.3.6 */
  739         stp4020_delay(20000);
  740 
  741         /* Wait for the chip to finish initializing (5 seconds max) */
  742         for (i = 10000; i > 0; i--) {
  743                 v = stp4020_rd_sockctl(h, STP4020_ISR0_IDX);
  744                 /* If the card has been removed, abort */
  745                 if ((v & (STP4020_ISR0_CD1ST | STP4020_ISR0_CD2ST)) == 0) {
  746                         h->flags &= ~STP4020_SOCKET_ENABLING;
  747                         return;
  748                 }
  749                 if ((v & STP4020_ISR0_RDYST) != 0)
  750                         break;
  751                 delay(500);
  752         }
  753         if (i <= 0) {
  754 #ifdef STP4020_DEBUG
  755                 printf("stp4020_chip_socket_enable: not ready: status %b\n",
  756                     v, STP4020_ISR0_IOBITS);
  757 #endif
  758                 h->flags &= ~STP4020_SOCKET_ENABLING;
  759                 return;
  760         }
  761 
  762         v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
  763 
  764         /*
  765          * Check the card type.
  766          * Enable socket I/O interrupts for IO cards.
  767          * We use level SB_INT[0] for I/O interrupts.
  768          */
  769         if (pcmcia_card_gettype(h->pcmcia) == PCMCIA_IFTYPE_IO) {
  770                 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE);
  771                 v |= STP4020_ICR0_IFTYPE_IO | STP4020_ICR0_IOIE |
  772                     STP4020_ICR0_IOILVL_SB0 | STP4020_ICR0_SPKREN;
  773                 DPRINTF(("%s: configuring card for IO usage\n",
  774                     h->sc->sc_dev.dv_xname));
  775         } else {
  776                 v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
  777                     STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
  778                 v |= STP4020_ICR0_IFTYPE_MEM;
  779                 DPRINTF(("%s: configuring card for MEM ONLY usage\n",
  780                     h->sc->sc_dev.dv_xname));
  781         }
  782         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
  783 
  784         h->flags &= ~STP4020_SOCKET_ENABLING;
  785 }
  786 
  787 void
  788 stp4020_chip_socket_disable(pch)
  789         pcmcia_chipset_handle_t pch;
  790 {
  791         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  792         int v;
  793 
  794         /*
  795          * Disable socket I/O interrupts.
  796          */
  797         v = stp4020_rd_sockctl(h, STP4020_ICR0_IDX);
  798         v &= ~(STP4020_ICR0_IOILVL | STP4020_ICR0_IFTYPE |
  799             STP4020_ICR0_SPKREN | STP4020_ICR0_IOIE);
  800         stp4020_wr_sockctl(h, STP4020_ICR0_IDX, v);
  801 
  802         /* Power down the socket */
  803         stp4020_wr_sockctl(h, STP4020_ICR1_IDX, 0);
  804 
  805         /*
  806          * wait 300ms until power fails (Tpf).
  807          */
  808         stp4020_delay(300 * 1000);
  809 }
  810 
  811 void *
  812 stp4020_chip_intr_establish(pch, pf, ipl, handler, arg, xname)
  813         pcmcia_chipset_handle_t pch;
  814         struct pcmcia_function *pf;
  815         int ipl;
  816         int (*handler) (void *);
  817         void *arg;
  818         char *xname;
  819 {
  820         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  821 
  822         h->intrhandler = handler;
  823         h->intrarg = arg;
  824         h->ipl = ipl;
  825         return (h);
  826 }
  827 
  828 void
  829 stp4020_chip_intr_disestablish(pch, ih)
  830         pcmcia_chipset_handle_t pch;
  831         void *ih;
  832 {
  833         struct stp4020_socket *h = (struct stp4020_socket *)pch;
  834 
  835         h->intrhandler = NULL;
  836         h->intrarg = NULL;
  837 }
  838 
  839 const char *
  840 stp4020_chip_intr_string(pch, ih)
  841         pcmcia_chipset_handle_t pch;
  842         void *ih;
  843 {
  844         if (ih == NULL)
  845                 return ("couldn't establish interrupt");
  846         else
  847                 return ("");    /* nothing for now */
  848 }
  849 
  850 /*
  851  * Delay and possibly yield CPU.
  852  * XXX - assumes a context
  853  */
  854 void
  855 stp4020_delay(ms)
  856         unsigned int ms;
  857 {
  858         unsigned int ticks;
  859 
  860         /* Convert to ticks */
  861         ticks = (ms * hz) / 1000000;
  862 
  863         if (cold || ticks == 0) {
  864                 delay(ms);
  865                 return;
  866         }
  867 
  868 #ifdef DEBUG
  869         if (ticks > 60 * hz)
  870                 panic("stp4020: preposterous delay: %u", ticks);
  871 #endif
  872         tsleep(&ticks, 0, "stp4020_delay", ticks);
  873 }
  874 
  875 #ifdef STP4020_DEBUG
  876 void
  877 stp4020_dump_regs(h)
  878         struct stp4020_socket *h;
  879 {
  880         /*
  881          * Dump control and status registers.
  882          */
  883         printf("socket[%d] registers:\n"
  884             "\tICR0=%b\n\tICR1=%b\n\tISR0=%b\n\tISR1=%x\n", h->sock,
  885             stp4020_rd_sockctl(h, STP4020_ICR0_IDX), STP4020_ICR0_BITS,
  886             stp4020_rd_sockctl(h, STP4020_ICR1_IDX), STP4020_ICR1_BITS,
  887             stp4020_rd_sockctl(h, STP4020_ISR0_IDX), STP4020_ISR0_IOBITS,
  888             stp4020_rd_sockctl(h, STP4020_ISR1_IDX));
  889 }
  890 #endif /* STP4020_DEBUG */

/* [<][>][^][v][top][bottom][index][help] */