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/isa/gscsio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: gscsio.c,v 1.14 2022/04/06 18:59:28 naddy Exp $       */
    2 /*
    3  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 /*
   19  * National Semiconductor Geode SC1100 Super I/O.
   20  * Only ACCESS.bus logical device is supported.
   21  */
   22 
   23 #include <sys/param.h>
   24 #include <sys/systm.h>
   25 #include <sys/device.h>
   26 #include <sys/kernel.h>
   27 #include <sys/rwlock.h>
   28 
   29 #include <machine/bus.h>
   30 
   31 #include <dev/i2c/i2cvar.h>
   32 
   33 #include <dev/isa/isareg.h>
   34 #include <dev/isa/isavar.h>
   35 
   36 #include <dev/isa/gscsioreg.h>
   37 
   38 struct gscsio_softc {
   39         struct device sc_dev;
   40 
   41         bus_space_tag_t sc_iot;
   42         bus_space_handle_t sc_ioh;
   43 
   44         int sc_ld_en[GSCSIO_LDN_LAST + 1];
   45         bus_space_handle_t sc_ld_ioh0[GSCSIO_LDN_LAST + 1];
   46         bus_space_handle_t sc_ld_ioh1[GSCSIO_LDN_LAST + 1];
   47 
   48         /* ACCESS.bus */
   49         struct gscsio_acb {
   50                 void *sc;
   51                 bus_space_handle_t ioh;
   52                 struct rwlock buslock;
   53         } sc_acb[2];
   54         struct i2c_controller sc_acb1_tag;
   55         struct i2c_controller sc_acb2_tag;
   56 };
   57 
   58 /* Supported logical devices description */
   59 static const struct {
   60         const char *ld_name;
   61         int ld_num;
   62         int ld_iosize0;
   63         int ld_iosize1;
   64 } gscsio_ld[] = {
   65         { "ACB1", GSCSIO_LDN_ACB1, 6, 0 },
   66         { "ACB2", GSCSIO_LDN_ACB2, 6, 0 },
   67 };
   68 
   69 int     gscsio_probe(struct device *, void *, void *);
   70 void    gscsio_attach(struct device *, struct device *, void *);
   71 
   72 void    gscsio_acb_init(struct gscsio_acb *, i2c_tag_t);
   73 int     gscsio_acb_wait(struct gscsio_acb *, int, int);
   74 void    gscsio_acb_reset(struct gscsio_acb *acb);
   75 
   76 int     gscsio_acb_acquire_bus(void *, int);
   77 void    gscsio_acb_release_bus(void *, int);
   78 int     gscsio_acb_send_start(void *, int);
   79 int     gscsio_acb_send_stop(void *, int);
   80 int     gscsio_acb_initiate_xfer(void *, i2c_addr_t, int);
   81 int     gscsio_acb_read_byte(void *, uint8_t *, int);
   82 int     gscsio_acb_write_byte(void *, uint8_t, int);
   83 
   84 const struct cfattach gscsio_ca = {
   85         sizeof(struct gscsio_softc),
   86         gscsio_probe,
   87         gscsio_attach
   88 };
   89 
   90 struct cfdriver gscsio_cd = {
   91         NULL, "gscsio", DV_DULL
   92 };
   93 
   94 #define ACB_READ(reg) \
   95         bus_space_read_1(sc->sc_iot, acb->ioh, (reg))
   96 #define ACB_WRITE(reg, val) \
   97         bus_space_write_1(sc->sc_iot, acb->ioh, (reg), (val))
   98 
   99 static __inline u_int8_t
  100 idxread(bus_space_tag_t iot, bus_space_handle_t ioh, int idx)
  101 {
  102         bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
  103 
  104         return (bus_space_read_1(iot, ioh, GSCSIO_DAT));
  105 }
  106 
  107 static __inline void
  108 idxwrite(bus_space_tag_t iot, bus_space_handle_t ioh, int idx, u_int8_t data)
  109 {
  110         bus_space_write_1(iot, ioh, GSCSIO_IDX, idx);
  111         bus_space_write_1(iot, ioh, GSCSIO_DAT, data);
  112 }
  113 
  114 int
  115 gscsio_probe(struct device *parent, void *match, void *aux)
  116 {
  117         struct isa_attach_args *ia = aux;
  118         bus_space_tag_t iot;
  119         bus_space_handle_t ioh;
  120         int iobase;
  121         int rv = 0;
  122 
  123         iot = ia->ia_iot;
  124         iobase = ia->ipa_io[0].base;
  125         if (bus_space_map(iot, iobase, GSCSIO_IOSIZE, 0, &ioh))
  126                 return (0);
  127         if (idxread(iot, ioh, GSCSIO_ID) == GSCSIO_ID_SC1100)
  128                 rv = 1;
  129         bus_space_unmap(iot, ioh, GSCSIO_IOSIZE);
  130 
  131         if (rv) {
  132                 ia->ipa_nio = 1;
  133                 ia->ipa_io[0].length = GSCSIO_IOSIZE;
  134                 ia->ipa_nmem = 0;
  135                 ia->ipa_nirq = 0;
  136                 ia->ipa_ndrq = 0;
  137         }
  138 
  139         return (rv);
  140 }
  141 
  142 void
  143 gscsio_attach(struct device *parent, struct device *self, void *aux)
  144 {
  145         struct gscsio_softc *sc = (void *)self;
  146         struct isa_attach_args *ia = aux;
  147         int i;
  148         int iobase;
  149 
  150         sc->sc_iot = ia->ia_iot;
  151         if (bus_space_map(sc->sc_iot, ia->ipa_io[0].base, GSCSIO_IOSIZE,
  152             0, &sc->sc_ioh)) {
  153                 printf(": can't map i/o space\n");
  154                 return;
  155         }
  156         printf(": SC1100 SIO rev %d:",
  157             idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_REV));
  158 
  159         /* Configure all supported logical devices */
  160         for (i = 0; i < sizeof (gscsio_ld) / sizeof(gscsio_ld[0]); i++) {
  161                 sc->sc_ld_en[gscsio_ld[i].ld_num] = 0;
  162 
  163                 /* Select the device and check if it's activated */
  164                 idxwrite(sc->sc_iot, sc->sc_ioh, GSCSIO_LDN,
  165                     gscsio_ld[i].ld_num);
  166                 if ((idxread(sc->sc_iot, sc->sc_ioh, GSCSIO_ACT) &
  167                     GSCSIO_ACT_EN) == 0)
  168                         continue;
  169 
  170                 /* Map I/O space 0 if necessary */
  171                 if (gscsio_ld[i].ld_iosize0 != 0) {
  172                         iobase = idxread(sc->sc_iot, sc->sc_ioh,
  173                             GSCSIO_IO0_MSB);
  174                         iobase <<= 8;
  175                         iobase |= idxread(sc->sc_iot, sc->sc_ioh,
  176                             GSCSIO_IO0_LSB);
  177                         if (bus_space_map(sc->sc_iot, iobase,
  178                             gscsio_ld[i].ld_iosize0, 0,
  179                             &sc->sc_ld_ioh0[gscsio_ld[i].ld_num]))
  180                                 continue;
  181                 }
  182 
  183                 /* Map I/O space 1 if necessary */
  184                 if (gscsio_ld[i].ld_iosize1 != 0) {
  185                         iobase = idxread(sc->sc_iot, sc->sc_ioh,
  186                             GSCSIO_IO1_MSB);
  187                         iobase <<= 8;
  188                         iobase |= idxread(sc->sc_iot, sc->sc_ioh,
  189                             GSCSIO_IO1_LSB);
  190                         if (bus_space_map(sc->sc_iot, iobase,
  191                             gscsio_ld[i].ld_iosize1, 0,
  192                             &sc->sc_ld_ioh0[gscsio_ld[i].ld_num])) {
  193                                 bus_space_unmap(sc->sc_iot,
  194                                     sc->sc_ld_ioh0[gscsio_ld[i].ld_num],
  195                                     gscsio_ld[i].ld_iosize0);
  196                                 continue;
  197                         }
  198                 }
  199 
  200                 sc->sc_ld_en[gscsio_ld[i].ld_num] = 1;
  201                 printf(" %s", gscsio_ld[i].ld_name);
  202         }
  203         printf("\n");
  204 
  205         /* Initialize ACCESS.bus 1 */
  206         if (sc->sc_ld_en[GSCSIO_LDN_ACB1]) {
  207                 sc->sc_acb[0].sc = sc;
  208                 sc->sc_acb[0].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB1];
  209                 rw_init(&sc->sc_acb[0].buslock, "iiclk");
  210                 gscsio_acb_init(&sc->sc_acb[0], &sc->sc_acb1_tag);
  211         }
  212 
  213         /* Initialize ACCESS.bus 2 */
  214         if (sc->sc_ld_en[GSCSIO_LDN_ACB2]) {
  215                 sc->sc_acb[1].sc = sc;
  216                 sc->sc_acb[1].ioh = sc->sc_ld_ioh0[GSCSIO_LDN_ACB2];
  217                 rw_init(&sc->sc_acb[1].buslock, "iiclk");
  218                 gscsio_acb_init(&sc->sc_acb[1], &sc->sc_acb2_tag);
  219         }
  220 }
  221 
  222 void
  223 gscsio_acb_init(struct gscsio_acb *acb, i2c_tag_t tag)
  224 {
  225         struct gscsio_softc *sc = acb->sc;
  226         struct i2cbus_attach_args iba;
  227 
  228         /* Enable ACB and configure clock frequency */
  229         ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
  230             (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
  231 
  232         /* Select polling mode */
  233         ACB_WRITE(GSCSIO_ACB_CTL1, ACB_READ(GSCSIO_ACB_CTL1) &
  234             ~GSCSIO_ACB_CTL1_INTEN);
  235 
  236         /* Disable slave address */
  237         ACB_WRITE(GSCSIO_ACB_ADDR, ACB_READ(GSCSIO_ACB_ADDR) &
  238             ~GSCSIO_ACB_ADDR_SAEN);
  239 
  240         /* Attach I2C framework */
  241         tag->ic_cookie = acb;
  242         tag->ic_acquire_bus = gscsio_acb_acquire_bus;
  243         tag->ic_release_bus = gscsio_acb_release_bus;
  244         tag->ic_send_start = gscsio_acb_send_start;
  245         tag->ic_send_stop = gscsio_acb_send_stop;
  246         tag->ic_initiate_xfer = gscsio_acb_initiate_xfer;
  247         tag->ic_read_byte = gscsio_acb_read_byte;
  248         tag->ic_write_byte = gscsio_acb_write_byte;
  249 
  250         bzero(&iba, sizeof(iba));
  251         iba.iba_name = "iic";
  252         iba.iba_tag = tag;
  253         config_found(&sc->sc_dev, &iba, iicbus_print);
  254 }
  255 
  256 int
  257 gscsio_acb_wait(struct gscsio_acb *acb, int bits, int flags)
  258 {
  259         struct gscsio_softc *sc = acb->sc;
  260         u_int8_t st;
  261         int i;
  262 
  263         for (i = 0; i < 100; i++) {
  264                 st = ACB_READ(GSCSIO_ACB_ST);
  265                 if (st & GSCSIO_ACB_ST_BER) {
  266                         printf("%s: bus error, flags=0x%x\n",
  267                             sc->sc_dev.dv_xname, flags);
  268                         gscsio_acb_reset(acb);
  269                         return (EIO);
  270                 }
  271                 if (st & GSCSIO_ACB_ST_NEGACK) {
  272 #if 0
  273                         printf("%s: negative ack, flags=0x%x\n",
  274                             sc->sc_dev.dv_xname, flags);
  275 #endif
  276                         gscsio_acb_reset(acb);
  277                         return (EIO);
  278                 }
  279                 if ((st & bits) == bits)
  280                         break;
  281                 delay(10);
  282         }
  283         if ((st & bits) != bits) {
  284                 printf("%s: timeout, flags=0x%x\n",
  285                     sc->sc_dev.dv_xname, flags);
  286                 gscsio_acb_reset(acb);
  287                 return (ETIMEDOUT);
  288         }
  289 
  290         return (0);
  291 }
  292 
  293 void
  294 gscsio_acb_reset(struct gscsio_acb *acb)
  295 {
  296         struct gscsio_softc *sc = acb->sc;
  297         u_int8_t st, ctl;
  298 
  299         /* Clear MASTER, NEGACK and BER */
  300         st = ACB_READ(GSCSIO_ACB_ST);
  301         st |= GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_NEGACK | GSCSIO_ACB_ST_BER;
  302         ACB_WRITE(GSCSIO_ACB_ST, st);
  303 
  304         /* Disable and re-enable ACB */
  305         ACB_WRITE(GSCSIO_ACB_CTL2, 0);
  306         ACB_WRITE(GSCSIO_ACB_CTL2, GSCSIO_ACB_CTL2_EN |
  307             (GSCSIO_ACB_FREQ << GSCSIO_ACB_CTL2_FREQ_SHIFT));
  308 
  309         /* Send stop */
  310         ctl = ACB_READ(GSCSIO_ACB_CTL1);
  311         ctl |= GSCSIO_ACB_CTL1_STOP;
  312         ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  313 }
  314 
  315 int
  316 gscsio_acb_acquire_bus(void *cookie, int flags)
  317 {
  318         struct gscsio_acb *acb = cookie;
  319 
  320         if (cold || flags & I2C_F_POLL)
  321                 return (0);
  322 
  323         return (rw_enter(&acb->buslock, RW_WRITE | RW_INTR));
  324 }
  325 
  326 void
  327 gscsio_acb_release_bus(void *cookie, int flags)
  328 {
  329         struct gscsio_acb *acb = cookie;
  330 
  331         if (cold || flags & I2C_F_POLL)
  332                 return;
  333 
  334         rw_exit(&acb->buslock);
  335 }
  336 
  337 int
  338 gscsio_acb_send_start(void *cookie, int flags)
  339 {
  340         struct gscsio_acb *acb = cookie;
  341         struct gscsio_softc *sc = acb->sc;
  342         u_int8_t ctl;
  343 
  344         ctl = ACB_READ(GSCSIO_ACB_CTL1);
  345         ctl |= GSCSIO_ACB_CTL1_START;
  346         ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  347 
  348         return (0);
  349 }
  350 
  351 int
  352 gscsio_acb_send_stop(void *cookie, int flags)
  353 {
  354         struct gscsio_acb *acb = cookie;
  355         struct gscsio_softc *sc = acb->sc;
  356         u_int8_t ctl;
  357 
  358         ctl = ACB_READ(GSCSIO_ACB_CTL1);
  359         ctl |= GSCSIO_ACB_CTL1_STOP;
  360         ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  361 
  362         return (0);
  363 }
  364 
  365 int
  366 gscsio_acb_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
  367 {
  368         struct gscsio_acb *acb = cookie;
  369         struct gscsio_softc *sc = acb->sc;
  370         u_int8_t ctl;
  371         int dir;
  372         int error;
  373 
  374         /* Issue start condition */
  375         ctl = ACB_READ(GSCSIO_ACB_CTL1);
  376         ctl |= GSCSIO_ACB_CTL1_START;
  377         ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  378 
  379         /* Wait for bus mastership */
  380         if ((error = gscsio_acb_wait(acb,
  381             GSCSIO_ACB_ST_MASTER | GSCSIO_ACB_ST_SDAST, flags)))
  382                 return (error);
  383 
  384         /* Send address byte */
  385         dir = (flags & I2C_F_READ ? 1 : 0);
  386         ACB_WRITE(GSCSIO_ACB_SDA, (addr << 1) | dir);
  387 
  388         return (0);
  389 }
  390 
  391 int
  392 gscsio_acb_read_byte(void *cookie, uint8_t *bytep, int flags)
  393 {
  394         struct gscsio_acb *acb = cookie;
  395         struct gscsio_softc *sc = acb->sc;
  396         u_int8_t ctl;
  397         int error;
  398 
  399         /* Wait for the bus to be ready */
  400         if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
  401                 return (error);
  402 
  403         /* Acknowledge the last byte */
  404         if (flags & I2C_F_LAST) {
  405                 ctl = ACB_READ(GSCSIO_ACB_CTL1);
  406                 ctl |= GSCSIO_ACB_CTL1_ACK;
  407                 ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  408         }
  409 
  410         /* Read data byte */
  411         *bytep = ACB_READ(GSCSIO_ACB_SDA);
  412 
  413         return (0);
  414 }
  415 
  416 int
  417 gscsio_acb_write_byte(void *cookie, uint8_t byte, int flags)
  418 {
  419         struct gscsio_acb *acb = cookie;
  420         struct gscsio_softc *sc = acb->sc;
  421         u_int8_t ctl;
  422         int error;
  423 
  424         /* Wait for the bus to be ready */
  425         if ((error = gscsio_acb_wait(acb, GSCSIO_ACB_ST_SDAST, flags)))
  426                 return (error);
  427 
  428         /* Send stop after the last byte */
  429         if (flags & I2C_F_STOP) {
  430                 ctl = ACB_READ(GSCSIO_ACB_CTL1);
  431                 ctl |= GSCSIO_ACB_CTL1_STOP;
  432                 ACB_WRITE(GSCSIO_ACB_CTL1, ctl);
  433         }
  434 
  435         /* Write data byte */
  436         ACB_WRITE(GSCSIO_ACB_SDA, byte);
  437 
  438         return (0);
  439 }

Cache object: 3d4e32b27bd8b3873f30fdbf14d268cd


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