1 /* $OpenBSD: amdpcib.c,v 1.1 2007/10/07 18:41:06 mbalmer Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 16 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * AMD8111 series LPC bridge also containing HPET and watchdog 22 */ 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/device.h> 27 #include <sys/sysctl.h> 28 #include <sys/timetc.h> 29 30 #include <machine/bus.h> 31 32 #include <dev/pci/pcireg.h> 33 #include <dev/pci/pcivar.h> 34 #include <dev/pci/pcidevs.h> 35 36 #define AMD8111_HPET 0xa0 /* PCI config space */ 37 #define AMD8111_HPET_ENA 0x00000001 38 #define AMD8111_HPET_BASE 0xfffffc00 39 #define AMD8111_HPET_SIZE 0x00000400 40 41 #define AMD8111_HPET_ID 0x000 42 #define AMD8111_HPET_WIDTH 0x00002000 43 #define AMD8111_HPET_REV 0x000000ff 44 #define AMD8111_HPET_PERIOD 0x004 45 #define AMD8111_HPET_CFG 0x010 46 #define AMD8111_HPET_CFG_GIEN 0x00000001 47 #define AMD8111_HPET_ISTAT 0x020 48 #define AMD8111_HPET_MAIN 0x0f0 49 #define AMD8111_HPET_T0CFG 0x100 50 #define AMD8111_HPET_T0CMP 0x108 51 #define AMD8111_HPET_T1CFG 0x120 52 #define AMD8111_HPET_T1CMP 0x128 53 #define AMD8111_HPET_T2CFG 0x140 54 #define AMD8111_HPET_T2CMP 0x148 55 56 #define AMD8111_WDOG 0xa8 /* PCI config space */ 57 #define AMD8111_WDOG_ENA 0x00000001 58 #define AMD8111_WDOG_HALT 0x00000002 59 #define AMD8111_WDOG_SILENT 0x00000004 60 #define AMD8111_WDOG_BASE 0xffffffe0 61 62 #define AMD8111_WDOG_CTRL 0x00 63 #define AMD8111_WDOG_RSTOP 0x0001 64 #define AMD8111_WDOG_WFIR 0x0002 65 #define AMD8111_WDOG_WACT 0x0004 66 #define AMD8111_WDOG_WDALIAS 0x0008 67 #define AMD8111_WDOG_WTRIG 0x0080 68 #define AMD8111_WDOG_COUNT 0x08 69 #define AMD8111_WDOG_MASK 0xffff 70 71 struct amdpcib_softc { 72 struct device sc_dev; 73 74 bus_space_tag_t sc_hpet_iot; 75 bus_space_handle_t sc_hpet_ioh; 76 struct timecounter sc_hpet_timecounter; 77 }; 78 79 struct cfdriver amdpcib_cd = { 80 NULL, "amdpcib", DV_DULL 81 }; 82 83 int amdpcib_match(struct device *, void *, void *); 84 void amdpcib_attach(struct device *, struct device *, void *); 85 86 struct cfattach amdpcib_ca = { 87 sizeof(struct amdpcib_softc), amdpcib_match, amdpcib_attach 88 }; 89 90 /* from arch/<*>/pci/pcib.c */ 91 void pcibattach(struct device *parent, struct device *self, void *aux); 92 93 u_int amdpcib_get_timecount(struct timecounter *tc); 94 95 const struct pci_matchid amdpcib_devices[] = { 96 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC8111_LPC } 97 /* also available on 590 and 690 chipsets */ 98 }; 99 100 int 101 amdpcib_match(struct device *parent, void *match, void *aux) 102 { 103 if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices, 104 sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0]))) 105 return 2; 106 107 return 0; 108 } 109 110 void 111 amdpcib_attach(struct device *parent, struct device *self, void *aux) 112 { 113 struct amdpcib_softc *sc = (struct amdpcib_softc *)self; 114 struct pci_attach_args *pa = aux; 115 struct timecounter *tc = &sc->sc_hpet_timecounter; 116 pcireg_t reg; 117 u_int32_t v; 118 119 120 sc->sc_hpet_iot = pa->pa_memt; 121 reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET); 122 if (reg & AMD8111_HPET_ENA && 123 bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE, 124 AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) { 125 126 tc->tc_get_timecount = amdpcib_get_timecount; 127 /* XXX 64-bit counter is not supported! */ 128 tc->tc_counter_mask = 0xffffffff; 129 130 v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, 131 AMD8111_HPET_PERIOD); 132 /* femtosecs -> Hz */ 133 tc->tc_frequency = 1000000000000000ULL / v; 134 135 tc->tc_name = "AMD8111"; 136 tc->tc_quality = 2000; 137 tc->tc_priv = sc; 138 tc_init(tc); 139 140 /* enable counting */ 141 bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, 142 AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN); 143 144 v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, 145 AMD8111_HPET_ID); 146 printf(": %d-bit %lluHz timer rev %d", 147 (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency, 148 v & AMD8111_HPET_REV); 149 } 150 151 pcibattach(parent, self, aux); 152 } 153 154 u_int 155 amdpcib_get_timecount(struct timecounter *tc) 156 { 157 struct amdpcib_softc *sc = tc->tc_priv; 158 159 /* XXX 64-bit counter is not supported! */ 160 return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh, 161 AMD8111_HPET_MAIN); 162 } 163