1*24ee467dScheloha /* $OpenBSD: gscpm.c,v 1.14 2023/02/04 19:19:36 cheloha Exp $ */
20fd6afa2Sgrange /*
30fd6afa2Sgrange * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
40fd6afa2Sgrange *
50fd6afa2Sgrange * Permission to use, copy, modify, and distribute this software for any
60fd6afa2Sgrange * purpose with or without fee is hereby granted, provided that the above
70fd6afa2Sgrange * copyright notice and this permission notice appear in all copies.
80fd6afa2Sgrange *
90fd6afa2Sgrange * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100fd6afa2Sgrange * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110fd6afa2Sgrange * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120fd6afa2Sgrange * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130fd6afa2Sgrange * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140fd6afa2Sgrange * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150fd6afa2Sgrange * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160fd6afa2Sgrange */
170fd6afa2Sgrange
180fd6afa2Sgrange /*
190fd6afa2Sgrange * National Semiconductor Geode SC1100 SMI/ACPI module.
200fd6afa2Sgrange */
210fd6afa2Sgrange
220fd6afa2Sgrange #include <sys/param.h>
230fd6afa2Sgrange #include <sys/systm.h>
240fd6afa2Sgrange #include <sys/device.h>
250fd6afa2Sgrange #include <sys/kernel.h>
260fd6afa2Sgrange #include <sys/timetc.h>
270fd6afa2Sgrange
280fd6afa2Sgrange #include <machine/bus.h>
290fd6afa2Sgrange
300fd6afa2Sgrange #include <dev/pci/pcireg.h>
310fd6afa2Sgrange #include <dev/pci/pcivar.h>
32b6edc779Sgrange #include <dev/pci/pcidevs.h>
330fd6afa2Sgrange
340fd6afa2Sgrange #include <i386/pci/gscpmreg.h>
350fd6afa2Sgrange
360fd6afa2Sgrange struct gscpm_softc {
370fd6afa2Sgrange struct device sc_dev;
380fd6afa2Sgrange
390fd6afa2Sgrange pci_chipset_tag_t sc_pc;
400fd6afa2Sgrange pcitag_t sc_tag;
410fd6afa2Sgrange bus_space_tag_t sc_iot;
420fd6afa2Sgrange bus_space_handle_t sc_acpi_ioh;
430fd6afa2Sgrange };
440fd6afa2Sgrange
450fd6afa2Sgrange int gscpm_match(struct device *, void *, void *);
460fd6afa2Sgrange void gscpm_attach(struct device *, struct device *, void *);
470fd6afa2Sgrange
4896773847Sdim void gscpm_setperf(int);
490fd6afa2Sgrange
500fd6afa2Sgrange u_int gscpm_get_timecount(struct timecounter *tc);
510fd6afa2Sgrange
520fd6afa2Sgrange struct timecounter gscpm_timecounter = {
538611d3cdScheloha .tc_get_timecount = gscpm_get_timecount,
548611d3cdScheloha .tc_counter_mask = 0xffffff,
558611d3cdScheloha .tc_frequency = 3579545,
568611d3cdScheloha .tc_name = "GSCPM",
578611d3cdScheloha .tc_quality = 1000,
588611d3cdScheloha .tc_priv = NULL,
598611d3cdScheloha .tc_user = 0,
600fd6afa2Sgrange };
610fd6afa2Sgrange
627769e6a4Smpi const struct cfattach gscpm_ca = {
630fd6afa2Sgrange sizeof (struct gscpm_softc),
640fd6afa2Sgrange gscpm_match,
650fd6afa2Sgrange gscpm_attach
660fd6afa2Sgrange };
670fd6afa2Sgrange
680fd6afa2Sgrange struct cfdriver gscpm_cd = {
690fd6afa2Sgrange NULL, "gscpm", DV_DULL
700fd6afa2Sgrange };
710fd6afa2Sgrange
720fd6afa2Sgrange #if 0
730fd6afa2Sgrange static void *gscpm_cookie; /* XXX */
740fd6afa2Sgrange #endif
750fd6afa2Sgrange
760fd6afa2Sgrange int
gscpm_match(struct device * parent,void * match,void * aux)770fd6afa2Sgrange gscpm_match(struct device *parent, void *match, void *aux)
780fd6afa2Sgrange {
790fd6afa2Sgrange struct pci_attach_args *pa = aux;
800fd6afa2Sgrange
810fd6afa2Sgrange if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS &&
820fd6afa2Sgrange PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SC1100_SMI)
830fd6afa2Sgrange return (1);
840fd6afa2Sgrange
850fd6afa2Sgrange return (0);
860fd6afa2Sgrange }
870fd6afa2Sgrange
880fd6afa2Sgrange void
gscpm_attach(struct device * parent,struct device * self,void * aux)890fd6afa2Sgrange gscpm_attach(struct device *parent, struct device *self, void *aux)
900fd6afa2Sgrange {
910fd6afa2Sgrange struct gscpm_softc *sc = (struct gscpm_softc *)self;
920fd6afa2Sgrange struct pci_attach_args *pa = aux;
930fd6afa2Sgrange pcireg_t csr, acpibase;
940fd6afa2Sgrange
950fd6afa2Sgrange sc->sc_pc = pa->pa_pc;
960fd6afa2Sgrange sc->sc_tag = pa->pa_tag;
970fd6afa2Sgrange sc->sc_iot = pa->pa_iot;
980fd6afa2Sgrange
990fd6afa2Sgrange /* Enable I/O space */
1000fd6afa2Sgrange csr = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
1010fd6afa2Sgrange pci_conf_write(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG,
1020fd6afa2Sgrange csr | PCI_COMMAND_IO_ENABLE);
1030fd6afa2Sgrange
1040fd6afa2Sgrange /* Map ACPI registers */
1050fd6afa2Sgrange acpibase = pci_conf_read(sc->sc_pc, sc->sc_tag, GSCPM_ACPIBASE);
1063d57c359Sderaadt if (PCI_MAPREG_IO_ADDR(acpibase) == 0 ||
1073d57c359Sderaadt bus_space_map(sc->sc_iot, PCI_MAPREG_IO_ADDR(acpibase),
1080fd6afa2Sgrange GSCPM_ACPISIZE, 0, &sc->sc_acpi_ioh)) {
1090fd6afa2Sgrange printf(": failed to map ACPI registers\n");
1100fd6afa2Sgrange return;
1110fd6afa2Sgrange }
1120fd6afa2Sgrange
1130fd6afa2Sgrange printf("\n");
1140fd6afa2Sgrange
1150fd6afa2Sgrange /* Hook into the kern_tc */
1160fd6afa2Sgrange gscpm_timecounter.tc_priv = sc;
1170fd6afa2Sgrange tc_init(&gscpm_timecounter);
1180fd6afa2Sgrange
1190fd6afa2Sgrange /* XXX: disabled due to unresolved yet hardware errata */
1200fd6afa2Sgrange #if 0
1210fd6afa2Sgrange /* Hook into the hw.setperf sysctl */
1220fd6afa2Sgrange gscpm_cookie = sc;
1230fd6afa2Sgrange cpu_setperf = gscpm_setperf;
1240fd6afa2Sgrange #endif
1250fd6afa2Sgrange
1260fd6afa2Sgrange }
1270fd6afa2Sgrange
1280fd6afa2Sgrange u_int
gscpm_get_timecount(struct timecounter * tc)1290fd6afa2Sgrange gscpm_get_timecount(struct timecounter *tc)
1300fd6afa2Sgrange {
1310fd6afa2Sgrange struct gscpm_softc *sc = tc->tc_priv;
1320fd6afa2Sgrange
133b6a7f1efSmickey return (bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_PM_TMR));
1340fd6afa2Sgrange }
1350fd6afa2Sgrange
1360fd6afa2Sgrange #if 0
13796773847Sdim void
1380fd6afa2Sgrange gscpm_setperf(int level)
1390fd6afa2Sgrange {
1400fd6afa2Sgrange struct gscpm_softc *sc = gscpm_cookie;
1410fd6afa2Sgrange int i;
1420fd6afa2Sgrange u_int32_t pctl;
1430fd6afa2Sgrange
1440fd6afa2Sgrange pctl = bus_space_read_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT);
1450fd6afa2Sgrange
1460fd6afa2Sgrange if (level == 100) {
14736fd90dcSjsg /* 100 is a maximum performance, disable throttling */
1480fd6afa2Sgrange pctl &= ~GSCPM_P_CNT_THTEN;
1490fd6afa2Sgrange } else {
1500fd6afa2Sgrange for (i = 0; i < GSCPM_THT_LEVELS; i++)
1510fd6afa2Sgrange if (level >= gscpm_tht[i].level)
1520fd6afa2Sgrange break;
1530fd6afa2Sgrange pctl = (0xf0 | GSCPM_P_CNT_THTEN |
1540fd6afa2Sgrange GSCPM_P_CNT_CLK(gscpm_tht[i].value));
1550fd6afa2Sgrange }
1560fd6afa2Sgrange
1570fd6afa2Sgrange /* Update processor control register */
1580fd6afa2Sgrange bus_space_write_4(sc->sc_iot, sc->sc_acpi_ioh, GSCPM_P_CNT, pctl);
1590fd6afa2Sgrange }
1600fd6afa2Sgrange #endif
161