1*8d2c75e4Smpi /* $OpenBSD: amdpcib.c,v 1.4 2022/03/11 18:00:45 mpi Exp $ */
20676a2deSmbalmer
30676a2deSmbalmer /*
40676a2deSmbalmer * Copyright (c) 2007 Michael Shalayeff
50676a2deSmbalmer * All rights reserved.
60676a2deSmbalmer *
70676a2deSmbalmer * Permission to use, copy, modify, and distribute this software for any
80676a2deSmbalmer * purpose with or without fee is hereby granted, provided that the above
90676a2deSmbalmer * copyright notice and this permission notice appear in all copies.
100676a2deSmbalmer *
110676a2deSmbalmer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
120676a2deSmbalmer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
130676a2deSmbalmer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
140676a2deSmbalmer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
150676a2deSmbalmer * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
160676a2deSmbalmer * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
170676a2deSmbalmer * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
180676a2deSmbalmer */
190676a2deSmbalmer
200676a2deSmbalmer /*
210676a2deSmbalmer * AMD8111 series LPC bridge also containing HPET and watchdog
220676a2deSmbalmer */
230676a2deSmbalmer
240676a2deSmbalmer #include <sys/param.h>
250676a2deSmbalmer #include <sys/systm.h>
260676a2deSmbalmer #include <sys/device.h>
270676a2deSmbalmer #include <sys/timetc.h>
280676a2deSmbalmer
290676a2deSmbalmer #include <machine/bus.h>
300676a2deSmbalmer
310676a2deSmbalmer #include <dev/pci/pcivar.h>
320676a2deSmbalmer #include <dev/pci/pcidevs.h>
330676a2deSmbalmer
340676a2deSmbalmer #define AMD8111_HPET 0xa0 /* PCI config space */
350676a2deSmbalmer #define AMD8111_HPET_ENA 0x00000001
360676a2deSmbalmer #define AMD8111_HPET_BASE 0xfffffc00
370676a2deSmbalmer #define AMD8111_HPET_SIZE 0x00000400
380676a2deSmbalmer
390676a2deSmbalmer #define AMD8111_HPET_ID 0x000
400676a2deSmbalmer #define AMD8111_HPET_WIDTH 0x00002000
410676a2deSmbalmer #define AMD8111_HPET_REV 0x000000ff
420676a2deSmbalmer #define AMD8111_HPET_PERIOD 0x004
430676a2deSmbalmer #define AMD8111_HPET_CFG 0x010
440676a2deSmbalmer #define AMD8111_HPET_CFG_GIEN 0x00000001
450676a2deSmbalmer #define AMD8111_HPET_ISTAT 0x020
460676a2deSmbalmer #define AMD8111_HPET_MAIN 0x0f0
470676a2deSmbalmer #define AMD8111_HPET_T0CFG 0x100
480676a2deSmbalmer #define AMD8111_HPET_T0CMP 0x108
490676a2deSmbalmer #define AMD8111_HPET_T1CFG 0x120
500676a2deSmbalmer #define AMD8111_HPET_T1CMP 0x128
510676a2deSmbalmer #define AMD8111_HPET_T2CFG 0x140
520676a2deSmbalmer #define AMD8111_HPET_T2CMP 0x148
530676a2deSmbalmer
540676a2deSmbalmer #define AMD8111_WDOG 0xa8 /* PCI config space */
550676a2deSmbalmer #define AMD8111_WDOG_ENA 0x00000001
560676a2deSmbalmer #define AMD8111_WDOG_HALT 0x00000002
570676a2deSmbalmer #define AMD8111_WDOG_SILENT 0x00000004
580676a2deSmbalmer #define AMD8111_WDOG_BASE 0xffffffe0
590676a2deSmbalmer
600676a2deSmbalmer #define AMD8111_WDOG_CTRL 0x00
610676a2deSmbalmer #define AMD8111_WDOG_RSTOP 0x0001
620676a2deSmbalmer #define AMD8111_WDOG_WFIR 0x0002
630676a2deSmbalmer #define AMD8111_WDOG_WACT 0x0004
640676a2deSmbalmer #define AMD8111_WDOG_WDALIAS 0x0008
650676a2deSmbalmer #define AMD8111_WDOG_WTRIG 0x0080
660676a2deSmbalmer #define AMD8111_WDOG_COUNT 0x08
670676a2deSmbalmer #define AMD8111_WDOG_MASK 0xffff
680676a2deSmbalmer
690676a2deSmbalmer struct amdpcib_softc {
700676a2deSmbalmer struct device sc_dev;
710676a2deSmbalmer
720676a2deSmbalmer bus_space_tag_t sc_hpet_iot;
730676a2deSmbalmer bus_space_handle_t sc_hpet_ioh;
740676a2deSmbalmer struct timecounter sc_hpet_timecounter;
750676a2deSmbalmer };
760676a2deSmbalmer
770676a2deSmbalmer struct cfdriver amdpcib_cd = {
780676a2deSmbalmer NULL, "amdpcib", DV_DULL
790676a2deSmbalmer };
800676a2deSmbalmer
810676a2deSmbalmer int amdpcib_match(struct device *, void *, void *);
820676a2deSmbalmer void amdpcib_attach(struct device *, struct device *, void *);
830676a2deSmbalmer
84*8d2c75e4Smpi const struct cfattach amdpcib_ca = {
850676a2deSmbalmer sizeof(struct amdpcib_softc), amdpcib_match, amdpcib_attach
860676a2deSmbalmer };
870676a2deSmbalmer
880676a2deSmbalmer /* from arch/<*>/pci/pcib.c */
890676a2deSmbalmer void pcibattach(struct device *parent, struct device *self, void *aux);
900676a2deSmbalmer
910676a2deSmbalmer u_int amdpcib_get_timecount(struct timecounter *tc);
920676a2deSmbalmer
930676a2deSmbalmer const struct pci_matchid amdpcib_devices[] = {
940676a2deSmbalmer { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC8111_LPC }
950676a2deSmbalmer /* also available on 590 and 690 chipsets */
960676a2deSmbalmer };
970676a2deSmbalmer
980676a2deSmbalmer int
amdpcib_match(struct device * parent,void * match,void * aux)990676a2deSmbalmer amdpcib_match(struct device *parent, void *match, void *aux)
1000676a2deSmbalmer {
1010676a2deSmbalmer if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices,
1020676a2deSmbalmer sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0])))
1030676a2deSmbalmer return 2;
1040676a2deSmbalmer
1050676a2deSmbalmer return 0;
1060676a2deSmbalmer }
1070676a2deSmbalmer
1080676a2deSmbalmer void
amdpcib_attach(struct device * parent,struct device * self,void * aux)1090676a2deSmbalmer amdpcib_attach(struct device *parent, struct device *self, void *aux)
1100676a2deSmbalmer {
1110676a2deSmbalmer struct amdpcib_softc *sc = (struct amdpcib_softc *)self;
1120676a2deSmbalmer struct pci_attach_args *pa = aux;
1130676a2deSmbalmer struct timecounter *tc = &sc->sc_hpet_timecounter;
1140676a2deSmbalmer pcireg_t reg;
1150676a2deSmbalmer u_int32_t v;
1160676a2deSmbalmer
1170676a2deSmbalmer
1180676a2deSmbalmer sc->sc_hpet_iot = pa->pa_memt;
1190676a2deSmbalmer reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET);
1200676a2deSmbalmer if (reg & AMD8111_HPET_ENA &&
1210676a2deSmbalmer bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE,
1220676a2deSmbalmer AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) {
1230676a2deSmbalmer
1240676a2deSmbalmer tc->tc_get_timecount = amdpcib_get_timecount;
1250676a2deSmbalmer /* XXX 64-bit counter is not supported! */
1260676a2deSmbalmer tc->tc_counter_mask = 0xffffffff;
1270676a2deSmbalmer
1280676a2deSmbalmer v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
1290676a2deSmbalmer AMD8111_HPET_PERIOD);
1300676a2deSmbalmer /* femtosecs -> Hz */
1310676a2deSmbalmer tc->tc_frequency = 1000000000000000ULL / v;
1320676a2deSmbalmer
1330676a2deSmbalmer tc->tc_name = "AMD8111";
1340676a2deSmbalmer tc->tc_quality = 2000;
1350676a2deSmbalmer tc->tc_priv = sc;
1360676a2deSmbalmer tc_init(tc);
1370676a2deSmbalmer
1380676a2deSmbalmer /* enable counting */
1390676a2deSmbalmer bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
1400676a2deSmbalmer AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN);
1410676a2deSmbalmer
1420676a2deSmbalmer v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
1430676a2deSmbalmer AMD8111_HPET_ID);
1440676a2deSmbalmer printf(": %d-bit %lluHz timer rev %d",
1450676a2deSmbalmer (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency,
1460676a2deSmbalmer v & AMD8111_HPET_REV);
1470676a2deSmbalmer }
1480676a2deSmbalmer
1490676a2deSmbalmer pcibattach(parent, self, aux);
1500676a2deSmbalmer }
1510676a2deSmbalmer
1520676a2deSmbalmer u_int
amdpcib_get_timecount(struct timecounter * tc)1530676a2deSmbalmer amdpcib_get_timecount(struct timecounter *tc)
1540676a2deSmbalmer {
1550676a2deSmbalmer struct amdpcib_softc *sc = tc->tc_priv;
1560676a2deSmbalmer
1570676a2deSmbalmer /* XXX 64-bit counter is not supported! */
1580676a2deSmbalmer return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
1590676a2deSmbalmer AMD8111_HPET_MAIN);
1600676a2deSmbalmer }
161