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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/pci/piixpm.c between version 1.3 and 1.3.2.6

version 1.3, 2006/06/17 17:04:44 version 1.3.2.6, 2008/01/21 09:44:14
Line 21 
Line 21 
  * Intel PIIX and compatible Power Management controller driver.   * Intel PIIX and compatible Power Management controller driver.
  */   */
   
   #include <sys/cdefs.h>
   __KERNEL_RCSID(0, "$NetBSD$");
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/device.h>  #include <sys/device.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
 #include <sys/lock.h>  #include <sys/rwlock.h>
 #include <sys/proc.h>  #include <sys/proc.h>
   
 #include <machine/bus.h>  #include <sys/bus.h>
   
 #include <dev/pci/pcidevs.h>  #include <dev/pci/pcidevs.h>
 #include <dev/pci/pcireg.h>  #include <dev/pci/pcireg.h>
Line 38 
Line 41 
   
 #include <dev/i2c/i2cvar.h>  #include <dev/i2c/i2cvar.h>
   
   #include <dev/ic/acpipmtimer.h>
   
 #ifdef PIIXPM_DEBUG  #ifdef PIIXPM_DEBUG
 #define DPRINTF(x) printf x  #define DPRINTF(x) printf x
 #else  #else
Line 50 
Line 55 
 struct piixpm_softc {  struct piixpm_softc {
         struct device           sc_dev;          struct device           sc_dev;
   
         bus_space_tag_t         sc_iot;          bus_space_tag_t         sc_smb_iot;
         bus_space_handle_t      sc_ioh;          bus_space_handle_t      sc_smb_ioh;
         void *                  sc_ih;          void *                  sc_smb_ih;
         int                     sc_poll;          int                     sc_poll;
   
           bus_space_tag_t         sc_pm_iot;
           bus_space_handle_t      sc_pm_ioh;
   
         pci_chipset_tag_t       sc_pc;          pci_chipset_tag_t       sc_pc;
         pcitag_t                sc_pcitag;          pcitag_t                sc_pcitag;
   
         struct i2c_controller   sc_i2c_tag;          struct i2c_controller   sc_i2c_tag;
         struct lock             sc_i2c_lock;          krwlock_t               sc_i2c_rwlock;
         struct {          struct {
                 i2c_op_t     op;                  i2c_op_t     op;
                 void *       buf;                  void *      buf;
                 size_t       len;                  size_t       len;
                 int          flags;                  int          flags;
                 volatile int error;                  volatile int error;
         }                       sc_i2c_xfer;          }                       sc_i2c_xfer;
   
         void *                  sc_powerhook;  
         struct pci_conf_state   sc_pciconf;  
         pcireg_t                sc_devact[2];          pcireg_t                sc_devact[2];
 };  };
   
 int     piixpm_match(struct device *, struct cfdata *, void *);  int     piixpm_match(struct device *, struct cfdata *, void *);
 void    piixpm_attach(struct device *, struct device *, void *);  void    piixpm_attach(struct device *, struct device *, void *);
   
 void    piixpm_powerhook(int, void *);  static bool     piixpm_suspend(device_t);
   static bool     piixpm_resume(device_t);
   
 int     piixpm_i2c_acquire_bus(void *, int);  int     piixpm_i2c_acquire_bus(void *, int);
 void    piixpm_i2c_release_bus(void *, int);  void    piixpm_i2c_release_bus(void *, int);
