xref: /openbsd-src/sys/dev/pci/amdpcib.c (revision 8d2c75e49a1f1e140a0efd2b93f23844e8cb679f)
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