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