1 /* $OpenBSD: gscpm.c,v 1.6 2006/12/12 23:14:27 dim 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 #include <sys/sysctl.h> 27 #ifdef __HAVE_TIMECOUNTER 28 #include <sys/timetc.h> 29 #endif 30 31 #include <machine/bus.h> 32 33 #include <dev/pci/pcireg.h> 34 #include <dev/pci/pcivar.h> 35 #include <dev/pci/pcidevs.h> 36 37 #include <i386/pci/gscpmreg.h> 38 39 struct gscpm_softc { 40 struct device sc_dev; 41 42 pci_chipset_tag_t sc_pc; 43 pcitag_t sc_tag; 44 bus_space_tag_t sc_iot; 45 bus_space_handle_t sc_acpi_ioh; 46 }; 47 48 int gscpm_match(struct device *, void *, void *); 49 void gscpm_attach(struct device *, struct device *, void *); 50 51 void gscpm_setperf(int); 52 53 #ifdef __HAVE_TIMECOUNTER 54 u_int gscpm_get_timecount(struct timecounter *tc); 55 56 struct timecounter gscpm_timecounter = { 57 gscpm_get_timecount, /* get_timecount */ 58 0, /* no poll_pps */ 59 0xffffff, /* counter_mask */ 60 3579545, /* frequency */ 61 "GSCPM", /* name */ 62 1000 /* quality */ 63 }; 64 #endif /* __HAVE_TIMECOUNTER */ 65 66 struct cfattach gscpm_ca = { 67 sizeof (struct gscpm_softc), 68 gscpm_match, 69 gscpm_attach 70 }; 71 72 struct cfdriver gscpm_cd = { 73 NULL, "gscpm", DV_DULL 74 }; 75 76 #if 0 77 static void *gscpm_cookie; /* XXX */ 78 #endif 79 80 int 81 gscpm_match(struct device *parent, void *match, void *aux) 82 { 83 struct pci_attach_args *pa = aux; 84 85 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS && 86 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SC1100_SMI) 87 return (1); 88 89 return (0); 90 } 91 92 void 93 gscpm_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct gscpm_softc *sc = (struct gscpm_softc *)self; 96 struct pci_attach_args *pa = aux; 97 pcireg_t csr, acpibase; 98 99 sc->sc_pc = pa->pa_pc; 100 sc->sc_tag = pa->pa_tag; 101 sc->sc_iot = pa->pa_iot; 102 103 /* Enable I/O space */ 104 csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG); 105 pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, 106 csr | PCI_COMMAND_IO_ENABLE); 107 108 /* Map ACPI registers */ 109 acpibase = pci_conf_read(sc->sc_pc, sc->sc_tag, GSCPM_ACPIBASE); 110 if (PCI_MAPREG_IO_ADDR(acpibase) == 0 || 111 bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(acpibase), 112 GSCPM_ACPISIZE, 0, &sc->sc_acpi_ioh)) { 113 printf(": failed to map ACPI registers\n"); 114 return; 115 } 116 117 printf("\n"); 118 119 #ifdef __HAVE_TIMECOUNTER 120 /* Hook into the kern_tc */ 121 gscpm_timecounter.tc_priv = sc; 122 tc_init(&gscpm_timecounter); 123 #endif /* __HAVE_TIMECOUNTER */ 124 125 /* XXX: disabled due to unresolved yet hardware errata */ 126 #if 0 127 /* Hook into the hw.setperf sysctl */ 128 gscpm_cookie = sc; 129 cpu_setperf = gscpm_setperf; 130 #endif 131 132 } 133 134 #ifdef __HAVE_TIMECOUNTER 135 u_int 136 gscpm_get_timecount(struct timecounter *tc) 137 { 138 struct gscpm_softc *sc = tc->tc_priv; 139 140 return (bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_PM_TMR)); 141 } 142 #endif /* __HAVE_TIMECOUNTER */ 143 144 #if 0 145 void 146 gscpm_setperf(int level) 147 { 148 struct gscpm_softc *sc = gscpm_cookie; 149 int i; 150 u_int32_t pctl; 151 152 pctl = bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT); 153 154 if (level == 100) { 155 /* 100 is a maximum perfomance, disable throttling */ 156 pctl &= ~GSCPM_P_CNT_THTEN; 157 } else { 158 for (i = 0; i < GSCPM_THT_LEVELS; i++) 159 if (level >= gscpm_tht[i].level) 160 break; 161 pctl = (0xf0 | GSCPM_P_CNT_THTEN | 162 GSCPM_P_CNT_CLK(gscpm_tht[i].value)); 163 } 164 165 /* Update processor control register */ 166 bus_space_write_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT, pctl); 167 } 168 #endif 169