Line 89  CFATTACH_DECL(piixpm, sizeof(struct piix
Line 96  CFATTACH_DECL(piixpm, sizeof(struct piix
     piixpm_match, piixpm_attach, NULL, NULL);      piixpm_match, piixpm_attach, NULL, NULL);
   
 int  int
 piixpm_match(struct device *parent, struct cfdata *match, void *aux)  piixpm_match(struct device *parent, struct cfdata *match,
       void *aux)
 {  {
         struct pci_attach_args *pa;          struct pci_attach_args *pa;
   
Line 105  piixpm_match(struct device *parent, stru
Line 113  piixpm_match(struct device *parent, stru
         case PCI_VENDOR_ATI:          case PCI_VENDOR_ATI:
                 switch (PCI_PRODUCT(pa->pa_id)) {                  switch (PCI_PRODUCT(pa->pa_id)) {
                 case PCI_PRODUCT_ATI_SB200_SMB:                  case PCI_PRODUCT_ATI_SB200_SMB:
                   case PCI_PRODUCT_ATI_SB300_SMB:
                   case PCI_PRODUCT_ATI_SB400_SMB:
                         return 1;                          return 1;
                 }                  }
                 break;                  break;
           case PCI_VENDOR_SERVERWORKS:
                   switch (PCI_PRODUCT(pa->pa_id)) {
                   case PCI_PRODUCT_SERVERWORKS_OSB4:
                   case PCI_PRODUCT_SERVERWORKS_CSB5:
                   case PCI_PRODUCT_SERVERWORKS_CSB6:
                   case PCI_PRODUCT_SERVERWORKS_HT1000SB:
                           return 1;
                   }
         }          }
   
         return 0;          return 0;
Line 120  piixpm_attach(struct device *parent, str
Line 138  piixpm_attach(struct device *parent, str
         struct pci_attach_args *pa = aux;          struct pci_attach_args *pa = aux;
         struct i2cbus_attach_args iba;          struct i2cbus_attach_args iba;
         pcireg_t base, conf;          pcireg_t base, conf;
           pcireg_t pmmisc;
         pci_intr_handle_t ih;          pci_intr_handle_t ih;
           char devinfo[256];
         const char *intrstr = NULL;          const char *intrstr = NULL;
   
         sc->sc_pc = pa->pa_pc;          sc->sc_pc = pa->pa_pc;
         sc->sc_pcitag = pa->pa_tag;          sc->sc_pcitag = pa->pa_tag;
   
         aprint_naive("\n");          aprint_naive("\n");
         aprint_normal(": Power Management Controller\n");  
   
         sc->sc_powerhook = powerhook_establish(piixpm_powerhook, sc);          pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
         if (sc->sc_powerhook == NULL)          aprint_normal("\n%s: %s (rev. 0x%02x)\n",
                 aprint_error("%s: can't establish powerhook\n",                        device_xname(self), devinfo, PCI_REVISION(pa->pa_class));
                     sc->sc_dev.dv_xname);  
           if (!pmf_device_register(self, piixpm_suspend, piixpm_resume))
                   aprint_error_dev(self, "couldn't establish power handler\n");
   
         /* Read configuration */          /* Read configuration */
         conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC);          conf = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_HOSTC);
         DPRINTF((": conf 0x%x", conf));          DPRINTF((": conf 0x%x", conf));
   
           if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL) ||
               (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_INTEL_82371AB_PMC))
                   goto nopowermanagement;
   
           /* check whether I/O access to PM regs is enabled */
           pmmisc = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PMREGMISC);
           if (!(pmmisc & 1))
                   goto nopowermanagement;
   
           sc->sc_pm_iot = pa->pa_iot;
           /* Map I/O space */
           base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_PM_BASE);
           if (bus_space_map(sc->sc_pm_iot, PCI_MAPREG_IO_ADDR(base),
               PIIX_PM_SIZE, 0, &sc->sc_pm_ioh)) {
                   aprint_error("%s: can't map power management I/O space\n",
                       sc->sc_dev.dv_xname);
                   goto nopowermanagement;
           }
   
           /*
            * Revision 0 and 1 are PIIX4, 2 is PIIX4E, 3 is PIIX4M.
            * PIIX4 and PIIX4E have a bug in the timer latch, see Errata #20
            * in the "Specification update" (document #297738).
            */
           acpipmtimer_attach(&sc->sc_dev, sc->sc_pm_iot, sc->sc_pm_ioh,
                              PIIX_PM_PMTMR,
                   (PCI_REVISION(pa->pa_class) < 3) ? ACPIPMT_BADLATCH : 0 );
   
   nopowermanagement:
         if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) {          if ((conf & PIIX_SMB_HOSTC_HSTEN) == 0) {
                 aprint_normal("%s: SMBus disabled\n", sc->sc_dev.dv_xname);                  aprint_normal("%s: SMBus disabled\n", sc->sc_dev.dv_xname);
                 return;                  return;
         }          }
   
         /* Map I/O space */          /* Map I/O space */
         sc->sc_iot = pa->pa_iot;          sc->sc_smb_iot = pa->pa_iot;
         base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff;          base = pci_conf_read(pa->pa_pc, pa->pa_tag, PIIX_SMB_BASE) & 0xffff;
         if (bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(base),          if (bus_space_map(sc->sc_smb_iot, PCI_MAPREG_IO_ADDR(base),
             PIIX_SMB_SIZE, 0, &sc->sc_ioh)) {              PIIX_SMB_SIZE, 0, &sc->sc_smb_ioh)) {
                 aprint_error("%s: can't map I/O space\n",                  aprint_error("%s: can't map smbus I/O space\n",
                     sc->sc_dev.dv_xname);                      sc->sc_dev.dv_xname);
                 return;                  return;
         }          }
