/* $OpenBSD: amdpcib.c,v 1.1 2007/10/07 18:41:06 mbalmer Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * All rights reserved. * * 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 MIND, 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. */ /* * AMD8111 series LPC bridge also containing HPET and watchdog */ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> #include <sys/sysctl.h> #include <sys/timetc.h> #include <machine/bus.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> #include <dev/pci/pcidevs.h> #define AMD8111_HPET 0xa0 /* PCI config space */ #define AMD8111_HPET_ENA 0x00000001 #define AMD8111_HPET_BASE 0xfffffc00 #define AMD8111_HPET_SIZE 0x00000400 #define AMD8111_HPET_ID 0x000 #define AMD8111_HPET_WIDTH 0x00002000 #define AMD8111_HPET_REV 0x000000ff #define AMD8111_HPET_PERIOD 0x004 #define AMD8111_HPET_CFG 0x010 #define AMD8111_HPET_CFG_GIEN 0x00000001 #define AMD8111_HPET_ISTAT 0x020 #define AMD8111_HPET_MAIN 0x0f0 #define AMD8111_HPET_T0CFG 0x100 #define AMD8111_HPET_T0CMP 0x108 #define AMD8111_HPET_T1CFG 0x120 #define AMD8111_HPET_T1CMP 0x128 #define AMD8111_HPET_T2CFG 0x140 #define AMD8111_HPET_T2CMP 0x148 #define AMD8111_WDOG 0xa8 /* PCI config space */ #define AMD8111_WDOG_ENA 0x00000001 #define AMD8111_WDOG_HALT 0x00000002 #define AMD8111_WDOG_SILENT 0x00000004 #define AMD8111_WDOG_BASE 0xffffffe0 #define AMD8111_WDOG_CTRL 0x00 #define AMD8111_WDOG_RSTOP 0x0001 #define AMD8111_WDOG_WFIR 0x0002 #define AMD8111_WDOG_WACT 0x0004 #define AMD8111_WDOG_WDALIAS 0x0008 #define AMD8111_WDOG_WTRIG 0x0080 #define AMD8111_WDOG_COUNT 0x08 #define AMD8111_WDOG_MASK 0xffff struct amdpcib_softc { struct device sc_dev; bus_space_tag_t sc_hpet_iot; bus_space_handle_t sc_hpet_ioh; struct timecounter sc_hpet_timecounter; }; struct cfdriver amdpcib_cd = { NULL, "amdpcib", DV_DULL }; int amdpcib_match(struct device *, void *, void *); void amdpcib_attach(struct device *, struct device *, void *); struct cfattach amdpcib_ca = { sizeof(struct amdpcib_softc), amdpcib_match, amdpcib_attach }; /* from arch/<*>/pci/pcib.c */ void pcibattach(struct device *parent, struct device *self, void *aux); u_int amdpcib_get_timecount(struct timecounter *tc); const struct pci_matchid amdpcib_devices[] = { { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC8111_LPC } /* also available on 590 and 690 chipsets */ }; int amdpcib_match(struct device *parent, void *match, void *aux) { if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices, sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0]))) return 2; return 0; } void amdpcib_attach(struct device *parent, struct device *self, void *aux) { struct amdpcib_softc *sc = (struct amdpcib_softc *)self; struct pci_attach_args *pa = aux; struct timecounter *tc = &sc->sc_hpet_timecounter; pcireg_t reg; u_int32_t v; sc->sc_hpet_iot = pa->pa_memt; reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET); if (reg & AMD8111_HPET_ENA && bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE, AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) { tc->tc_get_timecount = amdpcib_get_timecount; /* XXX 64-bit counter is not supported! */ tc->tc_counter_mask = 0xffffffff; v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, AMD8111_HPET_PERIOD); /* femtosecs -> Hz */ tc->tc_frequency = 1000000000000000ULL / v; tc->tc_name = "AMD8111"; tc->tc_quality = 2000; tc->tc_priv = sc; tc_init(tc); /* enable counting */ bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN); v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, AMD8111_HPET_ID); printf(": %d-bit %lluHz timer rev %d", (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency, v & AMD8111_HPET_REV); } pcibattach(parent, self, aux); } u_int amdpcib_get_timecount(struct timecounter *tc) { struct amdpcib_softc *sc = tc->tc_priv; /* XXX 64-bit counter is not supported! */ return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, AMD8111_HPET_MAIN); }