[BACK]Return to piixpm.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Annotation of src/sys/dev/pci/piixpm.c, Revision 1.49.2.1

1.49.2.1! pgoyette    1: /* $NetBSD: piixpm.c,v 1.50 2016/07/18 21:09:05 pgoyette Exp $ */
1.1       jmcneill    2: /*     $OpenBSD: piixpm.c,v 1.20 2006/02/27 08:25:02 grange Exp $      */
                      3:
                      4: /*
                      5:  * Copyright (c) 2005, 2006 Alexander Yurchenko <grange@openbsd.org>
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19:
                     20: /*
                     21:  * Intel PIIX and compatible Power Management controller driver.
                     22:  */
                     23:
1.19      lukem      24: #include <sys/cdefs.h>
1.49.2.1! pgoyette   25: __KERNEL_RCSID(0, "$NetBSD: piixpm.c,v 1.50 2016/07/18 21:09:05 pgoyette Exp $");
1.19      lukem      26:
1.1       jmcneill   27: #include <sys/param.h>
                     28: #include <sys/systm.h>
                     29: #include <sys/device.h>
                     30: #include <sys/kernel.h>
1.40      pgoyette   31: #include <sys/mutex.h>
1.1       jmcneill   32: #include <sys/proc.h>
                     33:
1.17      ad         34: #include <sys/bus.h>
1.1       jmcneill   35:
                     36: #include <dev/pci/pcidevs.h>
                     37: #include <dev/pci/pcireg.h>
                     38: #include <dev/pci/pcivar.h>
                     39:
                     40: #include <dev/pci/piixpmreg.h>
                     41:
                     42: #include <dev/i2c/i2cvar.h>
                     43:
1.5       drochner   44: #include <dev/ic/acpipmtimer.h>
1.4       jmcneill   45:
1.1       jmcneill   46: #ifdef PIIXPM_DEBUG
                     47: #define DPRINTF(x) printf x
                     48: #else
                     49: #define DPRINTF(x)
                     50: #endif
                     51:
1.35      hannken    52: #define PIIXPM_IS_CSB5(id) \
                     53:        (PCI_VENDOR((id)) == PCI_VENDOR_SERVERWORKS && \
                     54:        PCI_PRODUCT((id)) == PCI_PRODUCT_SERVERWORKS_CSB5)
1.1       jmcneill   55: #define PIIXPM_DELAY   200
                     56: #define PIIXPM_TIMEOUT 1
                     57:
1.42      soren      58: struct piixpm_smbus {
                     59:        int                     sda;
                     60:        struct                  piixpm_softc *softc;
                     61: };
1.36      jmcneill   62:
1.1       jmcneill   63: struct piixpm_softc {
1.25      joerg      64:        device_t                sc_dev;
1.1       jmcneill   65:
1.42      soren      66:        bus_space_tag_t         sc_iot;
                     67: #define        sc_pm_iot sc_iot
                     68: #define sc_smb_iot sc_iot
                     69:        bus_space_handle_t      sc_pm_ioh;
                     70:        bus_space_handle_t      sc_sb800_ioh;
1.4       jmcneill   71:        bus_space_handle_t      sc_smb_ioh;
                     72:        void *                  sc_smb_ih;
1.1       jmcneill   73:        int                     sc_poll;
                     74:
1.3       jmcneill   75:        pci_chipset_tag_t       sc_pc;
                     76:        pcitag_t                sc_pcitag;
1.35      hannken    77:        pcireg_t                sc_id;
1.3       jmcneill   78:
1.46      pgoyette   79:        int                     sc_numbusses;
                     80:        device_t                sc_i2c_device[4];
1.42      soren      81:        struct piixpm_smbus     sc_busses[4];
                     82:        struct i2c_controller   sc_i2c_tags[4];
                     83:
1.40      pgoyette   84:        kmutex_t                sc_i2c_mutex;
1.1       jmcneill   85:        struct {
1.42      soren      86:                i2c_op_t        op;
                     87:                void *          buf;
                     88:                size_t          len;
                     89:                int             flags;
                     90:                volatile int    error;
1.1       jmcneill   91:        }                       sc_i2c_xfer;
1.3       jmcneill   92:
                     93:        pcireg_t                sc_devact[2];
1.1       jmcneill   94: };
                     95:
1.25      joerg      96: static int     piixpm_match(device_t, cfdata_t, void *);
                     97: static void    piixpm_attach(device_t, device_t, void *);
1.46      pgoyette   98: static int     piixpm_rescan(device_t, const char *, const int *);
                     99: static void    piixpm_chdet(device_t, device_t);
1.1       jmcneill  100:
1.32      dyoung    101: static bool    piixpm_suspend(device_t, const pmf_qual_t *);
                    102: static bool    piixpm_resume(device_t, const pmf_qual_t *);
1.3       jmcneill  103:
1.42      soren     104: static int     piixpm_sb800_init(struct piixpm_softc *);
1.35      hannken   105: static void    piixpm_csb5_reset(void *);
1.25      joerg     106: static int     piixpm_i2c_acquire_bus(void *, int);
                    107: static void    piixpm_i2c_release_bus(void *, int);
                    108: static int     piixpm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
                    109:     size_t, void *, size_t, int);
1.1       jmcneill  110:
1.25      joerg     111: static int     piixpm_intr(void *);
1.1       jmcneill  112:
1.46      pgoyette  113: CFATTACH_DECL3_NEW(piixpm, sizeof(struct piixpm_softc),
                    114:     piixpm_match, piixpm_attach, NULL, NULL, piixpm_rescan, piixpm_chdet, 0);
1.1       jmcneill  115:
1.25      joerg     116: static int
                    117: piixpm_match(device_t parent, cfdata_t match, void *aux)
1.1       jmcneill  118: {
                    119:        struct pci_attach_args *pa;
                    120:
                    121:        pa = (struct pci_attach_args *)aux;
                    122:        switch (PCI_VENDOR(pa->pa_id)) {
                    123:        case PCI_VENDOR_INTEL:
                    124:                switch (PCI_PRODUCT(pa->pa_id)) {
                    125:                case PCI_PRODUCT_INTEL_82371AB_PMC:
                    126:                case PCI_PRODUCT_INTEL_82440MX_PMC:
                    127:                        return 1;
                    128:                }
                    129:                break;
                    130:        case PCI_VENDOR_ATI:
                    131:                switch (PCI_PRODUCT(pa->pa_id)) {
                    132:                case PCI_PRODUCT_ATI_SB200_SMB:
1.10      toshii    133:                case PCI_PRODUCT_ATI_SB300_SMB:
                    134:                case PCI_PRODUCT_ATI_SB400_SMB:
1.23      jmcneill  135:                case PCI_PRODUCT_ATI_SB600_SMB: /* matches SB600/SB700/SB800 */
1.1       jmcneill  136:                        return 1;
                    137:                }
                    138:                break;
1.14      martin    139:        case PCI_VENDOR_SERVERWORKS:
                    140:                switch (PCI_PRODUCT(pa->pa_id)) {
                    141:                case PCI_PRODUCT_SERVERWORKS_OSB4:
                    142:                case PCI_PRODUCT_SERVERWORKS_CSB5:
                    143:                case PCI_PRODUCT_SERVERWORKS_CSB6:
                    144:                case PCI_PRODUCT_SERVERWORKS_HT1000SB:
                    145:                        return 1;
                    146:                }
1.49.2.1! pgoyette  147:                break;
1.48      pgoyette  148:        case PCI_VENDOR_AMD:
                    149:                switch (PCI_PRODUCT(pa->pa_id)) {
                    150:                case PCI_PRODUCT_AMD_HUDSON_SMB:
                    151:                        return 1;
                    152:                }
1.49.2.1! pgoyette  153:                break;
1.1       jmcneill  154:        }
                    155:
                    156:        return 0;
                    157: }
                    158:
1.25      joerg     159: static void
                    160: piixpm_attach(device_t parent, device_t self, void *aux)
1.1       jmcneill  161: {
1.25      joerg     162:        struct piixpm_softc *sc = device_private(self);
1.1       jmcneill  163:        struct pci_attach_args *pa = aux;
                    164:        pcireg_t base, conf;
1.5       drochner  165:        pcireg_t pmmisc;
1.1       jmcneill  166:        pci_intr_handle_t ih;
                    167:        const char *intrstr = NULL;
1.46      pgoyette  168:        int i, flags;
1.44      christos  169:        char intrbuf[PCI_INTRSTR_LEN];
1.1       jmcneill  170:
1.25      joerg     171:        sc->sc_dev = self;
1.42      soren     172:        sc->sc_iot = pa->pa_iot;
1.35      hannken   173:        sc->sc_id = pa->pa_id;
1.3       jmcneill  174:        sc->sc_pc = pa->pa_pc;
                    175:        sc->sc_pcitag = pa->pa_tag;
1.46      pgoyette  176:        sc->sc_numbusses = 1;
1.3       jmcneill  177:
1.39      drochner  178:        pci_aprint_devinfo(pa, NULL);
1.3       jmcneill  179:
1.18      jmcneill  180:        if (!pmf_device_register(self, piixpm_suspend, piixpm_resume))
                    181:                aprint_error_dev(self, "couldn't establish power handler\n");
1.3       jmcneill  182:
1.1       jmcneill  183:        /* Read configuration */
                    184:        conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC);
1.25      joerg     185:        DPRINTF(("%s: conf 0x%x\n", device_xname(self), conf));
1.1       jmcneill  186:
1.5       drochner  187:        if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) ||
                    188:            (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_82371AB_PMC))
                    189:                goto nopowermanagement;
                    190:
                    191:        /* check whether I/O access to PM regs is enabled */
                    192:        pmmisc = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PMREGMISC);
                    193:        if (!(pmmisc & 1))
                    194:                goto nopowermanagement;
                    195:
1.4       jmcneill  196:        /* Map I/O space */
1.5       drochner  197:        base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE);
1.4       jmcneill  198:        if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(base),
                    199:            PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) {
1.49      msaitoh   200:                aprint_error_dev(self,
                    201:                    "can't map power management I/O space\n");
1.4       jmcneill  202:                goto nopowermanagement;
                    203:        }
                    204:
1.5       drochner  205:        /*
                    206:         * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M.
                    207:         * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20
                    208:         * in the "Specification update" (document #297738).
                    209:         */
1.25      joerg     210:        acpipmtimer_attach(self, sc->sc_pm_iot, sc->sc_pm_ioh,
1.5       drochner  211:                           PIIX_PM_PMTMR,
                    212:                (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0 );
1.4       jmcneill  213:
1.5       drochner  214: nopowermanagement:
1.36      jmcneill  215:
1.48      pgoyette  216:        /* SB800 rev 0x40+ and AMD HUDSON need special initialization */
                    217:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
                    218:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON_SMB) {
                    219:                if (piixpm_sb800_init(sc) == 0) {
                    220:                        goto attach_i2c;
                    221:                }
                    222:                aprint_normal_dev(self, "SMBus initialization failed\n");
                    223:                return;
                    224:        }
1.36      jmcneill  225:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI &&
                    226:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB &&
                    227:            PCI_REVISION(pa->pa_class) >= 0x40) {
1.42      soren     228:                if (piixpm_sb800_init(sc) == 0) {
1.46      pgoyette  229:                        sc->sc_numbusses = 4;
1.36      jmcneill  230:                        goto attach_i2c;
1.42      soren     231:                }
1.48      pgoyette  232:                aprint_normal_dev(self, "SMBus initialization failed\n");
1.36      jmcneill  233:                return;
                    234:        }
                    235:
1.1       jmcneill  236:        if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) {
1.25      joerg     237:                aprint_normal_dev(self, "SMBus disabled\n");
1.1       jmcneill  238:                return;
                    239:        }
                    240:
                    241:        /* Map I/O space */
                    242:        base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff;
1.4       jmcneill  243:        if (bus_space_map(sc->sc_smb_iot, PCI_MAPREG_IO_ADDR(base),
                    244:            PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
1.25      joerg     245:                aprint_error_dev(self, "can't map smbus I/O space\n");
1.1       jmcneill  246:                return;
                    247:        }
                    248:
                    249:        sc->sc_poll = 1;
1.28      pgoyette  250:        aprint_normal_dev(self, "");
1.1       jmcneill  251:        if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_SMI) {
                    252:                /* No PCI IRQ */
1.28      pgoyette  253:                aprint_normal("interrupting at SMI, ");
1.1       jmcneill  254:        } else if ((conf & PIIX_SMB_HOSTC_INTMASK) == PIIX_SMB_HOSTC_IRQ) {
                    255:                /* Install interrupt handler */
                    256:                if (pci_intr_map(pa, &ih) == 0) {
1.49      msaitoh   257:                        intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf,
                    258:                            sizeof(intrbuf));
                    259:                        sc->sc_smb_ih = pci_intr_establish(pa->pa_pc, ih,
                    260:                            IPL_BIO, piixpm_intr, sc);
1.4       jmcneill  261:                        if (sc->sc_smb_ih != NULL) {
1.28      pgoyette  262:                                aprint_normal("interrupting at %s", intrstr);
1.1       jmcneill  263:                                sc->sc_poll = 0;
                    264:                        }
                    265:                }
                    266:        }
1.26      martin    267:        if (sc->sc_poll)
1.28      pgoyette  268:                aprint_normal("polling");
1.1       jmcneill  269:
1.3       jmcneill  270:        aprint_normal("\n");
1.1       jmcneill  271:
1.37      jmcneill  272: attach_i2c:
1.46      pgoyette  273:        for (i = 0; i < sc->sc_numbusses; i++)
                    274:                sc->sc_i2c_device[i] = NULL;
                    275:
                    276:        flags = 0;
1.47      pgoyette  277:        mutex_init(&sc->sc_i2c_mutex, MUTEX_DEFAULT, IPL_NONE);
1.46      pgoyette  278:        piixpm_rescan(self, "i2cbus", &flags);
                    279: }
                    280:
                    281: static int
                    282: piixpm_rescan(device_t self, const char *ifattr, const int *flags)
                    283: {
                    284:        struct piixpm_softc *sc = device_private(self);
                    285:        struct i2cbus_attach_args iba;
                    286:        int i;
                    287:
                    288:        if (!ifattr_match(ifattr, "i2cbus"))
                    289:                return 0;
                    290:
1.1       jmcneill  291:        /* Attach I2C bus */
                    292:
1.46      pgoyette  293:        for (i = 0; i < sc->sc_numbusses; i++) {
                    294:                if (sc->sc_i2c_device[i])
                    295:                        continue;
1.42      soren     296:                sc->sc_busses[i].sda = i;
                    297:                sc->sc_busses[i].softc = sc;
                    298:                sc->sc_i2c_tags[i].ic_cookie = &sc->sc_busses[i];
                    299:                sc->sc_i2c_tags[i].ic_acquire_bus = piixpm_i2c_acquire_bus;
                    300:                sc->sc_i2c_tags[i].ic_release_bus = piixpm_i2c_release_bus;
                    301:                sc->sc_i2c_tags[i].ic_exec = piixpm_i2c_exec;
                    302:                memset(&iba, 0, sizeof(iba));
                    303:                iba.iba_type = I2C_TYPE_SMBUS;
                    304:                iba.iba_tag = &sc->sc_i2c_tags[i];
1.46      pgoyette  305:                sc->sc_i2c_device[i] = config_found_ia(self, ifattr, &iba,
                    306:                                                    iicbus_print);
1.42      soren     307:        }
1.46      pgoyette  308:
                    309:        return 0;
1.1       jmcneill  310: }
                    311:
1.46      pgoyette  312: static void
                    313: piixpm_chdet(device_t self, device_t child)
                    314: {
                    315:        struct piixpm_softc *sc = device_private(self);
                    316:        int i;
                    317:
                    318:        for (i = 0; i < sc->sc_numbusses; i++) {
                    319:                if (sc->sc_i2c_device[i] == child) {
                    320:                        sc->sc_i2c_device[i] = NULL;
                    321:                        break;
                    322:                }
                    323:        }
                    324: }
                    325:
                    326:
1.18      jmcneill  327: static bool
1.32      dyoung    328: piixpm_suspend(device_t dv, const pmf_qual_t *qual)
1.18      jmcneill  329: {
                    330:        struct piixpm_softc *sc = device_private(dv);
                    331:
                    332:        sc->sc_devact[0] = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                    333:            PIIX_DEVACTA);
                    334:        sc->sc_devact[1] = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                    335:            PIIX_DEVACTB);
                    336:
                    337:        return true;
                    338: }
                    339:
                    340: static bool
1.32      dyoung    341: piixpm_resume(device_t dv, const pmf_qual_t *qual)
1.3       jmcneill  342: {
1.18      jmcneill  343:        struct piixpm_softc *sc = device_private(dv);
1.3       jmcneill  344:
1.18      jmcneill  345:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTA,
                    346:            sc->sc_devact[0]);
                    347:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTB,
                    348:            sc->sc_devact[1]);
1.3       jmcneill  349:
1.18      jmcneill  350:        return true;
1.3       jmcneill  351: }
                    352:
1.36      jmcneill  353: /*
                    354:  * Extract SMBus base address from SB800 Power Management (PM) registers.
                    355:  * The PM registers can be accessed either through indirect I/O (CD6/CD7) or
                    356:  * direct mapping if AcpiMMioDecodeEn is enabled. Since this function is only
                    357:  * called once it uses indirect I/O for simplicity.
                    358:  */
                    359: static int
1.42      soren     360: piixpm_sb800_init(struct piixpm_softc *sc)
1.36      jmcneill  361: {
1.42      soren     362:        bus_space_tag_t iot = sc->sc_iot;
1.36      jmcneill  363:        bus_space_handle_t ioh; /* indirect I/O handle */
                    364:        uint16_t val, base_addr;
                    365:
                    366:        /* Fetch SMB base address */
                    367:        if (bus_space_map(iot,
                    368:            PIIXPM_INDIRECTIO_BASE, PIIXPM_INDIRECTIO_SIZE, 0, &ioh)) {
                    369:                device_printf(sc->sc_dev, "couldn't map indirect I/O space\n");
                    370:                return EBUSY;
                    371:        }
                    372:        bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX,
                    373:            SB800_PM_SMBUS0EN_LO);
                    374:        val = bus_space_read_1(iot, ioh, PIIXPM_INDIRECTIO_DATA);
                    375:        bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX,
                    376:            SB800_PM_SMBUS0EN_HI);
                    377:        val |= bus_space_read_1(iot, ioh, PIIXPM_INDIRECTIO_DATA) << 8;
1.42      soren     378:        sc->sc_sb800_ioh = ioh;
1.36      jmcneill  379:
                    380:        if ((val & SB800_PM_SMBUS0EN_ENABLE) == 0)
                    381:                return ENOENT;
                    382:
                    383:        base_addr = val & SB800_PM_SMBUS0EN_BADDR;
                    384:
                    385:        aprint_debug_dev(sc->sc_dev, "SMBus @ 0x%04x\n", base_addr);
                    386:
1.49      msaitoh   387:        bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_INDEX,
                    388:            SB800_PM_SMBUS0SELEN);
