add support for the per-device power management capability.

int pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, int newstate)
	set power state of the device to newstate.
int pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
	get current power state of the device.

In the future, these functions will be used for ACPI support.
This commit is contained in:
tshiozak 2002-06-18 13:18:37 +00:00
parent 3c5f05720a
commit fe6f56bfb7
3 changed files with 101 additions and 5 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: pci.c,v 1.65 2002/05/18 21:40:41 sommerfeld Exp $ */
/* $NetBSD: pci.c,v 1.66 2002/06/18 13:18:37 tshiozak Exp $ */
/*
* Copyright (c) 1995, 1996, 1997, 1998
@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.65 2002/05/18 21:40:41 sommerfeld Exp $");
__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.66 2002/06/18 13:18:37 tshiozak Exp $");
#include "opt_pci.h"
@ -448,3 +448,82 @@ pci_enumerate_bus_generic(struct pci_softc *sc,
}
return (0);
}
/*
* Power Management Capability (Rev 2.2)
*/
int
pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, int newstate)
{
int offset;
pcireg_t value, cap, now;
if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value))
return (EOPNOTSUPP);
cap = value >> 16;
value = pci_conf_read(pc, tag, offset+PCI_PMCSR);
now = value & PCI_PMCSR_STATE_MASK;
value &= ~PCI_PMCSR_STATE_MASK;
switch (newstate) {
case PCI_PWR_D0:
if (now == PCI_PMCSR_STATE_D0)
return (0);
value |= PCI_PMCSR_STATE_D0;
break;
case PCI_PWR_D1:
if (now == PCI_PMCSR_STATE_D1)
return (0);
if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3)
return (EINVAL);
if (!(cap & PCI_PMCR_D1SUPP))
return (EOPNOTSUPP);
value |= PCI_PMCSR_STATE_D1;
break;
case PCI_PWR_D2:
if (now == PCI_PMCSR_STATE_D2)
return (0);
if (now == PCI_PMCSR_STATE_D3)
return (EINVAL);
if (!(cap & PCI_PMCR_D2SUPP))
return (EOPNOTSUPP);
value |= PCI_PMCSR_STATE_D2;
break;
case PCI_PWR_D3:
if (now == PCI_PMCSR_STATE_D3)
return (0);
value |= PCI_PMCSR_STATE_D3;
break;
default:
return (EINVAL);
}
pci_conf_write(pc, tag, offset+PCI_PMCSR, value);
DELAY(1000);
return (0);
}
int
pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag)
{
int offset;
pcireg_t value;
if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value))
return (PCI_PWR_D0);
value = pci_conf_read(pc, tag, offset+PCI_PMCSR);
value &= PCI_PMCSR_STATE_MASK;
switch (value) {
case PCI_PMCSR_STATE_D0:
return (PCI_PWR_D0);
case PCI_PMCSR_STATE_D1:
return (PCI_PWR_D1);
case PCI_PMCSR_STATE_D2:
return (PCI_PWR_D2);
case PCI_PMCSR_STATE_D3:
return (PCI_PWR_D3);
}
return (PCI_PWR_D0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcireg.h,v 1.37 2002/03/22 20:03:20 drochner Exp $ */
/* $NetBSD: pcireg.h,v 1.38 2002/06/18 13:18:37 tshiozak Exp $ */
/*
* Copyright (c) 1995, 1996, 1999, 2000
@ -418,9 +418,15 @@ typedef u_int8_t pci_revision_t;
#define PCI_CAP_HOTPLUG 0x0c
/*
* Power Management Control Status Register; access via capability pointer.
* Power Management Capability; access via capability pointer.
*/
/* Power Management Capability Register */
#define PCI_PMCR 0x02
#define PCI_PMCR_D1SUPP 0x0200
#define PCI_PMCR_D2SUPP 0x0400
/* Power Management Control Status Register */
#define PCI_PMCSR 0x04
#define PCI_PMCSR_STATE_MASK 0x03
#define PCI_PMCSR_STATE_D0 0x00
#define PCI_PMCSR_STATE_D1 0x01

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcivar.h,v 1.52 2002/05/30 12:06:43 drochner Exp $ */
/* $NetBSD: pcivar.h,v 1.53 2002/06/18 13:18:37 tshiozak Exp $ */
/*
* Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
@ -209,6 +209,17 @@ struct proc;
int pci_devioctl __P((pci_chipset_tag_t, pcitag_t, u_long, caddr_t,
int flag, struct proc *));
/*
* Power Management (PCI 2.2)
*/
#define PCI_PWR_D0 0
#define PCI_PWR_D1 1
#define PCI_PWR_D2 2
#define PCI_PWR_D3 3
int pci_set_powerstate __P((pci_chipset_tag_t, pcitag_t, int));
int pci_get_powerstate __P((pci_chipset_tag_t, pcitag_t));
/*
* Misc.
*/