diff options
Diffstat (limited to 'sys/dev/acpi')
-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 |
8 files changed, 1526 insertions, 0 deletions
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 |