1.42      soren     389:        bus_space_write_1(iot, ioh, PIIXPM_INDIRECTIO_DATA, 1); /* SMBUS0SEL */
                    390:
                    391:        if (bus_space_map(iot, PCI_MAPREG_IO_ADDR(base_addr),
1.36      jmcneill  392:            PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
                    393:                aprint_error_dev(sc->sc_dev, "can't map smbus I/O space\n");
                    394:                return EBUSY;
                    395:        }
1.40      pgoyette  396:        aprint_normal_dev(sc->sc_dev, "polling (SB800)\n");
1.36      jmcneill  397:        sc->sc_poll = 1;
                    398:
                    399:        return 0;
                    400: }
                    401:
1.35      hannken   402: static void
                    403: piixpm_csb5_reset(void *arg)
                    404: {
                    405:        struct piixpm_softc *sc = arg;
                    406:        pcireg_t base, hostc, pmbase;
                    407:
                    408:        base = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE);
                    409:        hostc = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC);
                    410:
                    411:        pmbase = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE);
                    412:        pmbase |= PIIX_PM_BASE_CSB5_RESET;
                    413:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase);
                    414:        pmbase &= ~PIIX_PM_BASE_CSB5_RESET;
                    415:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_PM_BASE, pmbase);
                    416:
                    417:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_BASE, base);
                    418:        pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_SMB_HOSTC, hostc);
                    419:
                    420:        (void) tsleep(&sc, PRIBIO, "csb5reset", hz/2);
                    421: }
                    422:
1.25      joerg     423: static int
1.1       jmcneill  424: piixpm_i2c_acquire_bus(void *cookie, int flags)
                    425: {
1.42      soren     426:        struct piixpm_smbus *smbus = cookie;
                    427:        struct piixpm_softc *sc = smbus->softc;
1.1       jmcneill  428:
1.40      pgoyette  429:        if (!cold)
                    430:                mutex_enter(&sc->sc_i2c_mutex);
1.1       jmcneill  431:
1.42      soren     432:        if (smbus->sda > 0)     /* SB800 */
                    433:        {
                    434:                bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh,
                    435:                    PIIXPM_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL);
                    436:                bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh,
                    437:                    PIIXPM_INDIRECTIO_DATA, smbus->sda << 1);
                    438:        }
                    439:
1.16      xtraeme   440:        return 0;
1.1       jmcneill  441: }
                    442:
1.25      joerg     443: static void
1.1       jmcneill  444: piixpm_i2c_release_bus(void *cookie, int flags)
                    445: {
1.42      soren     446:        struct piixpm_smbus *smbus = cookie;
                    447:        struct piixpm_softc *sc = smbus->softc;
                    448:
                    449:        if (smbus->sda > 0)     /* SB800 */
                    450:        {
                    451:                /*
                    452:                 * HP Microserver hangs after reboot if not set to SDA0.
                    453:                 * Also add shutdown hook?
                    454:                 */
                    455:                bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh,
                    456:                    PIIXPM_INDIRECTIO_INDEX, SB800_PM_SMBUS0SEL);
                    457:                bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh,
                    458:                    PIIXPM_INDIRECTIO_DATA, 0);
                    459:        }
1.1       jmcneill  460:
1.40      pgoyette  461:        if (!cold)
                    462:                mutex_exit(&sc->sc_i2c_mutex);
1.1       jmcneill  463: }
                    464:
1.25      joerg     465: static int
1.1       jmcneill  466: piixpm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
                    467:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
                    468: {
1.42      soren     469:        struct piixpm_smbus *smbus = cookie;
                    470:        struct piixpm_softc *sc = smbus->softc;
1.1       jmcneill  471:        const u_int8_t *b;
                    472:        u_int8_t ctl = 0, st;
                    473:        int retries;
                    474:
1.33      jakllsch  475:        DPRINTF(("%s: exec: op %d, addr 0x%x, cmdlen %zu, len %zu, flags 0x%x\n",
1.25      joerg     476:            device_xname(sc->sc_dev), op, addr, cmdlen, len, flags));
1.1       jmcneill  477:
1.41      soren     478:        /* Clear status bits */
1.49      msaitoh   479:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS,
                    480:            PIIX_SMB_HS_INTR | PIIX_SMB_HS_DEVERR |
1.41      soren     481:            PIIX_SMB_HS_BUSERR | PIIX_SMB_HS_FAILED);
1.42      soren     482:        bus_space_barrier(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, 1,
1.41      soren     483:            BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
                    484:
1.1       jmcneill  485:        /* Wait for bus to be idle */
                    486:        for (retries = 100; retries > 0; retries--) {
1.4       jmcneill  487:                st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                    488:                    PIIX_SMB_HS);
1.1       jmcneill  489:                if (!(st & PIIX_SMB_HS_BUSY))
                    490:                        break;
                    491:                DELAY(PIIXPM_DELAY);
                    492:        }
