Line data Source code
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 0 : amdpcib_match(struct device *parent, void *match, void *aux)
100 : {
101 0 : if (pci_matchbyid((struct pci_attach_args *)aux, amdpcib_devices,
102 : sizeof(amdpcib_devices) / sizeof(amdpcib_devices[0])))
103 0 : return 2;
104 :
105 0 : return 0;
106 0 : }
107 :
108 : void
109 0 : amdpcib_attach(struct device *parent, struct device *self, void *aux)
110 : {
111 0 : struct amdpcib_softc *sc = (struct amdpcib_softc *)self;
112 0 : struct pci_attach_args *pa = aux;
113 0 : struct timecounter *tc = &sc->sc_hpet_timecounter;
114 : pcireg_t reg;
115 : u_int32_t v;
116 :
117 :
118 0 : sc->sc_hpet_iot = pa->pa_memt;
119 0 : reg = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_HPET);
120 0 : if (reg & AMD8111_HPET_ENA &&
121 0 : bus_space_map(sc->sc_hpet_iot, reg & AMD8111_HPET_BASE,
122 0 : AMD8111_HPET_SIZE, 0, &sc->sc_hpet_ioh) == 0) {
123 :
124 0 : tc->tc_get_timecount = amdpcib_get_timecount;
125 : /* XXX 64-bit counter is not supported! */
126 0 : tc->tc_counter_mask = 0xffffffff;
127 :
128 0 : v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
129 : AMD8111_HPET_PERIOD);
130 : /* femtosecs -> Hz */
131 0 : tc->tc_frequency = 1000000000000000ULL / v;
132 :
133 0 : tc->tc_name = "AMD8111";
134 0 : tc->tc_quality = 2000;
135 0 : tc->tc_priv = sc;
136 0 : tc_init(tc);
137 :
138 : /* enable counting */
139 0 : bus_space_write_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
140 : AMD8111_HPET_CFG, AMD8111_HPET_CFG_GIEN);
141 :
142 0 : v = bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
143 : AMD8111_HPET_ID);
144 0 : printf(": %d-bit %lluHz timer rev %d",
145 0 : (v & AMD8111_HPET_WIDTH? 64 : 32), tc->tc_frequency,
146 0 : v & AMD8111_HPET_REV);
147 0 : }
148 :
149 0 : pcibattach(parent, self, aux);
150 0 : }
151 :
152 : u_int
153 0 : amdpcib_get_timecount(struct timecounter *tc)
154 : {
155 0 : struct amdpcib_softc *sc = tc->tc_priv;
156 :
157 : /* XXX 64-bit counter is not supported! */
158 0 : return bus_space_read_4(sc->sc_hpet_iot, sc->sc_hpet_ioh,
159 : AMD8111_HPET_MAIN);
160 : }
|