Line 161  piixpm_attach(struct device *parent, str
Line 211  piixpm_attach(struct device *parent, str
                 /* Install interrupt handler */                  /* Install interrupt handler */
                 if (pci_intr_map(pa, &ih) == 0) {                  if (pci_intr_map(pa, &ih) == 0) {
                         intrstr = pci_intr_string(pa->pa_pc, ih);                          intrstr = pci_intr_string(pa->pa_pc, ih);
                         sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,                          sc->sc_smb_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
                             piixpm_intr, sc);                              piixpm_intr, sc);
                         if (sc->sc_ih != NULL) {                          if (sc->sc_smb_ih != NULL) {
                                 aprint_normal("%s: interrupting at %s",                                  aprint_normal("%s: interrupting at %s",
                                     sc->sc_dev.dv_xname, intrstr);                                      sc->sc_dev.dv_xname, intrstr);
                                 sc->sc_poll = 0;                                  sc->sc_poll = 0;
Line 176  piixpm_attach(struct device *parent, str
Line 226  piixpm_attach(struct device *parent, str
         aprint_normal("\n");          aprint_normal("\n");
   
         /* Attach I2C bus */          /* Attach I2C bus */
         lockinit(&sc->sc_i2c_lock, PRIBIO | PCATCH, "iiclk", 0, 0);          rw_init(&sc->sc_i2c_rwlock);
         sc->sc_i2c_tag.ic_cookie = sc;          sc->sc_i2c_tag.ic_cookie = sc;
         sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus;          sc->sc_i2c_tag.ic_acquire_bus = piixpm_i2c_acquire_bus;
         sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus;          sc->sc_i2c_tag.ic_release_bus = piixpm_i2c_release_bus;
         sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec;          sc->sc_i2c_tag.ic_exec = piixpm_i2c_exec;
   
         bzero(&iba, sizeof(iba));          bzero(&iba, sizeof(iba));
         iba.iba_name = "iic";  
         iba.iba_tag = &sc->sc_i2c_tag;          iba.iba_tag = &sc->sc_i2c_tag;
         config_found(self, &iba, iicbus_print);          config_found_ia(self, "i2cbus", &iba, iicbus_print);
   
         return;          return;
 }  }
   
 void  static bool
 piixpm_powerhook(int why, void *cookie)  piixpm_suspend(device_t dv)
 {  {
         struct piixpm_softc *sc = cookie;          struct piixpm_softc *sc = device_private(dv);
         pci_chipset_tag_t pc = sc->sc_pc;  
         pcitag_t tag = sc->sc_pcitag;  
   
         switch (why) {          sc->sc_devact[0] = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
         case PWR_SUSPEND:              PIIX_DEVACTA);
                 pci_conf_capture(pc, tag, &sc->sc_pciconf);          sc->sc_devact[1] = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
                 sc->sc_devact[0] = pci_conf_read(pc, tag, PIIX_DEVACTA);              PIIX_DEVACTB);
                 sc->sc_devact[1] = pci_conf_read(pc, tag, PIIX_DEVACTB);  
                 break;  
         case PWR_RESUME:  
                 pci_conf_restore(pc, tag, &sc->sc_pciconf);  
                 pci_conf_write(pc, tag, PIIX_DEVACTA, sc->sc_devact[0]);  
                 pci_conf_write(pc, tag, PIIX_DEVACTB, sc->sc_devact[1]);  
                 break;  
         }  
   
         return;          return true;
   }
   
   static bool
   piixpm_resume(device_t dv)
   {
           struct piixpm_softc *sc = device_private(dv);
   
           pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTA,
               sc->sc_devact[0]);
           pci_conf_write(sc->sc_pc, sc->sc_pcitag, PIIX_DEVACTB,
               sc->sc_devact[1]);
   
           return true;
 }  }
   
 int  int
Line 221  piixpm_i2c_acquire_bus(void *cookie, int
Line 273  piixpm_i2c_acquire_bus(void *cookie, int
         if (cold || sc->sc_poll || (flags & I2C_F_POLL))          if (cold || sc->sc_poll || (flags & I2C_F_POLL))
                 return (0);                  return (0);
   
         return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL));          rw_enter(&sc->sc_i2c_rwlock, RW_WRITER);
           return 0;
 }  }
   
 void  void