1.25      joerg     493:        DPRINTF(("%s: exec: st 0x%d\n", device_xname(sc->sc_dev), st & 0xff));
1.1       jmcneill  494:        if (st & PIIX_SMB_HS_BUSY)
                    495:                return (1);
                    496:
                    497:        if (cold || sc->sc_poll)
                    498:                flags |= I2C_F_POLL;
                    499:
1.34      hannken   500:        if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2 ||
                    501:            (cmdlen == 0 && len > 1))
1.1       jmcneill  502:                return (1);
                    503:
                    504:        /* Setup transfer */
                    505:        sc->sc_i2c_xfer.op = op;
                    506:        sc->sc_i2c_xfer.buf = buf;
                    507:        sc->sc_i2c_xfer.len = len;
                    508:        sc->sc_i2c_xfer.flags = flags;
                    509:        sc->sc_i2c_xfer.error = 0;
                    510:
                    511:        /* Set slave address and transfer direction */
1.4       jmcneill  512:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA,
1.1       jmcneill  513:            PIIX_SMB_TXSLVA_ADDR(addr) |
                    514:            (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0));
                    515:
                    516:        b = cmdbuf;
                    517:        if (cmdlen > 0)
                    518:                /* Set command byte */
1.4       jmcneill  519:                bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                    520:                    PIIX_SMB_HCMD, b[0]);
1.1       jmcneill  521:
                    522:        if (I2C_OP_WRITE_P(op)) {
                    523:                /* Write data */
                    524:                b = buf;
1.34      hannken   525:                if (cmdlen == 0 && len == 1)
                    526:                        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                    527:                            PIIX_SMB_HCMD, b[0]);
                    528:                else if (len > 0)
1.4       jmcneill  529:                        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
1.1       jmcneill  530:                            PIIX_SMB_HD0, b[0]);
                    531:                if (len > 1)
1.4       jmcneill  532:                        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
1.1       jmcneill  533:                            PIIX_SMB_HD1, b[1]);
                    534:        }
                    535:
                    536:        /* Set SMBus command */
1.34      hannken   537:        if (cmdlen == 0) {
                    538:                if (len == 0)
1.27      pgoyette  539:                        ctl = PIIX_SMB_HC_CMD_QUICK;
                    540:                else
                    541:                        ctl = PIIX_SMB_HC_CMD_BYTE;
                    542:        } else if (len == 1)
1.1       jmcneill  543:                ctl = PIIX_SMB_HC_CMD_BDATA;
                    544:        else if (len == 2)
                    545:                ctl = PIIX_SMB_HC_CMD_WDATA;
                    546:
                    547:        if ((flags & I2C_F_POLL) == 0)
                    548:                ctl |= PIIX_SMB_HC_INTREN;
                    549:
                    550:        /* Start transaction */
                    551:        ctl |= PIIX_SMB_HC_START;
