Lines 55-82
__FBSDID("$FreeBSD: src/sys/x86/isa/atrt
Link Here
|
55 |
#define RTC_LOCK mtx_lock_spin(&clock_lock) |
55 |
#define RTC_LOCK mtx_lock_spin(&clock_lock) |
56 |
#define RTC_UNLOCK mtx_unlock_spin(&clock_lock) |
56 |
#define RTC_UNLOCK mtx_unlock_spin(&clock_lock) |
57 |
|
57 |
|
|
|
58 |
/* atrtcclock_disable is set to 1 by apm_attach() or by hint.atrtc.0.clock=0 */ |
58 |
int atrtcclock_disable = 0; |
59 |
int atrtcclock_disable = 0; |
59 |
|
60 |
|
60 |
static int rtc_reg = -1; |
61 |
static int use_iodelay = 0; /* set from hint.atrtc.0.use_iodelay */ |
61 |
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; |
62 |
|
62 |
static u_char rtc_statusb = RTCSB_24HR; |
63 |
#define RTC_REINDEX_REQUIRED 0xffU |
|
|
64 |
#define NMI_ENABLE_BIT 0x80U |
65 |
|
66 |
static u_char nmi_enable; |
67 |
static u_char rtc_reg = RTC_REINDEX_REQUIRED; |
68 |
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; |
69 |
static u_char rtc_statusb = RTCSB_24HR; |
70 |
|
71 |
/* |
72 |
* Delay after writing to IO_RTC[+1] registers. Modern hardware doesn't |
73 |
* require this expensive delay, so it's a tuneable that's disabled by default. |
74 |
*/ |
75 |
static __inline void |
76 |
rtc_iodelay(void) |
77 |
{ |
78 |
if (use_iodelay) |
79 |
inb(0x84); |
80 |
} |
63 |
|
81 |
|
64 |
/* |
82 |
/* |
65 |
* RTC support routines |
83 |
* RTC support routines |
|
|
84 |
* |
85 |
* Most rtc chipsets let you write a value into the index register and then each |
86 |
* read of the IO register obtains a new value from the indexed location. Others |
87 |
* behave as if they latch the indexed value when you write to the index, and |
88 |
* repeated reads keep returning the same value until you write to the index |
89 |
* register again. atrtc_start() probes for this behavior and leaves rtc_reg |
90 |
* set to RTC_REINDEX_REQUIRED if reads keep returning the same value. |
66 |
*/ |
91 |
*/ |
67 |
|
92 |
|
|
|
93 |
static __inline void |
94 |
rtcindex(u_char reg) |
95 |
{ |
96 |
if (rtc_reg != reg) { |
97 |
if (rtc_reg != RTC_REINDEX_REQUIRED) |
98 |
rtc_reg = reg; |
99 |
outb(IO_RTC, reg | nmi_enable); |
100 |
rtc_iodelay(); |
101 |
} |
102 |
} |
103 |
|
68 |
int |
104 |
int |
69 |
rtcin(int reg) |
105 |
rtcin(int reg) |
70 |
{ |
106 |
{ |
71 |
u_char val; |
107 |
u_char val; |
72 |
|
108 |
|
73 |
RTC_LOCK; |
109 |
RTC_LOCK; |
74 |
if (rtc_reg != reg) { |
110 |
rtcindex(reg); |
75 |
inb(0x84); |
|
|
76 |
outb(IO_RTC, reg); |
77 |
rtc_reg = reg; |
78 |
inb(0x84); |
79 |
} |
80 |
val = inb(IO_RTC + 1); |
111 |
val = inb(IO_RTC + 1); |
81 |
RTC_UNLOCK; |
112 |
RTC_UNLOCK; |
82 |
return (val); |
113 |
return (val); |
Lines 87-100
writertc(int reg, u_char val)
Link Here
|
87 |
{ |
118 |
{ |
88 |
|
119 |
|
89 |
RTC_LOCK; |
120 |
RTC_LOCK; |
90 |
if (rtc_reg != reg) { |
121 |
rtcindex(reg); |
91 |
inb(0x84); |
|
|
92 |
outb(IO_RTC, reg); |
93 |
rtc_reg = reg; |
94 |
inb(0x84); |
95 |
} |
96 |
outb(IO_RTC + 1, val); |
122 |
outb(IO_RTC + 1, val); |
97 |
inb(0x84); |
123 |
rtc_iodelay(); |
98 |
RTC_UNLOCK; |
124 |
RTC_UNLOCK; |
99 |
} |
125 |
} |
100 |
|
126 |
|
Lines 104-115
readrtc(int port)
Link Here
|
104 |
return(bcd2bin(rtcin(port))); |
130 |
return(bcd2bin(rtcin(port))); |
105 |
} |
131 |
} |
106 |
|
132 |
|
|
|
133 |
/* |
134 |
* At start, probe read-without-reindex behavior. Reading RTC_INTR clears it; |
135 |
* read until it has a non-zero value, then read it again without re-writing the |
136 |
* index register. If 2nd read returns a different value it's safe to cache the |
137 |
* current index with this chipset; enable by changing rtc_reg to current index. |
138 |
*/ |
107 |
static void |
139 |
static void |
108 |
atrtc_start(void) |
140 |
atrtc_start(void) |
109 |
{ |
141 |
{ |
|
|
142 |
int status; |
110 |
|
143 |
|
111 |
writertc(RTC_STATUSA, rtc_statusa); |
144 |
writertc(RTC_STATUSA, RTCSA_DIVIDER | RTCSA_8192); |
112 |
writertc(RTC_STATUSB, RTCSB_24HR); |
145 |
writertc(RTC_STATUSB, RTCSB_24HR); |
|
|
146 |
|
147 |
RTC_LOCK; |
148 |
do { |
149 |
rtcindex(RTC_INTR); |
150 |
status = inb(IO_RTC+1); |
151 |
} while (status == 0); |
152 |
|
153 |
if (status != inb(IO_RTC+1)) |
154 |
rtc_reg = RTC_INTR; |
155 |
RTC_UNLOCK; |
156 |
|
157 |
writertc(RTC_STATUSA, RTCSA_DIVIDER | RTCSA_NOPROF); |
113 |
} |
158 |
} |
114 |
|
159 |
|
115 |
static void |
160 |
static void |
Lines 139-144
atrtc_disable_intr(void)
Link Here
|
139 |
} |
184 |
} |
140 |
|
185 |
|
141 |
void |
186 |
void |
|
|
187 |
atrtc_nmi_enable(int enable) |
188 |
{ |
189 |
/* Must not write to 0x70 without a following read or write of 0x71 on |
190 |
* some chipsets, so do a read. Also, must access a register other than |
191 |
* the current rtc_reg to force rtcin to push a change out to 0x70. |
192 |
*/ |
193 |
nmi_enable = enable ? NMI_ENABLE_BIT : 0x00; |
194 |
rtcin((rtc_reg == RTC_STATUSA) ? RTC_STATUSB : RTC_STATUSA); |
195 |
} |
196 |
|
197 |
void |
142 |
atrtc_restore(void) |
198 |
atrtc_restore(void) |
143 |
{ |
199 |
{ |
144 |
|
200 |
|
Lines 249-254
atrtc_attach(device_t dev)
Link Here
|
249 |
IO_RTC, IO_RTC + 1, 2, RF_ACTIVE); |
305 |
IO_RTC, IO_RTC + 1, 2, RF_ACTIVE); |
250 |
if (sc->port_res == NULL) |
306 |
if (sc->port_res == NULL) |
251 |
device_printf(dev, "Warning: Couldn't map I/O.\n"); |
307 |
device_printf(dev, "Warning: Couldn't map I/O.\n"); |
|
|
308 |
resource_int_value("atrtc", 0, "use_iodelay", &use_iodelay); |
252 |
atrtc_start(); |
309 |
atrtc_start(); |
253 |
clock_register(dev, 1000000); |
310 |
clock_register(dev, 1000000); |
254 |
bzero(&sc->et, sizeof(struct eventtimer)); |
311 |
bzero(&sc->et, sizeof(struct eventtimer)); |