Line 232  piixpm_i2c_release_bus(void *cookie, int
Line 285  piixpm_i2c_release_bus(void *cookie, int
         if (cold || sc->sc_poll || (flags & I2C_F_POLL))          if (cold || sc->sc_poll || (flags & I2C_F_POLL))
                 return;                  return;
   
         lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL);          rw_exit(&sc->sc_i2c_rwlock);
 }  }
   
 int  int
Line 249  piixpm_i2c_exec(void *cookie, i2c_op_t o
Line 302  piixpm_i2c_exec(void *cookie, i2c_op_t o
   
         /* Wait for bus to be idle */          /* Wait for bus to be idle */
         for (retries = 100; retries > 0; retries--) {          for (retries = 100; retries > 0; retries--) {
                 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);                  st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                       PIIX_SMB_HS);
                 if (!(st & PIIX_SMB_HS_BUSY))                  if (!(st & PIIX_SMB_HS_BUSY))
                         break;                          break;
                 DELAY(PIIXPM_DELAY);                  DELAY(PIIXPM_DELAY);
         }          }
         DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,          DPRINTF(("%s: exec: st 0x%d\n", sc->sc_dev.dv_xname, st & 0xff));
             PIIX_SMB_HS_BITS));  
         if (st & PIIX_SMB_HS_BUSY)          if (st & PIIX_SMB_HS_BUSY)
                 return (1);                  return (1);
   
Line 273  piixpm_i2c_exec(void *cookie, i2c_op_t o
Line 326  piixpm_i2c_exec(void *cookie, i2c_op_t o
         sc->sc_i2c_xfer.error = 0;          sc->sc_i2c_xfer.error = 0;
   
         /* Set slave address and transfer direction */          /* Set slave address and transfer direction */
         bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_TXSLVA,          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_TXSLVA,
             PIIX_SMB_TXSLVA_ADDR(addr) |              PIIX_SMB_TXSLVA_ADDR(addr) |
             (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0));              (I2C_OP_READ_P(op) ? PIIX_SMB_TXSLVA_READ : 0));
   
         b = cmdbuf;          b = cmdbuf;
         if (cmdlen > 0)          if (cmdlen > 0)
                 /* Set command byte */                  /* Set command byte */
                 bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HCMD, b[0]);                  bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                       PIIX_SMB_HCMD, b[0]);
   
         if (I2C_OP_WRITE_P(op)) {          if (I2C_OP_WRITE_P(op)) {
                 /* Write data */                  /* Write data */
                 b = buf;                  b = buf;
                 if (len > 0)                  if (len > 0)
                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,                          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                             PIIX_SMB_HD0, b[0]);                              PIIX_SMB_HD0, b[0]);
                 if (len > 1)                  if (len > 1)
                         bus_space_write_1(sc->sc_iot, sc->sc_ioh,                          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                             PIIX_SMB_HD1, b[1]);                              PIIX_SMB_HD1, b[1]);
         }          }
   
