1 /* $OpenBSD: gscpm.c,v 1.8 2010/08/02 04:37:42 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * National Semiconductor Geode SC1100 SMI/ACPI module. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/systm.h> 24 #include <sys/device.h> 25 #include <sys/kernel.h> 26 #ifdef __HAVE_TIMECOUNTER 27 #include <sys/timetc.h> 28 #endif 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 #include <i386/pci/gscpmreg.h> 37 38 struct gscpm_softc { 39 struct device sc_dev; 40 41 pci_chipset_tag_t sc_pc; 42 pcitag_t sc_tag; 43 bus_space_tag_t sc_iot; 44 bus_space_handle_t sc_acpi_ioh; 45 }; 46 47 int gscpm_match(struct device *, void *, void *); 48 void gscpm_attach(struct device *, struct device *, void *); 49 50 void gscpm_setperf(int); 51 52 #ifdef __HAVE_TIMECOUNTER 53 u_int gscpm_get_timecount(struct timecounter *tc); 54 55 struct timecounter gscpm_timecounter = { 56 gscpm_get_timecount, /* get_timecount */ 57 0, /* no poll_pps */ 58 0xffffff, /* counter_mask */ 59 3579545, /* frequency */ 60 "GSCPM", /* name */ 61 1000 /* quality */ 62 }; 63 #endif /* __HAVE_TIMECOUNTER */ 64 65 struct cfattach gscpm_ca = { 66 sizeof (struct gscpm_softc), 67 gscpm_match, 68 gscpm_attach 69 }; 70 71 struct cfdriver gscpm_cd = { 72 NULL, "gscpm", DV_DULL 73 }; 74 75 #if 0 76 static void *gscpm_cookie; /* XXX */ 77 #endif 78 79 int 80 gscpm_match(struct device *parent, void *match, void *aux) 81 { 82 struct pci_attach_args *pa = aux; 83 84 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS && 85 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SC1100_SMI) 86 return (1); 87 88 return (0); 89 } 90 91 void 92 gscpm_attach(struct device *parent, struct device *self, void *aux) 93 { 94 struct gscpm_softc *sc = (struct gscpm_softc *)self; 95 struct pci_attach_args *pa = aux; 96 pcireg_t csr, acpibase; 97 98 sc->sc_pc = pa->pa_pc; 99 sc->sc_tag = pa->pa_tag; 100 sc->sc_iot = pa->pa_iot; 101 102 /* Enable I/O space */ 103 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 104 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, 105 csr | PCI_COMMAND_IO_ENABLE); 106 107 /* Map ACPI registers */ 108 acpibase = pci_conf_read(sc->sc_pc, sc->sc_tag, GSCPM_ACPIBASE); 109 if (PCI_MAPREG_IO_ADDR(acpibase) == 0 || 110 bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(acpibase), 111 GSCPM_ACPISIZE, 0, &sc->sc_acpi_ioh)) { 112 printf(": failed to map ACPI registers\n"); 113 return; 114 } 115 116 printf("\n"); 117 118 #ifdef __HAVE_TIMECOUNTER 119 /* Hook into the kern_tc */ 120 gscpm_timecounter.tc_priv = sc; 121 tc_init(&gscpm_timecounter); 122 #endif /* __HAVE_TIMECOUNTER */ 123 124 /* XXX: disabled due to unresolved yet hardware errata */ 125 #if 0 126 /* Hook into the hw.setperf sysctl */ 127 gscpm_cookie = sc; 128 cpu_setperf = gscpm_setperf; 129 #endif 130 131 } 132 133 #ifdef __HAVE_TIMECOUNTER 134 u_int 135 gscpm_get_timecount(struct timecounter *tc) 136 { 137 struct gscpm_softc *sc = tc->tc_priv; 138 139 return (bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_PM_TMR)); 140 } 141 #endif /* __HAVE_TIMECOUNTER */ 142 143 #if 0 144 void 145 gscpm_setperf(int level) 146 { 147 struct gscpm_softc *sc = gscpm_cookie; 148 int i; 149 u_int32_t pctl; 150 151 pctl = bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT); 152 153 if (level == 100) { 154 /* 100 is a maximum perfomance, disable throttling */ 155 pctl &= ~GSCPM_P_CNT_THTEN; 156 } else { 157 for (i = 0; i < GSCPM_THT_LEVELS; i++) 158 if (level >= gscpm_tht[i].level) 159 break; 160 pctl = (0xf0 | GSCPM_P_CNT_THTEN | 161 GSCPM_P_CNT_CLK(gscpm_tht[i].value)); 162 } 163 164 /* Update processor control register */ 165 bus_space_write_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT, pctl); 166 } 167 #endif 168