xref: /openbsd/sys/dev/pci/amdpcib.c (revision 09467b48)
1 /*      $OpenBSD: amdpcib.c,v 1.3 2015/03/14 03:38:48 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
16  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * AMD8111 series LPC bridge also containing HPET and watchdog
22  */
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/device.h>
27 #include <sys/timetc.h>
28 
29 #include <machine/bus.h>
30 
31 #include <dev/pci/pcivar.h>
32 #include <dev/pci/pcidevs.h>
33 
34 #define	AMD8111_HPET	0xa0	/* PCI config space */
35 #define	AMD8111_HPET_ENA	0x00000001
36 #define	AMD8111_HPET_BASE	0xfffffc00
37 #define	AMD8111_HPET_SIZE	0x00000400
38 
39 #define	AMD8111_HPET_ID		0x000
40 #define	AMD8111_HPET_WIDTH	0x00002000
41 #define	AMD8111_HPET_REV	0x000000ff
42 #define	AMD8111_HPET_PERIOD	0x004
43 #define	AMD8111_HPET_CFG	0x010
44 #define	AMD8111_HPET_CFG_GIEN	0x00000001
45 #define	AMD8111_HPET_ISTAT	0x020
46 #define	AMD8111_HPET_MAIN	0x0f0
47 #define	AMD8111_HPET_T0CFG	0x100
48 #define	AMD8111_HPET_T0CMP	0x108
49 #define	AMD8111_HPET_T1CFG	0x120
50 #define	AMD8111_HPET_T1CMP	0x128
51 #define	AMD8111_HPET_T2CFG	0x140
52 #define	AMD8111_HPET_T2CMP	0x148
53 
54 #define	AMD8111_WDOG	0xa8	/* PCI config space */
55 #define	AMD8111_WDOG_ENA	0x00000001
56 #define	AMD8111_WDOG_HALT	0x00000002
57 #define	AMD8111_WDOG_SILENT	0x00000004
58 #define	AMD8111_WDOG_BASE	0xffffffe0
59 
60 #define	AMD8111_WDOG_CTRL	0x00
61 #define	AMD8111_WDOG_RSTOP	0x0001
62 #define	AMD8111_WDOG_WFIR	0x0002
63 #define	AMD8111_WDOG_WACT	0x0004
64 #define	AMD8111_WDOG_WDALIAS	0x0008
65 #define	AMD8111_WDOG_WTRIG	0x0080
66 #define	AMD8111_WDOG_COUNT	0x08
67 #define	AMD8111_WDOG_MASK	0xffff
68 
69 struct amdpcib_softc {
70 	struct device sc_dev;
71 
72 	bus_space_tag_t sc_hpet_iot;
73 	bus_space_handle_t sc_hpet_ioh;
74 	struct timecounter sc_hpet_timecounter;
75 };
76 
77 struct cfdriver amdpcib_cd = {
78 	NULL, "amdpcib", DV_DULL
79 };
80 
81 int	amdpcib_match(struct device *, void *, void *);
82 void	amdpcib_attach(struct device *, struct device *, void *);
83 
84 struct cfattach amdpcib_ca = {
85 	sizeof(struct amdpcib_softc), amdpcib_match, amdpcib_attach
86 };
87 
88 /* from arch/<*>/pci/pcib.c */
89 void	pcibattach(struct device *parent, struct device *self, void *aux);
90 
91 u_int	amdpcib_get_timecount(struct timecounter *tc);
92 
93 const struct pci_matchid amdpcib_devices[] = {
94 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_PBC8111_LPC }
95 	/* also available on 590 and 690 chipsets */
96 };
97 
98 int
99 amdpcib_match(struct device *parent, void *match, void *aux)
100 {
101 	if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices,
102 	    sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0])))
103 		return 2;
104 
105 	return 0;
106 }
107 
108 void
109 amdpcib_attach(struct device *parent, struct device *self, void *aux)
110 {
111         struct amdpcib_softc *sc = (struct amdpcib_softc *)self;
112 	struct pci_attach_args *pa = aux;
113 	struct timecounter *tc = &sc->sc_hpet_timecounter;
114 	pcireg_t reg;
115 	u_int32_t v;
116 
117 
118 	sc->sc_hpet_iot = pa->pa_memt;
119 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET);
120 	if (reg & AMD8111_HPET_ENA &&
121 	    bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE,
122 	     AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) {
123 
124 		tc->tc_get_timecount = amdpcib_get_timecount;
125 		/* XXX 64-bit counter is not supported! */
126 		tc->tc_counter_mask = 0xffffffff;
127 
128 		v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
129 		    AMD8111_HPET_PERIOD);
130 		/* femtosecs -> Hz */
131 		tc->tc_frequency = 1000000000000000ULL / v;
132 
133 		tc->tc_name = "AMD8111";
134 		tc->tc_quality = 2000;
135 		tc->tc_priv = sc;
136 		tc_init(tc);
137 
138 		/* enable counting */
139 		bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
140 		    AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN);
141 
142 		v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
143 		    AMD8111_HPET_ID);
144 		printf(": %d-bit %lluHz timer rev %d",
145 		    (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency,
146 		    v & AMD8111_HPET_REV);
147 	}
148 
149 	pcibattach(parent, self, aux);
150 }
151 
152 u_int
153 amdpcib_get_timecount(struct timecounter *tc)
154 {
155         struct amdpcib_softc *sc = tc->tc_priv;
156 
157 	/* XXX 64-bit counter is not supported! */
158 	return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
159 	    AMD8111_HPET_MAIN);
160 }
161