Line 306  piixpm_i2c_exec(void *cookie, i2c_op_t o
Line 360  piixpm_i2c_exec(void *cookie, i2c_op_t o
   
         /* Start transaction */          /* Start transaction */
         ctl |= PIIX_SMB_HC_START;          ctl |= PIIX_SMB_HC_START;
         bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC, ctl);          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC, ctl);
   
         if (flags & I2C_F_POLL) {          if (flags & I2C_F_POLL) {
                 /* Poll for completion */                  /* Poll for completion */
                 DELAY(PIIXPM_DELAY);                  DELAY(PIIXPM_DELAY);
                 for (retries = 1000; retries > 0; retries--) {                  for (retries = 1000; retries > 0; retries--) {
                         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,                          st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                             PIIX_SMB_HS);                              PIIX_SMB_HS);
                         if ((st & PIIX_SMB_HS_BUSY) == 0)                          if ((st & PIIX_SMB_HS_BUSY) == 0)
                                 break;                                  break;
Line 337  timeout:
Line 391  timeout:
          * Transfer timeout. Kill the transaction and clear status bits.           * Transfer timeout. Kill the transaction and clear status bits.
          */           */
         aprint_error("%s: timeout, status 0x%x\n", sc->sc_dev.dv_xname, st);          aprint_error("%s: timeout, status 0x%x\n", sc->sc_dev.dv_xname, st);
         bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HC,          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HC,
             PIIX_SMB_HC_KILL);              PIIX_SMB_HC_KILL);
         DELAY(PIIXPM_DELAY);          DELAY(PIIXPM_DELAY);
         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);          st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS);
         if ((st & PIIX_SMB_HS_FAILED) == 0)          if ((st & PIIX_SMB_HS_FAILED) == 0)
                 aprint_error("%s: transaction abort failed, status 0x%x\n",                  aprint_error("%s: transaction abort failed, status 0x%x\n",
                     sc->sc_dev.dv_xname, st);                      sc->sc_dev.dv_xname, st);
         bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st);
         return (1);          return (1);
 }  }
   
Line 357  piixpm_intr(void *arg)
Line 411  piixpm_intr(void *arg)
         size_t len;          size_t len;
   
         /* Read status */          /* Read status */
         st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS);          st = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS);
         if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR |          if ((st & PIIX_SMB_HS_BUSY) != 0 || (st & (PIIX_SMB_HS_INTR |
             PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |              PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
             PIIX_SMB_HS_FAILED)) == 0)              PIIX_SMB_HS_FAILED)) == 0)
                 /* Interrupt was not for us */                  /* Interrupt was not for us */
                 return (0);                  return (0);
   
         DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,          DPRINTF(("%s: intr st 0x%d\n", sc->sc_dev.dv_xname, st & 0xff));
             PIIX_SMB_HS_BITS));  
   
         /* Clear status bits */          /* Clear status bits */
         bus_space_write_1(sc->sc_iot, sc->sc_ioh, PIIX_SMB_HS, st);          bus_space_write_1(sc->sc_smb_iot, sc->sc_smb_ioh, PIIX_SMB_HS, st);
   
         /* Check for errors */          /* Check for errors */
         if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |          if (st & (PIIX_SMB_HS_DEVERR | PIIX_SMB_HS_BUSERR |
Line 385  piixpm_intr(void *arg)
Line 438  piixpm_intr(void *arg)
                 b = sc->sc_i2c_xfer.buf;                  b = sc->sc_i2c_xfer.buf;
                 len = sc->sc_i2c_xfer.len;                  len = sc->sc_i2c_xfer.len;
                 if (len > 0)                  if (len > 0)
                         b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,                          b[0] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                             PIIX_SMB_HD0);                              PIIX_SMB_HD0);
                 if (len > 1)                  if (len > 1)
                         b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,                          b[1] = bus_space_read_1(sc->sc_smb_iot, sc->sc_smb_ioh,
                             PIIX_SMB_HD1);                              PIIX_SMB_HD1);
         }          }
   

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.3.2.6

CVSweb <webmaster@jp.NetBSD.org>