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