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