diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/acpi_machdep.c | 154 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/machdep.c | 16 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/mainbus.c | 24 | ||||
-rw-r--r-- | sys/arch/amd64/conf/GENERIC | 9 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 8 | ||||
-rw-r--r-- | sys/arch/amd64/include/conf.h | 9 | ||||
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 9 | ||||
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 5 | ||||
-rw-r--r-- | sys/arch/i386/i386/acpi_machdep.c | 175 | ||||
-rw-r--r-- | sys/arch/i386/i386/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/i386/i386/mainbus.c | 21 | ||||
-rw-r--r-- | sys/arch/i386/include/conf.h | 10 | ||||
-rw-r--r-- | sys/dev/acpi/acpi.c | 597 | ||||
-rw-r--r-- | sys/dev/acpi/acpireg.h | 428 | ||||
-rw-r--r-- | sys/dev/acpi/acpitimer.c | 152 | ||||
-rw-r--r-- | sys/dev/acpi/acpiutil.c | 42 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 111 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 20 | ||||
-rw-r--r-- | sys/dev/acpi/hpet.c | 144 | ||||
-rw-r--r-- | sys/dev/acpi/hpetreg.h | 32 |
21 files changed, 1957 insertions, 17 deletions
diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c new file mode 100644 index 00000000000..c9596fe5368 --- /dev/null +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -0,0 +1,154 @@ +/* $OpenBSD: acpi_machdep.c,v 1.1 2005/06/02 20:09:38 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <machine/biosvar.h> + +#include <dev/isa/isareg.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +#define ACPI_BIOS_RSDP_WINDOW_BASE 0xe0000 +#define ACPI_BIOS_RSDP_WINDOW_SIZE 0x20000 + +u_int8_t *acpi_scan(struct acpi_mem_map *, paddr_t, size_t); + +int +acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle) +{ + paddr_t pgpa = x86_trunc_page(pa); + paddr_t endpa = x86_round_page(pa + len); + vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa); + + if (va == 0) + return (ENOMEM); + + handle->baseva = va; + handle->va = (u_int8_t *)(va + (pa & PGOFSET)); + handle->vsize = endpa - pgpa; + handle->pa = pa; + + do { + pmap_kenter_pa(va, pgpa, VM_PROT_READ); + va += NBPG; + pgpa += NBPG; + } while (pgpa < endpa); + + return 0; +} + +void +acpi_unmap(struct acpi_mem_map *handle) +{ + pmap_kremove(handle->baseva, handle->vsize); + uvm_km_free(kernel_map, handle->baseva, handle->vsize); +} + +u_int8_t * +acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) +{ + size_t i; + u_int8_t *ptr; + struct acpi_rsdp1 *rsdp; + + if (acpi_map(pa, len, handle)) + return (NULL); + for (ptr = handle->va, i = 0; + i < len; + ptr += 16, i += 16) + if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0) { + rsdp = (struct acpi_rsdp1 *)ptr; + /* + * Only checksum whichever portion of the + * RSDP that is actually present + */ + if (rsdp->revision == 0 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) == 0) + return (ptr); + else if (rsdp->revision == 2 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) + return (ptr); + } + acpi_unmap(handle); + + return (NULL); +} + +int +acpi_probe(struct device *parent, struct cfdata *match, struct acpi_attach_args *aaa) +{ + struct acpi_mem_map handle; + u_int8_t *ptr; + paddr_t ebda; + bios_memmap_t *im; + + /* + * First look for ACPI entries in the BIOS memory map + */ + for (im = bios_memmap; im->type != BIOS_MAP_END; im++) + if (im->type == BIOS_MAP_ACPI) { + if ((ptr = acpi_scan(&handle, im->addr, im->size))) + goto havebase; + } + + /* + * Next try to find ACPI table entries in the EBDA + */ + if (acpi_map(0, NBPG, &handle)) + printf("acpi: failed to map BIOS data area\n"); + else { + ebda = *(const u_int16_t *)(&handle.va[0x40e]); + ebda <<= 4; + acpi_unmap(&handle); + + if (ebda && ebda < IOM_BEGIN) { + if ((ptr = acpi_scan(&handle, ebda, 1024))) + goto havebase; + } + } + + /* + * Finally try to find the ACPI table entries in the + * BIOS memory + */ + if ((ptr = acpi_scan(&handle, ACPI_BIOS_RSDP_WINDOW_BASE, + ACPI_BIOS_RSDP_WINDOW_SIZE))) + goto havebase; + + return (0); + +havebase: + aaa->aaa_pbase = ptr - handle.va + handle.pa; + acpi_unmap(&handle); + + return (1); +} + +void +acpi_attach_machdep(struct acpi_softc *sc) +{ + sc->sc_interrupt = intr_establish(sc->sc_fadt->sci_int, &i8259_pic, sc->sc_fadt->sci_int, + IST_LEVEL, IPL_TTY, acpi_interrupt, sc, "acpi"); +} diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c index ffa6fb787c9..d2fa2a4e57d 100644 --- a/sys/arch/amd64/amd64/conf.c +++ b/sys/arch/amd64/amd64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.6 2004/05/30 08:11:26 grange Exp $ */ +/* $OpenBSD: conf.c,v 1.7 2005/06/02 20:09:38 tholo Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -159,6 +159,7 @@ cdev_decl(mcd); #include "midi.h" #include "sequencer.h" cdev_decl(music); +#include "acpi.h" #include "iop.h" #ifdef XFS #include <xfs/nxfs.h> @@ -297,6 +298,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 80: gpr? XXX */ cdev_ptm_init(NPTY,ptm), /* 81: pseudo-tty ptm device */ cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ + cdev_acpi_init(NACPI,acpi), /* 83: ACPI */ }; int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 7ce605412d7..cdd4ffa0843 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.30 2004/08/03 00:56:22 art Exp $ */ +/* $OpenBSD: machdep.c,v 1.31 2005/06/02 20:09:38 tholo Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -131,16 +131,22 @@ #include <dev/isa/isareg.h> #include <machine/isa_machdep.h> #include <dev/ic/i8042reg.h> +#include <dev/acpi/acpivar.h> #ifdef DDB #include <machine/db_machdep.h> #include <ddb/db_extern.h> #endif +#include "acpi.h" #include "isa.h" #include "isadma.h" #include "ksyms.h" +#if NACPI > 0 +extern struct acpi_softc *acpi_softc; +#endif + /* the following is used externally (sysctl_hw) */ char machine[] = "amd64"; /* cpu "architecture" */ char machine_arch[] = "amd64"; /* machine == machine_arch */ @@ -893,9 +899,11 @@ haltsys: if (howto & RB_HALT) { if (howto & RB_POWERDOWN) { #if NACPI > 0 - delay(500000); - acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); - printf("WARNING: powerdown failed!\n"); + if (acpi_softc) { + delay(500000); + acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); + printf("WARNING: powerdown failed!\n"); + } #endif } diff --git a/sys/arch/amd64/amd64/mainbus.c b/sys/arch/amd64/amd64/mainbus.c index e4c5e6d32fd..8625cb64de5 100644 --- a/sys/arch/amd64/amd64/mainbus.c +++ b/sys/arch/amd64/amd64/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: mainbus.c,v 1.2 2005/06/02 20:09:38 tholo Exp $ */ /* $NetBSD: mainbus.c,v 1.1 2003/04/26 18:39:29 fvdl Exp $ */ /* @@ -44,14 +44,16 @@ #include "pci.h" #include "isa.h" +#include "acpi.h" #include <machine/cpuvar.h> #include <machine/i82093var.h> #include <machine/mpbiosvar.h> -/* - * XXXfvdl ACPI - */ +#if NACPI > 0 +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#endif int mainbus_match(struct device *, void *, void *); void mainbus_attach(struct device *, struct device *, void *); @@ -72,6 +74,9 @@ union mainbus_attach_args { struct isabus_attach_args mba_iba; struct cpu_attach_args mba_caa; struct apic_attach_args aaa_caa; +#if NACPI > 0 + struct acpi_attach_args mba_aaa; +#endif }; /* @@ -131,6 +136,17 @@ mainbus_attach(parent, self, aux) printf("\n"); +#if NACPI > 0 + { + memset(&mba.mba_aaa, 0, sizeof(mba.mba_aaa)); + mba.mba_aaa.aaa_name = "acpi"; + mba.mba_aaa.aaa_iot = X86_BUS_SPACE_IO; + mba.mba_aaa.aaa_memt = X86_BUS_SPACE_MEM; + + config_found(self, &mba.mba_aaa, mainbus_print); + } +#endif + #ifdef MPBIOS mpbios_present = mpbios_probe(self); #endif diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index c213f546627..8d9be42b133 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.70 2005/05/27 06:36:23 jason Exp $ +# $OpenBSD: GENERIC,v 1.71 2005/06/02 20:09:39 tholo Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -41,6 +41,13 @@ isa0 at mainbus0 #isa0 at pcib? pci* at mainbus0 +#acpi0 at mainbus? +#acpitimer* at acpi? +#hpet* at acpi? + +#option ACPIVERBOSE +#option ACPI_ENABLE + option PCIVERBOSE option USBVERBOSE diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index e77341ac1b3..f45e713e16f 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.11 2005/05/27 06:28:41 jason Exp $ +# $OpenBSD: files.amd64,v 1.12 2005/06/02 20:09:39 tholo Exp $ maxpartitions 16 maxusers 2 16 128 @@ -142,6 +142,12 @@ file dev/isa/fd.c fd needs-flag include "dev/usb/files.usb" # +# ACPI +# +include "../../../dev/acpi/files.acpi" +file arch/amd64/amd64/acpi_machdep.c acpi + +# # device major numbers # diff --git a/sys/arch/amd64/include/conf.h b/sys/arch/amd64/include/conf.h index 0eeee30a029..688c8eda04d 100644 --- a/sys/arch/amd64/include/conf.h +++ b/sys/arch/amd64/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: conf.h,v 1.2 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */ /* @@ -43,3 +43,10 @@ cdev_decl(spkr); #define biosselect seltrue cdev_decl(bios); + +#define cdev_acpi_init(c,n) {\ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +cdev_decl(acpi); diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 42a9a622555..43c2cca9c6e 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.416 2005/05/27 02:08:14 martin Exp $ +# $OpenBSD: GENERIC,v 1.417 2005/06/02 20:09:39 tholo Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -56,6 +56,13 @@ isa0 at gscpcib? eisa0 at mainbus0 pci* at mainbus0 +#acpi0 at mainbus? +#acpitimer* at acpi? +#hpet* at acpi? + +option ACPIVERBOSE +#option ACPI_ENABLE + option PCIVERBOSE option EISAVERBOSE option USBVERBOSE diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index c92ad29ca6c..a61bfa4fbf7 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.134 2005/05/21 19:13:55 brad Exp $ +# $OpenBSD: files.i386,v 1.135 2005/06/02 20:09:39 tholo Exp $ # # new style config file for i386 architecture # @@ -396,3 +396,6 @@ include "dev/i2c/files.i2c" # Machine-independent GPIO drivers # include "dev/gpio/files.gpio" + +include "../../../dev/acpi/files.acpi" +file arch/i386/i386/acpi_machdep.c acpi diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c new file mode 100644 index 00000000000..51f674c2cd0 --- /dev/null +++ b/sys/arch/i386/i386/acpi_machdep.c @@ -0,0 +1,175 @@ +/* $OpenBSD: acpi_machdep.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <i386/isa/isa_machdep.h> + +#include <dev/isa/isareg.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +#include "bios.h" +#include "apm.h" + +#if NBIOS > 0 +#include <machine/biosvar.h> +#endif + +#define ACPI_BIOS_RSDP_WINDOW_BASE 0xe0000 +#define ACPI_BIOS_RSDP_WINDOW_SIZE 0x20000 + +#if NAPM > 0 && NBIOS > 0 +extern bios_apminfo_t *apm; +#endif + +u_int8_t *acpi_scan(struct acpi_mem_map *, paddr_t, size_t); + +int +acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle) +{ + paddr_t pgpa = i386_trunc_page(pa); + paddr_t endpa = i386_round_page(pa + len); + vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa); + + if (va == 0) + return (ENOMEM); + + handle->baseva = va; + handle->va = (u_int8_t *)(va + (pa & PGOFSET)); + handle->vsize = endpa - pgpa; + handle->pa = pa; + + do { + pmap_kenter_pa(va, pgpa, VM_PROT_READ); + va += NBPG; + pgpa += NBPG; + } while (pgpa < endpa); + + return 0; +} + +void +acpi_unmap(struct acpi_mem_map *handle) +{ + pmap_kremove(handle->baseva, handle->vsize); + uvm_km_free(kernel_map, handle->baseva, handle->vsize); +} + +u_int8_t * +acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) +{ + size_t i; + u_int8_t *ptr; + struct acpi_rsdp1 *rsdp; + + if (acpi_map(pa, len, handle)) + return (NULL); + for (ptr = handle->va, i = 0; + i < len; + ptr += 16, i += 16) + if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0) { + rsdp = (struct acpi_rsdp1 *)ptr; + /* + * Only checksum whichever portion of the + * RSDP that is actually present + */ + if (rsdp->revision == 0 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) == 0) + return (ptr); + else if (rsdp->revision == 2 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) + return (ptr); + } + acpi_unmap(handle); + + return (NULL); +} + +int +acpi_probe(struct device *parent, struct cfdata *match, struct acpi_attach_args *aaa) +{ + struct acpi_mem_map handle; + u_int8_t *ptr; + paddr_t ebda; +#if NBIOS > 0 + bios_memmap_t *im; + + /* + * First look for ACPI entries in the BIOS memory map + */ + for (im = bios_memmap; im->type != BIOS_MAP_END; im++) + if (im->type == BIOS_MAP_ACPI) { + if ((ptr = acpi_scan(&handle, im->addr, im->size))) + goto havebase; + } +#endif + + /* + * Next try to find ACPI table entries in the EBDA + */ + if (acpi_map(0, NBPG, &handle)) + printf("acpi: failed to map BIOS data area\n"); + else { + ebda = *(const u_int16_t *)(&handle.va[0x40e]); + ebda <<= 4; + acpi_unmap(&handle); + + if (ebda && ebda < IOM_BEGIN) { + if ((ptr = acpi_scan(&handle, ebda, 1024))) + goto havebase; + } + } + + /* + * Finally try to find the ACPI table entries in the + * BIOS memory + */ + if ((ptr = acpi_scan(&handle, ACPI_BIOS_RSDP_WINDOW_BASE, + ACPI_BIOS_RSDP_WINDOW_SIZE))) + goto havebase; + + return (0); + +havebase: + aaa->aaa_pbase = ptr - handle.va + handle.pa; + acpi_unmap(&handle); + +#ifdef notyet + /* + * Disable APM if we are using ACPI + */ +#if NAPM > 0 && NBIOS > 0 + apm = NULL; +#endif +#endif + return (1); +} + +void +acpi_attach_machdep(struct acpi_softc *sc) +{ + sc->sc_interrupt = isa_intr_establish(NULL, sc->sc_fadt->sci_int, IST_LEVEL, + IPL_TTY, acpi_interrupt, sc, "acpi"); +} diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c index 38072585d96..8a5ead04876 100644 --- a/sys/arch/i386/i386/conf.c +++ b/sys/arch/i386/i386/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.109 2004/10/03 21:28:34 jcs Exp $ */ +/* $OpenBSD: conf.c,v 1.110 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */ /* @@ -168,6 +168,7 @@ cdev_decl(mcd); #include "sequencer.h" cdev_decl(music); #include "joy.h" +#include "acpi.h" #include "apm.h" #include "pctr.h" #include "bios.h" @@ -324,6 +325,7 @@ struct cdevsw cdevsw[] = cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ cdev_gpio_init(NGPIO,gpio), /* 83: GPIO interface */ cdev_nvram_init(NNVRAM,nvram), /* 84: NVRAM interface */ + cdev_acpi_init(NACPI,acpi), /* 85: ACPI */ }; int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c index c242f14e5da..053a78ee8d5 100644 --- a/sys/arch/i386/i386/mainbus.c +++ b/sys/arch/i386/i386/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.16 2004/06/13 21:49:15 niklas Exp $ */ +/* $OpenBSD: mainbus.c,v 1.17 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: mainbus.c,v 1.21 1997/06/06 23:14:20 thorpej Exp $ */ /* @@ -50,6 +50,7 @@ #include "apm.h" #include "bios.h" #include "mpbios.h" +#include "acpi.h" #include <machine/cpuvar.h> #include <machine/i82093var.h> @@ -59,6 +60,11 @@ #include <machine/biosvar.h> #endif +#if NACPI > 0 +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#endif + #if 0 #ifdef SMP /* XXX MULTIPROCESSOR */ #include <machine/mp.h> @@ -88,6 +94,9 @@ union mainbus_attach_args { #endif struct cpu_attach_args mba_caa; struct apic_attach_args aaa_caa; +#if NACPI > 0 + struct acpi_attach_args mba_aaa; +#endif }; /* @@ -121,6 +130,16 @@ mainbus_attach(parent, self, aux) printf("\n"); +#if NACPI > 0 + { + memset(&mba.mba_aaa, 0, sizeof(mba.mba_aaa)); + mba.mba_aaa.aaa_name = "acpi"; + mba.mba_aaa.aaa_iot = I386_BUS_SPACE_IO; + mba.mba_aaa.aaa_memt = I386_BUS_SPACE_MEM; + + config_found(self, &mba.mba_aaa, mainbus_print); + } +#endif #if NBIOS > 0 { mba.mba_bios.bios_dev = "bios"; diff --git a/sys/arch/i386/include/conf.h b/sys/arch/i386/include/conf.h index 82a4f670620..33276008ce1 100644 --- a/sys/arch/i386/include/conf.h +++ b/sys/arch/i386/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.10 2003/09/23 16:51:11 millert Exp $ */ +/* $OpenBSD: conf.h,v 1.11 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */ /* @@ -55,6 +55,12 @@ cdev_decl(pc); (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +#define cdev_acpi_init(c,n) {\ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } + cdev_decl(spkr); cdev_decl(mms); @@ -68,6 +74,8 @@ cdev_decl(joy); #define biospoll seltrue cdev_decl(bios); +cdev_decl(acpi); + cdev_decl(apm); #define pctrpoll seltrue diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c new file mode 100644 index 00000000000..77cdcc04ec1 --- /dev/null +++ b/sys/dev/acpi/acpi.c @@ -0,0 +1,597 @@ +/* $OpenBSD: acpi.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/fcntl.h> +#include <sys/ioccom.h> +#include <sys/event.h> + +#include <machine/conf.h> +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +int acpimatch(struct device *, void *, void *); +void acpiattach(struct device *, struct device *, void *); +int acpi_submatch(struct device *, void *, void *); +int acpi_print(void *, const char *); +int acpi_loadtables(struct acpi_softc *, struct acpi_rsdp *); +void acpi_load_table(paddr_t, size_t, acpi_qhead_t *); +void acpi_load_dsdt(paddr_t, struct acpi_q **); +void acpi_softintr(void *); +void acpi_filtdetach(struct knote *); +int acpi_filtread(struct knote *, long); + +#define ACPI_LOCK(sc) +#define ACPI_UNLOCK(sc) + +struct filterops acpiread_filtops = { + 1, NULL, acpi_filtdetach, acpi_filtread +}; + +struct cfattach acpi_ca = { + sizeof(struct acpi_softc), acpimatch, acpiattach +}; + +struct cfdriver acpi_cd = { + NULL, "acpi", DV_DULL +}; + +int acpi_evindex; +struct acpi_softc *acpi_softc; + +int +acpimatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + /* sanity */ + if (strcmp(aaa->aaa_name, cf->cf_driver->cd_name)) + return (0); + + if (!acpi_probe(parent, cf, aaa)) + return (0); + + return (1); +} + +void +acpiattach(struct device *parent, struct device *self, void *aux) +{ +#ifdef ACPI_ENABLE + bus_space_handle_t ioh; +#endif + struct acpi_attach_args *aaa = aux; + struct acpi_softc *sc = (struct acpi_softc *)self; + struct acpi_mem_map handle; + struct acpi_rsdp *rsdp; + struct acpi_q *entry; + paddr_t facspa; + + sc->sc_iot = aaa->aaa_iot; + sc->sc_memt = aaa->aaa_memt; + + printf(": "); + if (acpi_map(aaa->aaa_pbase, sizeof(struct acpi_rsdp), &handle)) + goto fail; + + rsdp = (struct acpi_rsdp *)handle.va; + printf("revision %d ", (int)rsdp->rsdp_revision); + + SIMPLEQ_INIT(&sc->sc_tables); + + sc->sc_fadt = NULL; + sc->sc_facs = NULL; + sc->sc_powerbtn = 0; + sc->sc_sleepbtn = 0; + + sc->sc_note = malloc(sizeof(struct klist), M_DEVBUF, M_NOWAIT); + memset(sc->sc_note, 0, sizeof(struct klist)); + + if (acpi_loadtables(sc, rsdp)) { + acpi_unmap(&handle); + return; + } + + acpi_unmap(&handle); + + /* + * Find the FADT + */ + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + if (memcmp(entry->q_table, FADT_SIG, sizeof(FADT_SIG) - 1) == 0) { + sc->sc_fadt = entry->q_table; + break; + } + } + if (sc->sc_fadt == NULL) + goto fail; + + /* + * Check if we are able to enable ACPI control + */ + if (!sc->sc_fadt->smi_cmd || + (!sc->sc_fadt->acpi_enable && !sc->sc_fadt->acpi_disable)) + goto fail; + + /* + * Load the DSDT from the FADT pointer -- use the + * extended (64-bit) pointer if it exists + */ + if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_dsdt == 0) + acpi_load_dsdt(sc->sc_fadt->dsdt, &entry); + else + acpi_load_dsdt(sc->sc_fadt->x_dsdt, &entry); + + if (entry == NULL) + printf("!DSDT "); + SIMPLEQ_INSERT_HEAD(&sc->sc_tables, entry, q_next); + + /* + * Set up a pointer to the firmware control structure + */ + if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_firmware_ctl == 0) + facspa = sc->sc_fadt->firmware_ctl; + else + facspa = sc->sc_fadt->x_firmware_ctl; + + if (acpi_map(facspa, sizeof(struct acpi_facs), &handle)) + printf("!FACS "); + else + sc->sc_facs = (struct acpi_facs *)handle.va; + + /* + * Take over ACPI control. Note that once we do this, we + * effectively tell the system that we have ownership of + * the ACPI hardware registers, and that SMI should leave + * them alone + * + * This may prevent thermal control on some systems where + * that actually does work + */ +#ifdef ACPI_ENABLE + bus_space_map(sc->sc_iot, sc->sc_fadt->smi_cmd, 1, 0, &ioh); + bus_space_write_1(sc->sc_iot, ioh, 0, sc->sc_fadt->acpi_enable); + bus_space_unmap(sc->sc_iot, ioh, 1); +#endif + + bus_space_map(sc->sc_iot, + sc->sc_fadt->pm1a_evt_blk, sc->sc_fadt->pm1_evt_len, + 0, &sc->sc_ioh_pm1a_evt); + +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + sc->sc_softih = softintr_establish(IPL_TTY, acpi_softintr, sc); +#else + timeout_set(&sc->sc_timeout, acpi_softintr, sc); +#endif + acpi_attach_machdep(sc); + + /* + * If we have an interrupt handler, we can get notification + * when certain status bits changes in the ACPI registers, + * so let us enable some events we can forward to userland + */ + if (sc->sc_interrupt) { + int16_t flags; + + flags = bus_space_read_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + sc->sc_fadt->pm1_evt_len / 2); + flags |= ACPI_PM1_PWRBTN_EN | ACPI_PM1_SLPBTN_EN; + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + sc->sc_fadt->pm1_evt_len / 2, flags); + } + + printf("attached\n"); + + /* + * ACPI is enabled now -- attach timer + */ + { + struct acpi_attach_args aaa; + + memset(&aaa, 0, sizeof(aaa)); + aaa.aaa_name = "acpitimer"; + aaa.aaa_iot = sc->sc_iot; + aaa.aaa_memt = sc->sc_memt; +#if 0 + aaa.aaa_pcit = sc->sc_pcit; + aaa.aaa_smbust = sc->sc_smbust; +#endif + config_found(self, &aaa, acpi_print); + } + + /* + * Attach table-defined devices + */ + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + struct acpi_attach_args aaa; + + memset(&aaa, 0, sizeof(aaa)); + aaa.aaa_iot = sc->sc_iot; + aaa.aaa_memt = sc->sc_memt; +#if 0 + aaa.aaa_pcit = sc->sc_pcit; + aaa.aaa_smbust = sc->sc_smbust; +#endif + aaa.aaa_table = entry->q_table; + + config_found_sm(self, &aaa, acpi_print, acpi_submatch); + } + + acpi_softc = sc; + + return; + +fail: + printf(" failed attach\n"); +} + +int +acpi_submatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = (struct acpi_attach_args *)aux; + struct cfdata *cf = match; + + if (aaa->aaa_table == NULL) + return (0); + return ((*cf->cf_attach->ca_match)(parent, match, aux)); +} + +int +acpi_print(void *aux, const char *pnp) +{ + struct acpi_attach_args *aa = aux; +#ifdef ACPIVERBOSE + struct acpi_table_header *hdr = (struct acpi_table_header *)aa->aaa_table; +#endif + + if (pnp) { + if (aa->aaa_name) + printf("%s at %s", aa->aaa_name, pnp); +#ifdef ACPIVERBOSE + else + printf("acpi device at %s from", pnp); +#endif + } +#ifdef ACPIVERBOSE + if (hdr) + printf(" table %c%c%c%c", + hdr->signature[0], hdr->signature[1], + hdr->signature[2], hdr->signature[3]); +#endif + + return (UNCONF); +} + +int +acpi_loadtables(struct acpi_softc *sc, struct acpi_rsdp *rsdp) +{ + struct acpi_mem_map hrsdt, handle; + struct acpi_table_header *hdr; + int i, ntables; + size_t len; + + if (rsdp->rsdp_revision == 2) { + struct acpi_xsdt *xsdt; + + if (acpi_map(rsdp->rsdp_xsdt, sizeof(*hdr), &handle)) { + printf("couldn't map rsdt\n"); + return (ENOMEM); + } + + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + hdr = NULL; + + acpi_map(rsdp->rsdp_xsdt, len, &hrsdt); + xsdt = (struct acpi_xsdt *)hrsdt.va; + + ntables = (len - sizeof(struct acpi_table_header)) / + sizeof(xsdt->table_offsets[0]); + + for (i = 0; i < ntables; i++) { + acpi_map(xsdt->table_offsets[i], sizeof(*hdr), &handle); + hdr = (struct acpi_table_header *)handle.va; + acpi_load_table(xsdt->table_offsets[i], hdr->length, &sc->sc_tables); + acpi_unmap(&handle); + } + acpi_unmap(&hrsdt); + } + else { + struct acpi_rsdt *rsdt; + + if (acpi_map(rsdp->rsdp_rsdt, sizeof(*hdr), &handle)) { + printf("couldn't map rsdt\n"); + return (ENOMEM); + } + + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + hdr = NULL; + + acpi_map(rsdp->rsdp_rsdt, len, &hrsdt); + rsdt = (struct acpi_rsdt *)hrsdt.va; + + ntables = (len - sizeof(struct acpi_table_header)) / + sizeof(rsdt->table_offsets[0]); + + for (i = 0; i < ntables; i++) { + acpi_map(rsdt->table_offsets[i], sizeof(*hdr), &handle); + hdr = (struct acpi_table_header *)handle.va; + acpi_load_table(rsdt->table_offsets[i], hdr->length, &sc->sc_tables); + acpi_unmap(&handle); + } + acpi_unmap(&hrsdt); + } + + return (0); +} + +void +acpi_load_table(paddr_t pa, size_t len, acpi_qhead_t *queue) +{ + struct acpi_mem_map handle; + struct acpi_q *entry; + + entry = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); + + if (entry != NULL) { + if (acpi_map(pa, len, &handle)) { + free(entry, M_DEVBUF); + return; + } + memcpy(entry->q_data, handle.va, len); + entry->q_table = entry->q_data; + acpi_unmap(&handle); + SIMPLEQ_INSERT_TAIL(queue, entry, q_next); + } +} + +void +acpi_load_dsdt(paddr_t pa, struct acpi_q **dsdt) +{ + struct acpi_mem_map handle; + struct acpi_table_header *hdr; + size_t len; + + if (acpi_map(pa, sizeof(*hdr), &handle)) + return; + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + + *dsdt = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); + + if (*dsdt != NULL) { + if (acpi_map(pa, len, &handle)) { + free(*dsdt, M_DEVBUF); + *dsdt = NULL; + return; + } + memcpy((*dsdt)->q_data, handle.va, len); + (*dsdt)->q_table = (*dsdt)->q_data; + acpi_unmap(&handle); + } +} + +int +acpi_interrupt(void *arg) +{ + struct acpi_softc *sc = (struct acpi_softc *)arg; + u_int16_t flags; + + flags = bus_space_read_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, ACPI_PM1_STATUS); + if (flags & (ACPI_PM1_PWRBTN_STS | ACPI_PM1_SLPBTN_STS)) { + if (flags & ACPI_PM1_PWRBTN_STS) { + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + ACPI_PM1_STATUS, ACPI_PM1_PWRBTN_STS); + /* + * Power-button has been pressed, do something! + */ + sc->sc_powerbtn = 1; + } + if (flags & ACPI_PM1_SLPBTN_STS) { + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + ACPI_PM1_STATUS, ACPI_PM1_SLPBTN_STS); + /* + * Sleep-button has been pressed, do something! + */ + sc->sc_sleepbtn = 1; + } +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + softintr_schedule(sc->sc_softih); +#else + if (!timeout_pending(&sc->sc_timeout)) + timeout_add(&sc->sc_timeout, 0); +#endif + return (1); + } + return (0); +} + +void +acpi_softintr(void *arg) +{ + struct acpi_softc *sc = arg; + + if (sc->sc_powerbtn) { + sc->sc_powerbtn = 0; + acpi_evindex++; + KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_PWRBTN, acpi_evindex)); + } + if (sc->sc_sleepbtn) { + sc->sc_sleepbtn = 0; + acpi_evindex++; + KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_SLPBTN, acpi_evindex)); + } +} + +int +acpiopen(dev_t dev, int flag, int mode, struct proc *p) +{ + struct acpi_softc *sc; + int error = 0; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + if (!(flag & FREAD) || (flag & FWRITE)) + error = EINVAL; + + return (error); +} + +void +acpi_enter_sleep_state(struct acpi_softc *sc, int state) +{ +#ifdef ACPI_ENABLE + bus_space_handle_t ioh; + u_int16_t bits; + + bus_space_map(sc->sc_iot, + sc->sc_fadt->pm1a_cnt_blk, sc->sc_fadt->pm1_cnt_len, + 0, &ioh); + bits = bus_space_read_2(sc->sc_iot, ioh, 0); + bits |= state << 10; /* XXX This is sick and wrong and illegal! */ + bus_space_write_2(sc->sc_iot, ioh, 0, bits); + bits |= ACPI_PM1_SLP_EN; + bus_space_write_2(sc->sc_iot, ioh, 0, bits); + bus_space_unmap(sc->sc_iot, ioh, sc->sc_fadt->pm1_cnt_len); +#endif +} + +int +acpiclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct acpi_softc *sc; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + return (0); +} + +int +acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct acpi_softc *sc; + int error = 0; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + ACPI_LOCK(sc); + switch (cmd) { + case ACPI_IOC_GETFACS: + if (suser(p, 0) != 0) + error = EPERM; + else { + struct acpi_facs *facs = (struct acpi_facs *)data; + + bcopy(sc->sc_facs, facs, sc->sc_facs->length); + } + break; + + case ACPI_IOC_GETTABLE: + if (suser(p, 0) != 0) + error = EPERM; + else { + struct acpi_table *table = (struct acpi_table *)data; + struct acpi_table_header *hdr; + struct acpi_q *entry; + + error = ENOENT; + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + if (table->offset-- == 0) { + hdr = (struct acpi_table_header *)entry->q_table; + if (table->table == NULL) { + table->size = hdr->length; + error = 0; + } + else if (hdr->length > table->size) + error = ENOSPC; + else + error = copyout(hdr, table->table, hdr->length); + break; + } + } + } + break; + + default: + error = ENOTTY; + } + + ACPI_UNLOCK(sc); + return (error); +} + +void +acpi_filtdetach(struct knote *kn) +{ + struct acpi_softc *sc = kn->kn_hook; + + ACPI_LOCK(sc); + SLIST_REMOVE(sc->sc_note, kn, knote, kn_selnext); + ACPI_UNLOCK(sc); +} + +int +acpi_filtread(struct knote *kn, long hint) +{ + /* XXX weird kqueue_scan() semantics */ + if (hint & !kn->kn_data) + kn->kn_data = hint; + + return(1); +} + +int +acpikqfilter(dev_t dev, struct knote *kn) +{ + struct acpi_softc *sc; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &acpiread_filtops; + break; + default: + return (1); + } + + kn->kn_hook = sc; + + ACPI_LOCK(sc); + SLIST_INSERT_HEAD(sc->sc_note, kn, kn_selnext); + ACPI_UNLOCK(sc); + + return (0); +} diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h new file mode 100644 index 00000000000..9b3c965ffe8 --- /dev/null +++ b/sys/dev/acpi/acpireg.h @@ -0,0 +1,428 @@ +/* $OpenBSD: acpireg.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Root System Descriptor Pointer */ +struct acpi_rsdp1 { + u_int8_t signature[8]; +#define RSDP_SIG "RSD PTR " +#define rsdp_signaturee rsdp1.signature + u_int8_t checksum; /* make sum == 0 */ +#define rsdp_checksum rsdp1.checksum + u_int8_t oemid[6]; +#define rsdp_oemid rsdp1.oemid + u_int8_t revision; /* 0 for 1, 2 for 2 */ +#define rsdp_revision rsdp1.revision + u_int32_t rsdt; /* physical */ +#define rsdp_rsdt rsdp1.rsdt +} __packed; + +struct acpi_rsdp { + struct acpi_rsdp1 rsdp1; + /* + * The following values are only valid + * when rsdp_revision == 2 + */ + u_int32_t rsdp_length; /* length of rsdp */ + u_int64_t rsdp_xsdt; /* physical */ + u_int8_t rsdp_extchecksum; /* entire table */ + u_int8_t rsdp_reserved[3]; /* must be zero */ +} __packed; + +struct acpi_table_header { + u_int8_t signature[4]; +#define hdr_signature hdr.signature + u_int32_t length; +#define hdr_length hdr.length + u_int8_t revision; +#define hdr_revision hdr.revision + u_int8_t checksum; +#define hdr_checksum hdr.checksum + u_int8_t oemid[6]; +#define hdr_oemid hdr.oemid + u_int8_t oemtableid[8]; +#define hdr_oemtableid hdr.oemtableid + u_int32_t oemrevision; +#define hdr_oemrevision hdr.oemrevision + u_int8_t aslcompilerid[4]; +#define hdr_aslcompilerid hdr.aslcompilerid + u_int32_t aslcompilerrevision; +#define hdr_aslcompilerrevision hdr.aslcompilerrevision +} __packed; + +struct acpi_rsdt { + struct acpi_table_header hdr; +#define RSDT_SIG "RSDT" + u_int32_t table_offsets[1]; +} __packed; + +struct acpi_xsdt { + struct acpi_table_header hdr; +#define XSDT_SIG "XSDT" + u_int64_t table_offsets[1]; +} __packed; + +struct acpi_gas { + u_int8_t address_space_id; +#define GAS_SYSTEM_MEMORY 0 +#define GAS_SYSTEM_IOSPACE 1 +#define GAS_PCI_CFG_SPACE 2 +#define GAS_EMBEDDED 3 +#define GAS_SMBUS 4 +#define GAS_FUNCTIONAL_FIXED 127 + u_int8_t register_bit_width; + u_int8_t register_bit_offset; + u_int8_t access_size; +#define GAS_ACCESS_UNDEFINED 0 +#define GAS_ACCESS_BYTE 1 +#define GAS_ACCESS_WORD 2 +#define GAS_ACCESS_DWORD 3 +#define GAS_ACCESS_QWORD 4 + u_int64_t address; +} __packed; + +struct acpi_fadt { + struct acpi_table_header hdr; +#define FADT_SIG "FACP" + u_int32_t firmware_ctl; /* phys addr FACS */ + u_int32_t dsdt; /* phys addr DSDT */ + u_int8_t int_model; /* interrupt model (hdr_revision < 3) */ +#define FADT_INT_DUAL_PIC 0 +#define FADT_INT_MULTI_APIC 1 + u_int8_t pm_profile; /* power mgmt profile */ +#define FADT_PM_UNSPEC 0 +#define FADT_PM_DESKTOP 1 +#define FADT_PM_MOBILE 2 +#define FADT_PM_WORKSTATION 3 +#define FADT_PM_ENT_SERVER 4 +#define FADT_PM_SOHO_SERVER 5 +#define FADT_PM_APPLIANCE 6 +#define FADT_PM_PERF_SERVER 7 + u_int16_t sci_int; /* SCI interrupt */ + u_int32_t smi_cmd; /* SMI command port */ + u_int8_t acpi_enable; /* value to enable */ + u_int8_t acpi_disable; /* value to disable */ + u_int8_t s4bios_req; /* value for S4 */ + u_int8_t pstate_cnt; /* value for performance (hdr_revision > 2) */ + u_int32_t pm1a_evt_blk; /* power management 1a */ + u_int32_t pm1b_evt_blk; /* power mangement 1b */ + u_int32_t pm1a_cnt_blk; /* pm control 1a */ + u_int32_t pm1b_cnt_blk; /* pm control 1b */ + u_int32_t pm2_cnt_blk; /* pm control 2 */ + u_int32_t pm_tmr_blk; + u_int32_t gpe0_blk; + u_int32_t gpe1_blk; + u_int8_t pm1_evt_len; + u_int8_t pm1_cnt_len; + u_int8_t pm2_cnt_len; + u_int8_t pm_tmr_len; + u_int8_t gpe0_blk_len; + u_int8_t gpe1_blk_len; + u_int8_t gpe1_base; + u_int8_t cst_cnt; /* (hdr_revision > 2) */ + u_int16_t p_lvl2_lat; + u_int16_t p_lvl3_lat; + u_int16_t flush_size; + u_int16_t flush_stride; + u_int8_t duty_offset; + u_int8_t duty_width; + u_int8_t day_alrm; + u_int8_t mon_alrm; + u_int8_t century; + u_int16_t iapc_boot_arch; /* (hdr_revision > 2) */ +#define FADT_LEGACY_DEVICES 0x0001 /* Legacy devices supported */ +#define FADT_i8042 0x0002 /* Keyboard controller present */ +#define FADT_NO_VGA 0x0004 /* Do not probe VGA */ + u_int8_t reserved1; + u_int32_t flags; +#define FADT_WBINVD 0x00000001 +#define FADT_WBINVD_FLUSH 0x00000002 +#define FADT_PROC_C1 0x00000004 +#define FADT_P_LVL2_UP 0x00000008 +#define FADT_PWR_BUTTON 0x00000010 +#define FADT_SLP_BUTTON 0x00000020 +#define FADT_FIX_RTC 0x00000040 +#define FADT_RTC_S4 0x00000080 +#define FADT_TMR_VAL_EXT 0x00000100 +#define FADT_DCK_CAP 0x00000200 +#define FADT_RESET_REG_SUP 0x00000400 +#define FADT_SEALED_CASE 0x00000800 +#define FADT_HEADLESS 0x00001000 +#define FADT_CPU_SW_SLP 0x00002000 +#define FADT_PCI_EXP_WAK 0x00004000 +#define FADT_USE_PLATFORM_CLOCK 0x00008000 +#define FADT_S4_RTC_STS_VALID 0x00010000 +#define FADT_REMOTE_POWER_ON_CAPABLE 0x00020000 +#define FADT_FORCE_APIC_CLUSTER_MODEL 0x00040000 +#define FADT_FORCE_APIC_PHYS_DEST_MODE 0x00080000 + /* + * Following values only exist when rev > 1 + * If the extended addresses exists, they + * must be used in preferense to the non- + * extended values above + */ + struct acpi_gas reset_reg; + u_int8_t reset_value; + u_int8_t reserved2a; + u_int8_t reserved2b; + u_int8_t reserved2c; + u_int64_t x_firmware_ctl; + u_int64_t x_dsdt; + struct acpi_gas x_pm1a_evt_blk; + struct acpi_gas x_pm1b_evt_blk; + struct acpi_gas x_pm1a_cnt_blk; + struct acpi_gas x_pm1b_cnt_blk; + struct acpi_gas x_pm2_cnt_blk; + struct acpi_gas x_pm_tmr_blk; + struct acpi_gas x_gpe0_blk; + struct acpi_gas x_gpe1_blk; +} __packed; + +struct acpi_dsdt { + struct acpi_table_header hdr; +#define DSDT_SIG "DSDT" + u_int8_t aml[1]; +} __packed; + +struct acpi_ssdt { + struct acpi_table_header hdr; +#define SSDT_SIG "SSDT" + u_int8_t aml[1]; +} __packed; + +/* + * Table deprecated by ACPI 2.0 + */ +struct acpi_psdt { + struct acpi_table_header hdr; +#define PSDT_SIG "PSDT" +} __packed; + +struct acpi_madt { + struct acpi_table_header hdr; +#define MADT_SIG "APIC" + u_int32_t local_apic_address; + u_int32_t flags; +#define ACPI_APIC_PCAT_COMPAT 0x00000001 +} __packed; + +struct acpi_madt_lapic { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC 0 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int8_t apic_id; + u_int32_t flags; +#define ACPI_PROC_ENABLE 0x00000001 +} __packed; + +struct acpi_madt_ioapic { + u_int8_t apic_type; +#define ACPI_MADT_IOAPIC 1 + u_int8_t length; + u_int8_t acpi_ioapic_id; + u_int8_t reserved; + u_int32_t address; + u_int32_t global_int_base; +} __packed; + +struct acpi_madt_override { + u_int8_t apic_type; +#define ACPI_MADT_OVERRIDE 2 + u_int8_t length; + u_int8_t bus; +#define ACPI_OVERRIDE_BUS_ISA 0 + u_int8_t source; + u_int32_t global_int; + u_int16_t flags; +#define ACPI_OVERRIDE_POLARITY_BITS 0x3 +#define ACPI_OVERRIDE_POLARITY_BUS 0x0 +#define ACPI_OVERRIDE_POLARITY_HIGH 0x1 +#define ACPI_OVERRIDE_POLARITY_LOW 0x3 +#define ACPI_OVERRIDE_TRIGGER_BITS 0xc +#define ACPI_OVERRIDE_TRIGGER_BUS 0x0 +#define ACPI_OVERRIDE_TRIGGER_EDGE 0x4 +#define ACPI_OVERRIDE_TRIGGER_LEVEL 0xc +} __packed; + +struct acpi_madt_nmi { + u_int8_t apic_type; +#define ACPI_MADT_NMI 3 + u_int8_t length; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int32_t global_int; +} __packed; + +struct acpi_madt_lapic_nmi { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC_NMI 4 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int8_t local_apic_lint; +} __packed; + +struct acpi_madt_lapic_override { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC_OVERRIDE 5 + u_int8_t length; + u_int16_t reserved; + u_int64_t lapic_address; +} __packed; + +struct acpi_madt_io_sapic { + u_int8_t apic_type; +#define ACPI_MADT_IO_SAPIC 6 + u_int8_t length; + u_int8_t iosapic_id; + u_int8_t reserved; + u_int32_t global_int_base; + u_int64_t iosapic_address; +} __packed; + +struct acpi_madt_local_sapic { + u_int8_t apic_type; +#define ACPI_MADT_LOCAL_SAPIC 7 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int8_t local_sapic_id; + u_int8_t local_sapic_eid; + u_int8_t reserved[3]; + u_int32_t flags; /* Same flags as acpi_madt_lapic */ + u_int32_t acpi_proc_uid; + u_int8_t acpi_proc_uid_string[1]; +} __packed; + +struct acpi_madt_platform_int { + u_int8_t apic_type; +#define ACPI_MADT_PLATFORM_INT 8 + u_int8_t length; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int8_t int_type; +#define ACPI_MADT_PLATFORM_PMI 1 +#define ACPI_MADT_PLATFORM_INIT 2 +#define ACPI_MADT_PLATFORM_CORR_ERROR 3 + u_int8_t proc_id; + u_int8_t proc_eid; + u_int8_t io_sapic_vec; + u_int32_t global_int; + u_int32_t platform_int_flags; +#define ACPI_MADT_PLATFORM_CPEI 0x00000001 +} __packed; + +union acpi_madt_entry { + struct acpi_madt_lapic madt_lapic; + struct acpi_madt_ioapic madt_ioapic; + struct acpi_madt_override madt_override; + struct acpi_madt_nmi madt_nmi; + struct acpi_madt_lapic_nmi madt_lapic_nmi; + struct acpi_madt_lapic_override madt_lapic_override; + struct acpi_madt_io_sapic madt_io_sapic; + struct acpi_madt_local_sapic madt_local_sapic; + struct acpi_madt_platform_int madt_platform_int; +} __packed; + +struct acpi_sbst { + struct acpi_table_header hdr; +#define SBST_SIG "SBST" + u_int32_t warning_energy_level; + u_int32_t low_energy_level; + u_int32_t critical_energy_level; +} __packed; + +struct acpi_ecdt { + struct acpi_table_header hdr; +#define ECDT_SIG "ECDT" + struct acpi_gas ec_control; + struct acpi_gas ec_data; + u_int32_t uid; + u_int8_t gpe_bit; + u_int8_t ec_id[1]; +} __packed; + +struct acpi_srat { + struct acpi_table_header hdr; +#define SRAT_SIG "SRAT" + u_int32_t reserved1; + u_int64_t reserved2; +} __packed; + +struct acpi_slit { + struct acpi_table_header hdr; +#define SLIT_SIG "SLIT" + u_int64_t number_of_localities; +} __packed; + +struct acpi_hpet { + struct acpi_table_header hdr; +#define HPET_SIG "HPET" + u_int32_t event_timer_block_id; + struct acpi_gas base_address; + u_int8_t hpet_number; + u_int16_t main_counter_min_clock_tick; + u_int8_t page_protection; +} __packed; + +struct acpi_facs { + u_int8_t signature[4]; +#define FACS_SIG "FACS" + u_int32_t length; + u_int32_t hardware_signature; + u_int32_t wakeup_vector; + u_int32_t global_lock; +#define FACS_LOCK_PENDING 0x00000001 +#define FACS_LOCK_OWNED 0x00000002 + u_int32_t flags; +#define FACS_S4BIOS_F 0x00000001 /* S4BIOS_REQ supported */ + struct acpi_gas x_wakeup_vector; + u_int8_t version; + u_int8_t reserved[31]; +} __packed; + +#define ACPI_FREQUENCY 3579545 /* Per ACPI spec */ + +/* + * PM1 Status Registers Fixed Hardware Feature Status Bits + */ +#define ACPI_PM1_STATUS 0x00 +#define ACPI_PM1_TMR_STS 0x0001 +#define ACPI_PM1_BM_STS 0x0010 +#define ACPI_PM1_GBL_STS 0x0020 +#define ACPI_PM1_PWRBTN_STS 0x0100 +#define ACPI_PM1_SLPBTN_STS 0x0200 +#define ACPI_PM1_RTC_STS 0x0400 +#define ACPI_PM1_PCIEXP_WAKE_STS 0x4000 +#define ACPI_PM1_WAK_STS 0x8000 + +/* + * PM1 Enable Registers + */ +#define ACPI_PM1_ENABLE 0x02 +#define ACPI_PM1_TMR_EN 0x0001 +#define ACPI_PM1_GBL_EN 0x0020 +#define ACPI_PM1_PWRBTN_EN 0x0100 +#define ACPI_PM1_SLPBTN_EN 0x0200 +#define ACPI_PM1_RTC_EN 0x0400 +#define ACPI_PM1_PCIEXP_WAKE_DIS 0x4000 + +/* + * PM1 Control Registers + */ +#define ACPI_PM1_CONTROL 0x00 +#define ACPI_PM1_SCI_EN 0x0001 +#define ACPI_PM1_BM_RLD 0x0002 +#define ACPI_PM1_GBL_RLS 0x0004 +#define ACPI_PM1_SLP_EN 0x2000 diff --git a/sys/dev/acpi/acpitimer.c b/sys/dev/acpi/acpitimer.c new file mode 100644 index 00000000000..2cf89d6efda --- /dev/null +++ b/sys/dev/acpi/acpitimer.c @@ -0,0 +1,152 @@ +/* $OpenBSD: acpitimer.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#ifdef __HAVE_TIMECOUNTER +#include <sys/timetc.h> +#endif + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +int acpitimermatch(struct device *, void *, void *); +void acpitimerattach(struct device *, struct device *, void *); + +#ifdef __HAVE_TIMECOUNTER +u_int acpi_get_timecount(struct timecounter *tc); + +static struct timecounter acpi_timecounter = { + acpi_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0x00ffffff, /* counter_mask (24 bits) */ + ACPI_FREQUENCY, /* frequency */ + 0, /* name */ + 1000 /* quality */ +}; +#endif + +struct acpitimer_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct cfattach acpitimer_ca = { + sizeof(struct acpitimer_softc), acpitimermatch, acpitimerattach +}; + +struct cfdriver acpitimer_cd = { + NULL, "acpitimer", DV_DULL +}; + +int +acpitimermatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aa = aux; + struct cfdata *cf = match; + + /* sanity */ + if (aa->aaa_name == NULL || + strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || + aa->aaa_table != NULL) + return (0); + + return (1); +} + +void +acpitimerattach(struct device *parent, struct device *self, void *aux) +{ + struct acpitimer_softc *sc = (struct acpitimer_softc *) self; + struct acpi_softc *psc = (struct acpi_softc *) parent; + struct acpi_attach_args *aa = aux; + bus_addr_t address; + bus_size_t size; + + if (psc->sc_fadt->hdr_revision > 1) { + switch (psc->sc_fadt->x_pm_tmr_blk.address_space_id) { + case GAS_SYSTEM_MEMORY: + sc->sc_iot = aa->aaa_memt; + break; + + case GAS_SYSTEM_IOSPACE: + sc->sc_iot = aa->aaa_iot; + break; + +#if 0 + case GAS_SYSTEM_PCI_CFG_SPACE: + sc->sc_iot = aa->aaa_pcit; + break; + + case GAS_SYSTEM_SMBUS: + sc->sc_iot = aa->aaa_smbust; + break; +#endif + + default: + printf(": can't identify bus\n"); + return; + } + address = psc->sc_fadt->x_pm_tmr_blk.address; + } + else { + sc->sc_iot = aa->aaa_iot; + address = psc->sc_fadt->pm_tmr_blk; + } + size = psc->sc_fadt->pm_tmr_len; + + if (bus_space_map(sc->sc_iot, address, size, 0, &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + printf(": %ld Hz, %d bits\n", ACPI_FREQUENCY, + psc->sc_fadt->flags & FADT_TMR_VAL_EXT ? 32 : 24); + +#ifdef __HAVE_TIMECOUNTER + if (psc->sc_fadt->flags & FADT_TMR_VAL_EXT) + acpi_timecounter.tc_counter_mask = 0xffffffffU; + acpi_timecounter.tc_priv = sc; + acpi_timecounter.tc_name = sc->sc_dev.dv_xname; + tc_init(&acpi_timecounter); +#endif +} + + +#ifdef __HAVE_TIMECOUNTER +u_int +acpi_get_timecount(struct timecounter *tc) +{ + struct acpitimer_softc *sc = tc->tc_priv; + u_int u1, u2, u3; + + u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + do { + u1 = u2; + u2 = u3; + u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + } while (u1 > u2 || u2 > u3); + return (u2); +} +#endif diff --git a/sys/dev/acpi/acpiutil.c b/sys/dev/acpi/acpiutil.c new file mode 100644 index 00000000000..c364c97d03b --- /dev/null +++ b/sys/dev/acpi/acpiutil.c @@ -0,0 +1,42 @@ +/* $OpenBSD: acpiutil.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +u_int +acpi_checksum(const void *v, size_t len) +{ + const u_char *p = v; + u_char s; + int i; + + s = 0; + for (i = 0; i < len; i++) + s += p[i]; + + if (s) + printf("acpi: bad checksum at %p\n", v); + + return (s); +} diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h new file mode 100644 index 00000000000..b654a45bba4 --- /dev/null +++ b/sys/dev/acpi/acpivar.h @@ -0,0 +1,111 @@ +/* $OpenBSD: acpivar.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/timeout.h> + +struct klist; + +struct acpi_attach_args { + char *aaa_name; + bus_space_tag_t aaa_iot; + bus_space_tag_t aaa_memt; + void *aaa_table; + paddr_t aaa_pbase; /* Physical base address of ACPI tables */ +}; + +struct acpi_mem_map { + vaddr_t baseva; + u_int8_t *va; + size_t vsize; + paddr_t pa; +}; + +struct acpi_q { + SIMPLEQ_ENTRY(acpi_q) q_next; + void *q_table; + u_int8_t q_data[0]; +}; + +typedef SIMPLEQ_HEAD(, acpi_q) acpi_qhead_t; + +struct acpi_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; +#if 0 + bus_space_tag_t sc_pcit; + bus_space_tag_t sc_smbust; +#endif + + /* + * First-level ACPI tables + */ + struct acpi_fadt *sc_fadt; + acpi_qhead_t sc_tables; + + /* + * Second-level information from FADT + */ + struct acpi_facs *sc_facs; /* Shared with firmware! */ + + struct klist *sc_note; + bus_space_handle_t sc_ioh_pm1a_evt; + + void *sc_interrupt; +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + void *sc_softih; +#else + struct timeout sc_timeout; +#endif + + int sc_powerbtn; + int sc_sleepbtn; +}; + +struct acpi_table { + int offset; + size_t size; + void *table; +}; + +#define ACPI_IOC_GETFACS _IOR('A', 0, struct acpi_facs) +#define ACPI_IOC_GETTABLE _IOWR('A', 1, struct acpi_table) + +#define ACPI_EV_PWRBTN 0x0001 /* Power button was pushed */ +#define ACPI_EV_SLPBTN 0x0002 /* Sleep button was pushed */ + +#define ACPI_EVENT_MASK 0x0003 + +#define ACPI_EVENT_COMPOSE(t,i) (((i) & 0x7fff) << 16 | ((t) & ACPI_EVENT_MASK)) +#define ACPI_EVENT_TYPE(e) ((e) & ACPI_EVENT_MASK) +#define ACPI_EVENT_INDEX(e) ((e) >> 16) + +/* + * Sleep states + */ +#define ACPI_STATE_S5 5 + +#if defined(_KERNEL) +int acpi_map(paddr_t, size_t, struct acpi_mem_map *); +void acpi_unmap(struct acpi_mem_map *); +int acpi_probe(struct device *, struct cfdata *, struct acpi_attach_args *); +u_int acpi_checksum(const void *, size_t); +void acpi_attach_machdep(struct acpi_softc *); +int acpi_interrupt(void *); +void acpi_enter_sleep_state(struct acpi_softc *, int); +#endif diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi new file mode 100644 index 00000000000..c03ba10e83e --- /dev/null +++ b/sys/dev/acpi/files.acpi @@ -0,0 +1,20 @@ +# $OpenBSD: files.acpi,v 1.1 2005/06/02 20:09:39 tholo Exp $ +# +# Config file and device description for machine-independent ACPI code. +# Included by ports that need it. + +define acpi {} +device acpi +attach acpi at mainbus +file dev/acpi/acpi.c acpi needs-flag +file dev/acpi/acpiutil.c acpi + +# ACPI timer +device acpitimer +attach acpitimer at acpi +file dev/acpi/acpitimer.c acpitimer + +# High Precision Event Timer +device hpet +attach hpet at acpi +file dev/acpi/hpet.c hpet
\ No newline at end of file diff --git a/sys/dev/acpi/hpet.c b/sys/dev/acpi/hpet.c new file mode 100644 index 00000000000..e79e7a42627 --- /dev/null +++ b/sys/dev/acpi/hpet.c @@ -0,0 +1,144 @@ +/* $OpenBSD: hpet.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#ifdef __HAVE_TIMECOUNTER +#include <sys/timetc.h> +#endif + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/hpetreg.h> + +int hpetmatch(struct device *, void *, void *); +void hpetattach(struct device *, struct device *, void *); + +#ifdef __HAVE_TIMECOUNTER +u_int hpet_get_timecount(struct timecounter *tc); + +static struct timecounter hpet_timecounter = { + hpet_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0xffffffff, /* counter_mask (24 bits) */ + 0, /* frequency */ + 0, /* name */ + 1000 /* quality */ +}; +#endif + +struct hpet_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct cfattach hpet_ca = { + sizeof(struct hpet_softc), hpetmatch, hpetattach +}; + +struct cfdriver hpet_cd = { + NULL, "hpet", DV_DULL +}; + +int +hpetmatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpi_table_header *hdr; + + /* + * If we do not have a table, it is not us + */ + if (aaa->aaa_table == NULL) + return (0); + + /* + * If it is an HPET table, we can attach + */ + hdr = (struct acpi_table_header *)aaa->aaa_table; + if (memcmp(hdr->signature, HPET_SIG, sizeof(HPET_SIG) - 1) != 0) + return (0); + + return (1); +} + +void +hpetattach(struct device *parent, struct device *self, void *aux) +{ + struct hpet_softc *sc = (struct hpet_softc *) self; + struct acpi_attach_args *aa = aux; + struct acpi_hpet *hpet = (struct acpi_hpet *)aa->aaa_table; + u_int64_t period, freq; /* timer period in femtoseconds (10^-15) */ + + switch (hpet->base_address.address_space_id) { + case GAS_SYSTEM_MEMORY: + sc->sc_iot = aa->aaa_memt; + break; + + case GAS_SYSTEM_IOSPACE: + sc->sc_iot = aa->aaa_iot; + break; + +#if 0 + case GAS_SYSTEM_PCI_CFG_SPACE: + sc->sc_iot = aa->aaa_pcit; + break; + + case GAS_SYSTEM_SMBUS: + sc->sc_iot = aa->aaa_smbust; + break; +#endif + + default: + printf(": can't identify bus\n"); + return; + } + + if (bus_space_map(sc->sc_iot, hpet->base_address.address, HPET_REG_SIZE, + 0, &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + period = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + HPET_CAPABILITIES + sizeof(u_int32_t)); + freq = 1000000000000000ull / period; + printf(": %lld Hz\n", freq); + +#ifdef __HAVE_TIMECOUNTER + hpet_timecounter.tc_frequency = (u_int32_t)freq; + hpet_timecounter.tc_priv = sc; + hpet_timecounter.tc_name = sc->sc_dev.dv_xname; + tc_init(&hpet_timecounter); +#endif +} + +#ifdef __HAVE_TIMECOUNTER +u_int +hpet_get_timecount(struct timecounter *tc) +{ + struct hpet_softc *sc = tc->tc_priv; + + return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, HPET_MAIN_COUNTER)); +} +#endif diff --git a/sys/dev/acpi/hpetreg.h b/sys/dev/acpi/hpetreg.h new file mode 100644 index 00000000000..7c5bae72a82 --- /dev/null +++ b/sys/dev/acpi/hpetreg.h @@ -0,0 +1,32 @@ +/* $OpenBSD: hpetreg.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define HPET_REG_SIZE 1024 + +#define HPET_CAPABILITIES 0x000 +#define HPET_CONFIGURATION 0x010 +#define HPET_INTERRUPT_STATUS 0x020 +#define HPET_MAIN_COUNTER 0x0F0 +#define HPET_TIMER0_CONFIG 0x100 +#define HPET_TIMER0_COMPARE 0x108 +#define HPET_TIMER0_INTERRUPT 0x110 +#define HPET_TIMER1_CONFIG 0x200 +#define HPET_TIMER1_COMPARE 0x208 +#define HPET_TIMER1_INTERRUPT 0x310 +#define HPET_TIMER2_CONFIG 0x400 +#define HPET_TIMER2_COMPARE 0x408 +#define HPET_TIMER2_INTERRUPT 0x510 |