xref: /openbsd-src/sys/dev/pci/amdpcib.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*      $OpenBSD: amdpcib.c,v 1.2 2010/04/20 22:05:43 tedu 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/pcireg.h>
32 #include <dev/pci/pcivar.h>
33 #include <dev/pci/pcidevs.h>
34 
35 #define	AMD8111_HPET	0xa0	/* PCI config space */
36 #define	AMD8111_HPET_ENA	0x00000001
37 #define	AMD8111_HPET_BASE	0xfffffc00
38 #define	AMD8111_HPET_SIZE	0x00000400
39 
40 #define	AMD8111_HPET_ID		0x000
41 #define	AMD8111_HPET_WIDTH	0x00002000
42 #define	AMD8111_HPET_REV	0x000000ff
43 #define	AMD8111_HPET_PERIOD	0x004
44 #define	AMD8111_HPET_CFG	0x010
45 #define	AMD8111_HPET_CFG_GIEN	0x00000001
46 #define	AMD8111_HPET_ISTAT	0x020
47 #define	AMD8111_HPET_MAIN	0x0f0
48 #define	AMD8111_HPET_T0CFG	0x100
49 #define	AMD8111_HPET_T0CMP	0x108
50 #define	AMD8111_HPET_T1CFG	0x120
51 #define	AMD8111_HPET_T1CMP	0x128
52 #define	AMD8111_HPET_T2CFG	0x140
53 #define	AMD8111_HPET_T2CMP	0x148
54 
55 #define	AMD8111_WDOG	0xa8	/* PCI config space */
56 #define	AMD8111_WDOG_ENA	0x00000001
57 #define	AMD8111_WDOG_HALT	0x00000002
58 #define	AMD8111_WDOG_SILENT	0x00000004
59 #define	AMD8111_WDOG_BASE	0xffffffe0
60 
61 #define	AMD8111_WDOG_CTRL	0x00
62 #define	AMD8111_WDOG_RSTOP	0x0001
63 #define	AMD8111_WDOG_WFIR	0x0002
64 #define	AMD8111_WDOG_WACT	0x0004
65 #define	AMD8111_WDOG_WDALIAS	0x0008
66 #define	AMD8111_WDOG_WTRIG	0x0080
67 #define	AMD8111_WDOG_COUNT	0x08
68 #define	AMD8111_WDOG_MASK	0xffff
69 
70 struct amdpcib_softc {
71 	struct device sc_dev;
72 
73 	bus_space_tag_t sc_hpet_iot;
74 	bus_space_handle_t sc_hpet_ioh;
75 	struct timecounter sc_hpet_timecounter;
76 };
77 
78 struct cfdriver amdpcib_cd = {
79 	NULL, "amdpcib", DV_DULL
80 };
81 
82 int	amdpcib_match(struct device *, void *, void *);
83 void	amdpcib_attach(struct device *, struct device *, void *);
84 
85 struct cfattach amdpcib_ca = {
86 	sizeof(struct amdpcib_softc), amdpcib_match, amdpcib_attach
87 };
88 
89 /* from arch/<*>/pci/pcib.c */
90 void	pcibattach(struct device *parent, struct device *self, void *aux);
91 
92 u_int	amdpcib_get_timecount(struct timecounter *tc);
93 
94 const struct pci_matchid amdpcib_devices[] = {
95 	{ PCI_VENDOR_AMD,	PCI_PRODUCT_AMD_PBC8111_LPC }
96 	/* also available on 590 and 690 chipsets */
97 };
98 
99 int
100 amdpcib_match(struct device *parent, void *match, void *aux)
101 {
102 	if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices,
103 	    sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0])))
104 		return 2;
105 
106 	return 0;
107 }
108 
109 void
110 amdpcib_attach(struct device *parent, struct device *self, void *aux)
111 {
112         struct amdpcib_softc *sc = (struct amdpcib_softc *)self;
113 	struct pci_attach_args *pa = aux;
114 	struct timecounter *tc = &sc->sc_hpet_timecounter;
115 	pcireg_t reg;
116 	u_int32_t v;
117 
118 
119 	sc->sc_hpet_iot = pa->pa_memt;
120 	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET);
121 	if (reg & AMD8111_HPET_ENA &&
122 	    bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE,
123 	     AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) {
124 
125 		tc->tc_get_timecount = amdpcib_get_timecount;
126 		/* XXX 64-bit counter is not supported! */
127 		tc->tc_counter_mask = 0xffffffff;
128 
129 		v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
130 		    AMD8111_HPET_PERIOD);
131 		/* femtosecs -> Hz */
132 		tc->tc_frequency = 1000000000000000ULL / v;
133 
134 		tc->tc_name = "AMD8111";
135 		tc->tc_quality = 2000;
136 		tc->tc_priv = sc;
137 		tc_init(tc);
138 
139 		/* enable counting */
140 		bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
141 		    AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN);
142 
143 		v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
144 		    AMD8111_HPET_ID);
145 		printf(": %d-bit %lluHz timer rev %d",
146 		    (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency,
147 		    v & AMD8111_HPET_REV);
148 	}
149 
150 	pcibattach(parent, self, aux);
151 }
152 
153 u_int
154 amdpcib_get_timecount(struct timecounter *tc)
155 {
156         struct amdpcib_softc *sc = tc->tc_priv;
157 
158 	/* XXX 64-bit counter is not supported! */
159 	return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
160 	    AMD8111_HPET_MAIN);
161 }
162