1.4       jmcneill  552:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl);
1.1       jmcneill  553:
                    554:        if (flags & I2C_F_POLL) {
                    555:                /* Poll for completion */
1.35      hannken   556:                if (PIIXPM_IS_CSB5(sc->sc_id))
                    557:                        DELAY(2*PIIXPM_DELAY);
                    558:                else
                    559:                        DELAY(PIIXPM_DELAY);
1.1       jmcneill  560:                for (retries = 1000; retries > 0; retries--) {
1.4       jmcneill  561:                        st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
1.1       jmcneill  562:                            PIIX_SMB_HS);
                    563:                        if ((st & PIIX_SMB_HS_BUSY) == 0)
                    564:                                break;
                    565:                        DELAY(PIIXPM_DELAY);
                    566:                }
                    567:                if (st & PIIX_SMB_HS_BUSY)
                    568:                        goto timeout;
1.45      hannken   569:                piixpm_intr(sc);
1.1       jmcneill  570:        } else {
                    571:                /* Wait for interrupt */
                    572:                if (tsleep(sc, PRIBIO, "iicexec", PIIXPM_TIMEOUT * hz))
                    573:                        goto timeout;
                    574:        }
                    575:
                    576:        if (sc->sc_i2c_xfer.error)
                    577:                return (1);
                    578:
                    579:        return (0);
                    580:
                    581: timeout:
                    582:        /*
                    583:         * Transfer timeout. Kill the transaction and clear status bits.
                    584:         */
1.25      joerg     585:        aprint_error_dev(sc->sc_dev, "timeout, status 0x%x\n", st);
1.4       jmcneill  586:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC,
1.1       jmcneill  587:            PIIX_SMB_HC_KILL);
                    588:        DELAY(PIIXPM_DELAY);
1.4       jmcneill  589:        st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS);
1.1       jmcneill  590:        if ((st & PIIX_SMB_HS_FAILED) == 0)
1.49      msaitoh   591:                aprint_error_dev(sc->sc_dev,
                    592:                    "transaction abort failed, status 0x%x\n", st);
1.4       jmcneill  593:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st);
1.35      hannken   594:        /*
                    595:         * CSB5 needs hard reset to unlock the smbus after timeout.
                    596:         */
                    597:        if (PIIXPM_IS_CSB5(sc->sc_id))
                    598:                piixpm_csb5_reset(sc);
1.1       jmcneill  599:        return (1);
                    600: }
                    601:
1.25      joerg     602: static int
1.1       jmcneill  603: piixpm_intr(void *arg)
                    604: {
1.45      hannken   605:        struct piixpm_softc *sc = arg;
1.1       jmcneill  606:        u_int8_t st;
                    607:        u_int8_t *b;
                    608:        size_t len;
                    609:
                    610:        /* Read status */
1.4       jmcneill  611:        st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS);
1.1       jmcneill  612:        if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR |
                    613:            PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
                    614:            PIIX_SMB_HS_FAILED)) == 0)
                    615:                /* Interrupt was not for us */
                    616:                return (0);
                    617:
1.25      joerg     618:        DPRINTF(("%s: intr st 0x%d\n", device_xname(sc->sc_dev), st & 0xff));
1.1       jmcneill  619:
                    620:        /* Clear status bits */
1.4       jmcneill  621:        bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st);
1.1       jmcneill  622:
                    623:        /* Check for errors */
                    624:        if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
                    625:            PIIX_SMB_HS_FAILED)) {
                    626:                sc->sc_i2c_xfer.error = 1;
                    627:                goto done;
                    628:        }
                    629:
                    630:        if (st & PIIX_SMB_HS_INTR) {
                    631:                if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
                    632:                        goto done;
                    633:
                    634:                /* Read data */
                    635:                b = sc->sc_i2c_xfer.buf;
                    636:                len = sc->sc_i2c_xfer.len;
                    637:                if (len > 0)
1.4       jmcneill  638:                        b[0] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
1.1       jmcneill  639:                            PIIX_SMB_HD0);
                    640:                if (len > 1)
1.4       jmcneill  641:                        b[1] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
1.1       jmcneill  642:                            PIIX_SMB_HD1);
                    643:        }
                    644:
                    645: done:
                    646:        if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
                    647:                wakeup(sc);
                    648:        return (1);
                    649: }

CVSweb <webmaster@jp.NetBSD.org>