rtc.c revision 1.2.6.2 1 1.2.6.2 jdolecek /* $NetBSD: rtc.c,v 1.2.6.2 2017/12/03 11:36:10 jdolecek Exp $ */
2 1.2.6.2 jdolecek
3 1.2.6.2 jdolecek /*
4 1.2.6.2 jdolecek * Copyright 2002 Wasabi Systems, Inc.
5 1.2.6.2 jdolecek * All rights reserved.
6 1.2.6.2 jdolecek *
7 1.2.6.2 jdolecek * Written by Simon Burge for Wasabi Systems, Inc.
8 1.2.6.2 jdolecek *
9 1.2.6.2 jdolecek * Redistribution and use in source and binary forms, with or without
10 1.2.6.2 jdolecek * modification, are permitted provided that the following conditions
11 1.2.6.2 jdolecek * are met:
12 1.2.6.2 jdolecek * 1. Redistributions of source code must retain the above copyright
13 1.2.6.2 jdolecek * notice, this list of conditions and the following disclaimer.
14 1.2.6.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
15 1.2.6.2 jdolecek * notice, this list of conditions and the following disclaimer in the
16 1.2.6.2 jdolecek * documentation and/or other materials provided with the distribution.
17 1.2.6.2 jdolecek * 3. All advertising materials mentioning features or use of this software
18 1.2.6.2 jdolecek * must display the following acknowledgement:
19 1.2.6.2 jdolecek * This product includes software developed for the NetBSD Project by
20 1.2.6.2 jdolecek * Wasabi Systems, Inc.
21 1.2.6.2 jdolecek * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.2.6.2 jdolecek * or promote products derived from this software without specific prior
23 1.2.6.2 jdolecek * written permission.
24 1.2.6.2 jdolecek *
25 1.2.6.2 jdolecek * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.2.6.2 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.2.6.2 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.2.6.2 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.2.6.2 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.2.6.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.2.6.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.2.6.2 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.2.6.2 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.2.6.2 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.2.6.2 jdolecek * POSSIBILITY OF SUCH DAMAGE.
36 1.2.6.2 jdolecek */
37 1.2.6.2 jdolecek
38 1.2.6.2 jdolecek #include <sys/cdefs.h>
39 1.2.6.2 jdolecek __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.2.6.2 2017/12/03 11:36:10 jdolecek Exp $");
40 1.2.6.2 jdolecek
41 1.2.6.2 jdolecek #include <sys/param.h>
42 1.2.6.2 jdolecek #include <sys/device.h>
43 1.2.6.2 jdolecek #include <sys/kernel.h>
44 1.2.6.2 jdolecek #include <sys/systm.h>
45 1.2.6.2 jdolecek #include <sys/cpu.h>
46 1.2.6.2 jdolecek
47 1.2.6.2 jdolecek #include <dev/clock_subr.h>
48 1.2.6.2 jdolecek
49 1.2.6.2 jdolecek #include <evbmips/sbmips/swarm.h>
50 1.2.6.2 jdolecek #include <evbmips/sbmips/systemsw.h>
51 1.2.6.2 jdolecek
52 1.2.6.2 jdolecek #include <mips/locore.h>
53 1.2.6.2 jdolecek #include <mips/sibyte/dev/sbsmbusvar.h>
54 1.2.6.2 jdolecek
55 1.2.6.2 jdolecek #include <dev/smbus/m41t81reg.h>
56 1.2.6.2 jdolecek #include <dev/smbus/x1241reg.h>
57 1.2.6.2 jdolecek
58 1.2.6.2 jdolecek struct rtc_softc {
59 1.2.6.2 jdolecek device_t sc_dev;
60 1.2.6.2 jdolecek int sc_smbus_chan;
61 1.2.6.2 jdolecek int sc_smbus_addr;
62 1.2.6.2 jdolecek int sc_type;
63 1.2.6.2 jdolecek struct todr_chip_handle sc_ct;
64 1.2.6.2 jdolecek };
65 1.2.6.2 jdolecek
66 1.2.6.2 jdolecek /* "types" for RTCs we support */
67 1.2.6.2 jdolecek #define SMB_1BYTE_ADDR 1
68 1.2.6.2 jdolecek #define SMB_2BYTE_ADDR 2
69 1.2.6.2 jdolecek
70 1.2.6.2 jdolecek static int xirtc_match(device_t, cfdata_t , void *);
71 1.2.6.2 jdolecek static void xirtc_attach(device_t, device_t, void *);
72 1.2.6.2 jdolecek static int xirtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
73 1.2.6.2 jdolecek static int xirtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
74 1.2.6.2 jdolecek
75 1.2.6.2 jdolecek static int strtc_match(device_t, cfdata_t , void *);
76 1.2.6.2 jdolecek static void strtc_attach(device_t, device_t, void *);
77 1.2.6.2 jdolecek static int strtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
78 1.2.6.2 jdolecek static int strtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
79 1.2.6.2 jdolecek
80 1.2.6.2 jdolecek static void rtc_cal_timer(void);
81 1.2.6.2 jdolecek
82 1.2.6.2 jdolecek static void time_smbus_init(int);
83 1.2.6.2 jdolecek static int time_waitready(int);
84 1.2.6.2 jdolecek static int time_readrtc(int, int, int, int);
85 1.2.6.2 jdolecek static int time_writertc(int, int, int, int, int);
86 1.2.6.2 jdolecek
87 1.2.6.2 jdolecek #define WRITERTC(sc, dev, val) \
88 1.2.6.2 jdolecek time_writertc((sc)->sc_smbus_chan, (sc)->sc_smbus_addr, (dev), (sc)->sc_type, (val))
89 1.2.6.2 jdolecek #define READRTC(sc, dev) \
90 1.2.6.2 jdolecek time_readrtc((sc)->sc_smbus_chan, (sc)->sc_smbus_addr, (dev), (sc)->sc_type)
91 1.2.6.2 jdolecek
92 1.2.6.2 jdolecek
93 1.2.6.2 jdolecek CFATTACH_DECL_NEW(xirtc, sizeof(struct rtc_softc),
94 1.2.6.2 jdolecek xirtc_match, xirtc_attach, NULL, NULL);
95 1.2.6.2 jdolecek
96 1.2.6.2 jdolecek CFATTACH_DECL_NEW(m41t81rtc, sizeof(struct rtc_softc),
97 1.2.6.2 jdolecek strtc_match, strtc_attach, NULL, NULL);
98 1.2.6.2 jdolecek
99 1.2.6.2 jdolecek static int rtcfound = 0;
100 1.2.6.2 jdolecek struct rtc_softc *the_rtc;
101 1.2.6.2 jdolecek
102 1.2.6.2 jdolecek /*
103 1.2.6.2 jdolecek * Xicor X1241 RTC support.
104 1.2.6.2 jdolecek */
105 1.2.6.2 jdolecek static int
106 1.2.6.2 jdolecek xirtc_match(device_t parent, cfdata_t cf, void *aux)
107 1.2.6.2 jdolecek {
108 1.2.6.2 jdolecek struct smbus_attach_args *sa = aux;
109 1.2.6.2 jdolecek int ret;
110 1.2.6.2 jdolecek
111 1.2.6.2 jdolecek time_smbus_init(sa->sa_interface);
112 1.2.6.2 jdolecek
113 1.2.6.2 jdolecek if ((sa->sa_interface != X1241_SMBUS_CHAN) ||
114 1.2.6.2 jdolecek (sa->sa_device != X1241_RTC_SLAVEADDR))
115 1.2.6.2 jdolecek return (0);
116 1.2.6.2 jdolecek
117 1.2.6.2 jdolecek ret = time_readrtc(sa->sa_interface, sa->sa_device, SMB_2BYTE_ADDR, X1241REG_SC);
118 1.2.6.2 jdolecek if (ret < 0)
119 1.2.6.2 jdolecek return (0);
120 1.2.6.2 jdolecek
121 1.2.6.2 jdolecek return (!rtcfound);
122 1.2.6.2 jdolecek }
123 1.2.6.2 jdolecek
124 1.2.6.2 jdolecek static void
125 1.2.6.2 jdolecek xirtc_attach(device_t parent, device_t self, void *aux)
126 1.2.6.2 jdolecek {
127 1.2.6.2 jdolecek struct smbus_attach_args *sa = aux;
128 1.2.6.2 jdolecek struct rtc_softc *sc = device_private(self);
129 1.2.6.2 jdolecek
130 1.2.6.2 jdolecek rtcfound = 1;
131 1.2.6.2 jdolecek the_rtc = sc;
132 1.2.6.2 jdolecek
133 1.2.6.2 jdolecek sc->sc_dev = self;
134 1.2.6.2 jdolecek sc->sc_smbus_chan = sa->sa_interface;
135 1.2.6.2 jdolecek sc->sc_smbus_addr = sa->sa_device;
136 1.2.6.2 jdolecek sc->sc_type = SMB_2BYTE_ADDR; /* Two-byte register addresses on the Xicor */
137 1.2.6.2 jdolecek
138 1.2.6.2 jdolecek
139 1.2.6.2 jdolecek /* Set up MI todr(9) stuff */
140 1.2.6.2 jdolecek sc->sc_ct.cookie = sc;
141 1.2.6.2 jdolecek sc->sc_ct.todr_settime_ymdhms = xirtc_settime;
142 1.2.6.2 jdolecek sc->sc_ct.todr_gettime_ymdhms = xirtc_gettime;
143 1.2.6.2 jdolecek
144 1.2.6.2 jdolecek todr_attach(&sc->sc_ct);
145 1.2.6.2 jdolecek
146 1.2.6.2 jdolecek aprint_normal("\n");
147 1.2.6.2 jdolecek rtc_cal_timer(); /* XXX */
148 1.2.6.2 jdolecek }
149 1.2.6.2 jdolecek
150 1.2.6.2 jdolecek static int
151 1.2.6.2 jdolecek xirtc_settime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
152 1.2.6.2 jdolecek {
153 1.2.6.2 jdolecek struct rtc_softc *sc = handle->cookie;
154 1.2.6.2 jdolecek uint8_t year, y2k;
155 1.2.6.2 jdolecek
156 1.2.6.2 jdolecek time_smbus_init(sc->sc_smbus_chan);
157 1.2.6.2 jdolecek
158 1.2.6.2 jdolecek /* unlock writes to the CCR */
159 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_SR, X1241REG_SR_WEL);
160 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
161 1.2.6.2 jdolecek
162 1.2.6.2 jdolecek /* set the time */
163 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_HR, bintobcd(ymdhms->dt_hour) | X1241REG_HR_MIL);
164 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_MN, bintobcd(ymdhms->dt_min));
165 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_SC, bintobcd(ymdhms->dt_sec));
166 1.2.6.2 jdolecek
167 1.2.6.2 jdolecek /* set the date */
168 1.2.6.2 jdolecek y2k = (ymdhms->dt_year >= 2000) ? 0x20 : 0x19;
169 1.2.6.2 jdolecek year = ymdhms->dt_year % 100;
170 1.2.6.2 jdolecek
171 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_MO, bintobcd(ymdhms->dt_mon));
172 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_DT, bintobcd(ymdhms->dt_day));
173 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_YR, bintobcd(year));
174 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_Y2K, bintobcd(y2k));
175 1.2.6.2 jdolecek
176 1.2.6.2 jdolecek /* lock writes again */
177 1.2.6.2 jdolecek WRITERTC(sc, X1241REG_SR, 0);
178 1.2.6.2 jdolecek
179 1.2.6.2 jdolecek return (0);
180 1.2.6.2 jdolecek }
181 1.2.6.2 jdolecek
182 1.2.6.2 jdolecek static int
183 1.2.6.2 jdolecek xirtc_gettime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
184 1.2.6.2 jdolecek {
185 1.2.6.2 jdolecek struct rtc_softc *sc = handle->cookie;
186 1.2.6.2 jdolecek uint8_t hour, year, y2k;
187 1.2.6.2 jdolecek uint8_t status;
188 1.2.6.2 jdolecek
189 1.2.6.2 jdolecek time_smbus_init(sc->sc_smbus_chan);
190 1.2.6.2 jdolecek ymdhms->dt_day = bcdtobin(READRTC(sc, X1241REG_DT));
191 1.2.6.2 jdolecek ymdhms->dt_mon = bcdtobin(READRTC(sc, X1241REG_MO));
192 1.2.6.2 jdolecek year = READRTC(sc, X1241REG_YR);
193 1.2.6.2 jdolecek y2k = READRTC(sc, X1241REG_Y2K);
194 1.2.6.2 jdolecek ymdhms->dt_year = bcdtobin(y2k) * 100 + bcdtobin(year);
195 1.2.6.2 jdolecek
196 1.2.6.2 jdolecek
197 1.2.6.2 jdolecek ymdhms->dt_sec = bcdtobin(READRTC(sc, X1241REG_SC));
198 1.2.6.2 jdolecek ymdhms->dt_min = bcdtobin(READRTC(sc, X1241REG_MN));
199 1.2.6.2 jdolecek hour = READRTC(sc, X1241REG_HR);
200 1.2.6.2 jdolecek ymdhms->dt_hour = bcdtobin(hour & ~X1241REG_HR_MIL);
201 1.2.6.2 jdolecek
202 1.2.6.2 jdolecek status = READRTC(sc, X1241REG_SR);
203 1.2.6.2 jdolecek
204 1.2.6.2 jdolecek if (status & X1241REG_SR_RTCF) {
205 1.2.6.2 jdolecek printf("%s: battery has failed, clock setting is not accurate\n",
206 1.2.6.2 jdolecek device_xname(sc->sc_dev));
207 1.2.6.2 jdolecek return (EIO);
208 1.2.6.2 jdolecek }
209 1.2.6.2 jdolecek
210 1.2.6.2 jdolecek return (0);
211 1.2.6.2 jdolecek }
212 1.2.6.2 jdolecek
213 1.2.6.2 jdolecek /*
214 1.2.6.2 jdolecek * ST M41T81 RTC support.
215 1.2.6.2 jdolecek */
216 1.2.6.2 jdolecek static int
217 1.2.6.2 jdolecek strtc_match(device_t parent, cfdata_t cf, void *aux)
218 1.2.6.2 jdolecek {
219 1.2.6.2 jdolecek struct smbus_attach_args *sa = aux;
220 1.2.6.2 jdolecek int ret;
221 1.2.6.2 jdolecek
222 1.2.6.2 jdolecek if ((sa->sa_interface != M41T81_SMBUS_CHAN) ||
223 1.2.6.2 jdolecek (sa->sa_device != M41T81_SLAVEADDR))
224 1.2.6.2 jdolecek return (0);
225 1.2.6.2 jdolecek
226 1.2.6.2 jdolecek time_smbus_init(sa->sa_interface);
227 1.2.6.2 jdolecek
228 1.2.6.2 jdolecek ret = time_readrtc(sa->sa_interface, sa->sa_device, SMB_1BYTE_ADDR, M41T81_SEC);
229 1.2.6.2 jdolecek if (ret < 0)
230 1.2.6.2 jdolecek return (0);
231 1.2.6.2 jdolecek
232 1.2.6.2 jdolecek return (!rtcfound);
233 1.2.6.2 jdolecek }
234 1.2.6.2 jdolecek
235 1.2.6.2 jdolecek static void
236 1.2.6.2 jdolecek strtc_attach(device_t parent, device_t self, void *aux)
237 1.2.6.2 jdolecek {
238 1.2.6.2 jdolecek struct smbus_attach_args *sa = aux;
239 1.2.6.2 jdolecek struct rtc_softc *sc = device_private(self);
240 1.2.6.2 jdolecek
241 1.2.6.2 jdolecek rtcfound = 1;
242 1.2.6.2 jdolecek the_rtc = sc;
243 1.2.6.2 jdolecek
244 1.2.6.2 jdolecek sc->sc_dev = self;
245 1.2.6.2 jdolecek sc->sc_smbus_chan = sa->sa_interface;
246 1.2.6.2 jdolecek sc->sc_smbus_addr = sa->sa_device;
247 1.2.6.2 jdolecek sc->sc_type = SMB_1BYTE_ADDR; /* One-byte register addresses on the ST */
248 1.2.6.2 jdolecek
249 1.2.6.2 jdolecek /* Set up MI todr(9) stuff */
250 1.2.6.2 jdolecek sc->sc_ct.cookie = sc;
251 1.2.6.2 jdolecek sc->sc_ct.todr_settime_ymdhms = strtc_settime;
252 1.2.6.2 jdolecek sc->sc_ct.todr_gettime_ymdhms = strtc_gettime;
253 1.2.6.2 jdolecek
254 1.2.6.2 jdolecek todr_attach(&sc->sc_ct);
255 1.2.6.2 jdolecek
256 1.2.6.2 jdolecek aprint_normal("\n");
257 1.2.6.2 jdolecek rtc_cal_timer(); /* XXX */
258 1.2.6.2 jdolecek }
259 1.2.6.2 jdolecek
260 1.2.6.2 jdolecek static int
261 1.2.6.2 jdolecek strtc_settime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
262 1.2.6.2 jdolecek {
263 1.2.6.2 jdolecek struct rtc_softc *sc = handle->cookie;
264 1.2.6.2 jdolecek uint8_t hour;
265 1.2.6.2 jdolecek
266 1.2.6.2 jdolecek time_smbus_init(sc->sc_smbus_chan);
267 1.2.6.2 jdolecek
268 1.2.6.2 jdolecek hour = bintobcd(ymdhms->dt_hour);
269 1.2.6.2 jdolecek if (ymdhms->dt_year >= 2000) /* Should be always true! */
270 1.2.6.2 jdolecek hour |= M41T81_HOUR_CB | M41T81_HOUR_CEB;
271 1.2.6.2 jdolecek
272 1.2.6.2 jdolecek /* set the time */
273 1.2.6.2 jdolecek WRITERTC(sc, M41T81_SEC, bintobcd(ymdhms->dt_sec));
274 1.2.6.2 jdolecek WRITERTC(sc, M41T81_MIN, bintobcd(ymdhms->dt_min));
275 1.2.6.2 jdolecek WRITERTC(sc, M41T81_HOUR, hour);
276 1.2.6.2 jdolecek
277 1.2.6.2 jdolecek /* set the date */
278 1.2.6.2 jdolecek WRITERTC(sc, M41T81_DATE, bintobcd(ymdhms->dt_day));
279 1.2.6.2 jdolecek WRITERTC(sc, M41T81_MON, bintobcd(ymdhms->dt_mon));
280 1.2.6.2 jdolecek WRITERTC(sc, M41T81_YEAR, bintobcd(ymdhms->dt_year % 100));
281 1.2.6.2 jdolecek
282 1.2.6.2 jdolecek return (0);
283 1.2.6.2 jdolecek }
284 1.2.6.2 jdolecek
285 1.2.6.2 jdolecek static int
286 1.2.6.2 jdolecek strtc_gettime(todr_chip_handle_t handle, struct clock_ymdhms *ymdhms)
287 1.2.6.2 jdolecek {
288 1.2.6.2 jdolecek struct rtc_softc *sc = handle->cookie;
289 1.2.6.2 jdolecek uint8_t hour;
290 1.2.6.2 jdolecek
291 1.2.6.2 jdolecek time_smbus_init(sc->sc_smbus_chan);
292 1.2.6.2 jdolecek
293 1.2.6.2 jdolecek ymdhms->dt_sec = bcdtobin(READRTC(sc, M41T81_SEC));
294 1.2.6.2 jdolecek ymdhms->dt_min = bcdtobin(READRTC(sc, M41T81_MIN));
295 1.2.6.2 jdolecek hour = READRTC(sc, M41T81_HOUR & M41T81_HOUR_MASK);
296 1.2.6.2 jdolecek ymdhms->dt_hour = bcdtobin(hour & M41T81_HOUR_MASK);
297 1.2.6.2 jdolecek
298 1.2.6.2 jdolecek ymdhms->dt_day = bcdtobin(READRTC(sc, M41T81_DATE));
299 1.2.6.2 jdolecek ymdhms->dt_mon = bcdtobin(READRTC(sc, M41T81_MON));
300 1.2.6.2 jdolecek ymdhms->dt_year = 1900 + bcdtobin(READRTC(sc, M41T81_YEAR));
301 1.2.6.2 jdolecek if (hour & M41T81_HOUR_CB)
302 1.2.6.2 jdolecek ymdhms->dt_year += 100;
303 1.2.6.2 jdolecek
304 1.2.6.2 jdolecek return (0);
305 1.2.6.2 jdolecek }
306 1.2.6.2 jdolecek
307 1.2.6.2 jdolecek #define NITERS 3
308 1.2.6.2 jdolecek #define RTC_SECONDS(rtc) bcdtobin(READRTC((rtc), X1241REG_SC))
309 1.2.6.2 jdolecek
310 1.2.6.2 jdolecek /*
311 1.2.6.2 jdolecek * Since it takes so long to read the complete time/date values from
312 1.2.6.2 jdolecek * the RTC over the SMBus, we only read the seconds value.
313 1.2.6.2 jdolecek * Later versions of the SWARM will hopefully have the RTC interrupt
314 1.2.6.2 jdolecek * attached so we can do the clock calibration much more quickly and
315 1.2.6.2 jdolecek * with a higher resolution.
316 1.2.6.2 jdolecek */
317 1.2.6.2 jdolecek static void
318 1.2.6.2 jdolecek rtc_cal_timer(void)
319 1.2.6.2 jdolecek {
320 1.2.6.2 jdolecek uint32_t ctrdiff[NITERS], startctr, endctr;
321 1.2.6.2 jdolecek int sec, lastsec, i;
322 1.2.6.2 jdolecek
323 1.2.6.2 jdolecek if (rtcfound == 0) {
324 1.2.6.2 jdolecek printf("rtc_cal_timer before rtc attached\n");
325 1.2.6.2 jdolecek return;
326 1.2.6.2 jdolecek }
327 1.2.6.2 jdolecek return; /* XXX XXX */
328 1.2.6.2 jdolecek
329 1.2.6.2 jdolecek printf("%s: calibrating CPU clock", device_xname(the_rtc->sc_dev));
330 1.2.6.2 jdolecek
331 1.2.6.2 jdolecek /*
332 1.2.6.2 jdolecek * Run the loop an extra time to wait for the second to tick over
333 1.2.6.2 jdolecek * and to prime the cache.
334 1.2.6.2 jdolecek */
335 1.2.6.2 jdolecek time_smbus_init(the_rtc->sc_smbus_chan);
336 1.2.6.2 jdolecek sec = RTC_SECONDS(the_rtc);
337 1.2.6.2 jdolecek endctr = mips3_cp0_count_read();
338 1.2.6.2 jdolecek
339 1.2.6.2 jdolecek for (i = 0; i < NITERS; i++) {
340 1.2.6.2 jdolecek int diff;
341 1.2.6.2 jdolecek
342 1.2.6.2 jdolecek again:
343 1.2.6.2 jdolecek lastsec = sec;
344 1.2.6.2 jdolecek startctr = endctr;
345 1.2.6.2 jdolecek
346 1.2.6.2 jdolecek /* Wait for the timer to tick over. */
347 1.2.6.2 jdolecek do {
348 1.2.6.2 jdolecek // time_smbus_init(the_rtc->sc_smbus_chan);
349 1.2.6.2 jdolecek sec = RTC_SECONDS(the_rtc);
350 1.2.6.2 jdolecek } while (lastsec == sec);
351 1.2.6.2 jdolecek endctr = mips3_cp0_count_read();
352 1.2.6.2 jdolecek
353 1.2.6.2 jdolecek diff = sec - lastsec;
354 1.2.6.2 jdolecek if (diff < 0)
355 1.2.6.2 jdolecek diff += 60;
356 1.2.6.2 jdolecek
357 1.2.6.2 jdolecek /* Sometimes we appear to skip a second. Clock jitter? */
358 1.2.6.2 jdolecek if (diff > 1)
359 1.2.6.2 jdolecek goto again;
360 1.2.6.2 jdolecek
361 1.2.6.2 jdolecek if (endctr < startctr)
362 1.2.6.2 jdolecek ctrdiff[i] = 0xffffffff - startctr + endctr;
363 1.2.6.2 jdolecek else
364 1.2.6.2 jdolecek ctrdiff[i] = endctr - startctr;
365 1.2.6.2 jdolecek }
366 1.2.6.2 jdolecek printf("\n");
367 1.2.6.2 jdolecek
368 1.2.6.2 jdolecek /* Compute the number of cycles per second. */
369 1.2.6.2 jdolecek curcpu()->ci_cpu_freq = ((ctrdiff[1] + ctrdiff[2]) / 2);
370 1.2.6.2 jdolecek
371 1.2.6.2 jdolecek /* Compute the delay divisor. */
372 1.2.6.2 jdolecek curcpu()->ci_divisor_delay = curcpu()->ci_cpu_freq / 1000000;
373 1.2.6.2 jdolecek
374 1.2.6.2 jdolecek /* Compute clock cycles per hz */
375 1.2.6.2 jdolecek curcpu()->ci_cycles_per_hz = curcpu()->ci_cpu_freq / hz;
376 1.2.6.2 jdolecek
377 1.2.6.2 jdolecek printf("%s: timer calibration: %lu cycles/sec [(%u, %u)]\n",
378 1.2.6.2 jdolecek device_xname(the_rtc->sc_dev), curcpu()->ci_cpu_freq,
379 1.2.6.2 jdolecek ctrdiff[1], ctrdiff[2]);
380 1.2.6.2 jdolecek }
381 1.2.6.2 jdolecek #undef RTC_SECONDS
382 1.2.6.2 jdolecek
383 1.2.6.2 jdolecek /* XXX eville direct-access-to-the-device code follows... */
384 1.2.6.2 jdolecek
385 1.2.6.2 jdolecek /*
386 1.2.6.2 jdolecek * Copyright 2000,2001
387 1.2.6.2 jdolecek * Broadcom Corporation. All rights reserved.
388 1.2.6.2 jdolecek *
389 1.2.6.2 jdolecek * This software is furnished under license and may be used and copied only
390 1.2.6.2 jdolecek * in accordance with the following terms and conditions. Subject to these
391 1.2.6.2 jdolecek * conditions, you may download, copy, install, use, modify and distribute
392 1.2.6.2 jdolecek * modified or unmodified copies of this software in source and/or binary
393 1.2.6.2 jdolecek * form. No title or ownership is transferred hereby.
394 1.2.6.2 jdolecek *
395 1.2.6.2 jdolecek * 1) Any source code used, modified or distributed must reproduce and
396 1.2.6.2 jdolecek * retain this copyright notice and list of conditions as they appear in
397 1.2.6.2 jdolecek * the source file.
398 1.2.6.2 jdolecek *
399 1.2.6.2 jdolecek * 2) No right is granted to use any trade name, trademark, or logo of
400 1.2.6.2 jdolecek * Broadcom Corporation. The "Broadcom Corporation" name may not be
401 1.2.6.2 jdolecek * used to endorse or promote products derived from this software
402 1.2.6.2 jdolecek * without the prior written permission of Broadcom Corporation.
403 1.2.6.2 jdolecek *
404 1.2.6.2 jdolecek * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED
405 1.2.6.2 jdolecek * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF
406 1.2.6.2 jdolecek * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
407 1.2.6.2 jdolecek * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE
408 1.2.6.2 jdolecek * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE
409 1.2.6.2 jdolecek * LIABLE FOR DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
410 1.2.6.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
411 1.2.6.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
412 1.2.6.2 jdolecek * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
413 1.2.6.2 jdolecek * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
414 1.2.6.2 jdolecek * OR OTHERWISE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
415 1.2.6.2 jdolecek */
416 1.2.6.2 jdolecek
417 1.2.6.2 jdolecek #include <mips/sibyte/include/sb1250_regs.h>
418 1.2.6.2 jdolecek #include <mips/sibyte/include/sb1250_smbus.h>
419 1.2.6.2 jdolecek
420 1.2.6.2 jdolecek #define READ_REG(rp) mips3_ld((register_t)(MIPS_PHYS_TO_KSEG1(rp)))
421 1.2.6.2 jdolecek #define WRITE_REG(rp, val) mips3_sd((register_t)(MIPS_PHYS_TO_KSEG1(rp)), (val))
422 1.2.6.2 jdolecek
423 1.2.6.2 jdolecek static void
424 1.2.6.2 jdolecek time_smbus_init(int chan)
425 1.2.6.2 jdolecek {
426 1.2.6.2 jdolecek uint32_t reg;
427 1.2.6.2 jdolecek
428 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_FREQ);
429 1.2.6.2 jdolecek WRITE_REG(reg, K_SMB_FREQ_100KHZ);
430 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_CONTROL);
431 1.2.6.2 jdolecek WRITE_REG(reg, 0); /* not in direct mode, no interrupts, will poll */
432 1.2.6.2 jdolecek }
433 1.2.6.2 jdolecek
434 1.2.6.2 jdolecek static int
435 1.2.6.2 jdolecek time_waitready(int chan)
436 1.2.6.2 jdolecek {
437 1.2.6.2 jdolecek uint32_t reg;
438 1.2.6.2 jdolecek uint64_t status;
439 1.2.6.2 jdolecek
440 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_STATUS);
441 1.2.6.2 jdolecek
442 1.2.6.2 jdolecek for (;;) {
443 1.2.6.2 jdolecek status = READ_REG(reg);
444 1.2.6.2 jdolecek if (status & M_SMB_BUSY)
445 1.2.6.2 jdolecek continue;
446 1.2.6.2 jdolecek break;
447 1.2.6.2 jdolecek }
448 1.2.6.2 jdolecek
449 1.2.6.2 jdolecek if (status & M_SMB_ERROR) {
450 1.2.6.2 jdolecek WRITE_REG(reg, (status & M_SMB_ERROR));
451 1.2.6.2 jdolecek return (-1);
452 1.2.6.2 jdolecek }
453 1.2.6.2 jdolecek return (0);
454 1.2.6.2 jdolecek }
455 1.2.6.2 jdolecek
456 1.2.6.2 jdolecek static int
457 1.2.6.2 jdolecek time_readrtc(int chan, int slaveaddr, int devaddr, int type)
458 1.2.6.2 jdolecek {
459 1.2.6.2 jdolecek uint32_t reg;
460 1.2.6.2 jdolecek int err;
461 1.2.6.2 jdolecek
462 1.2.6.2 jdolecek /*
463 1.2.6.2 jdolecek * Make sure the bus is idle (probably should
464 1.2.6.2 jdolecek * ignore error here)
465 1.2.6.2 jdolecek */
466 1.2.6.2 jdolecek
467 1.2.6.2 jdolecek if (time_waitready(chan) < 0)
468 1.2.6.2 jdolecek return (-1);
469 1.2.6.2 jdolecek
470 1.2.6.2 jdolecek if (type == SMB_2BYTE_ADDR) {
471 1.2.6.2 jdolecek /*
472 1.2.6.2 jdolecek * Write the device address to the controller. There are two
473 1.2.6.2 jdolecek * parts, the high part goes in the "CMD" field, and the
474 1.2.6.2 jdolecek * low part is the data field.
475 1.2.6.2 jdolecek */
476 1.2.6.2 jdolecek
477 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_CMD);
478 1.2.6.2 jdolecek WRITE_REG(reg, (devaddr >> 8) & 0x7);
479 1.2.6.2 jdolecek
480 1.2.6.2 jdolecek /*
481 1.2.6.2 jdolecek * Write the data to the controller
482 1.2.6.2 jdolecek */
483 1.2.6.2 jdolecek
484 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_DATA);
485 1.2.6.2 jdolecek WRITE_REG(reg, (devaddr & 0xff) & 0xff);
486 1.2.6.2 jdolecek } else { /* SMB_1BYTE_ADDR */
487 1.2.6.2 jdolecek /*
488 1.2.6.2 jdolecek * Write the device address to the controller.
489 1.2.6.2 jdolecek */
490 1.2.6.2 jdolecek
491 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_CMD);
492 1.2.6.2 jdolecek WRITE_REG(reg, devaddr & 0xff);
493 1.2.6.2 jdolecek }
494 1.2.6.2 jdolecek
495 1.2.6.2 jdolecek /*
496 1.2.6.2 jdolecek * Start the command
497 1.2.6.2 jdolecek */
498 1.2.6.2 jdolecek
499 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_START);
500 1.2.6.2 jdolecek if (type == SMB_2BYTE_ADDR)
501 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR2BYTE) | V_SMB_ADDR(slaveaddr));
502 1.2.6.2 jdolecek else /* SMB_1BYTE_ADDR */
503 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR1BYTE) | V_SMB_ADDR(slaveaddr));
504 1.2.6.2 jdolecek
505 1.2.6.2 jdolecek /*
506 1.2.6.2 jdolecek * Wait till done
507 1.2.6.2 jdolecek */
508 1.2.6.2 jdolecek
509 1.2.6.2 jdolecek err = time_waitready(chan);
510 1.2.6.2 jdolecek if (err < 0)
511 1.2.6.2 jdolecek return (err);
512 1.2.6.2 jdolecek
513 1.2.6.2 jdolecek /*
514 1.2.6.2 jdolecek * Read the data byte
515 1.2.6.2 jdolecek */
516 1.2.6.2 jdolecek
517 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_RD1BYTE) | V_SMB_ADDR(slaveaddr));
518 1.2.6.2 jdolecek
519 1.2.6.2 jdolecek err = time_waitready(chan);
520 1.2.6.2 jdolecek if (err < 0)
521 1.2.6.2 jdolecek return (err);
522 1.2.6.2 jdolecek
523 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_DATA);
524 1.2.6.2 jdolecek err = READ_REG(reg);
525 1.2.6.2 jdolecek
526 1.2.6.2 jdolecek return (err & 0xff);
527 1.2.6.2 jdolecek }
528 1.2.6.2 jdolecek
529 1.2.6.2 jdolecek static int
530 1.2.6.2 jdolecek time_writertc(int chan, int slaveaddr, int devaddr, int type, int b)
531 1.2.6.2 jdolecek {
532 1.2.6.2 jdolecek uint32_t reg;
533 1.2.6.2 jdolecek int err, timer;
534 1.2.6.2 jdolecek
535 1.2.6.2 jdolecek /*
536 1.2.6.2 jdolecek * Make sure the bus is idle (probably should
537 1.2.6.2 jdolecek * ignore error here)
538 1.2.6.2 jdolecek */
539 1.2.6.2 jdolecek
540 1.2.6.2 jdolecek if (time_waitready(chan) < 0)
541 1.2.6.2 jdolecek return (-1);
542 1.2.6.2 jdolecek
543 1.2.6.2 jdolecek /*
544 1.2.6.2 jdolecek * Write the device address to the controller. There are two
545 1.2.6.2 jdolecek * parts, the high part goes in the "CMD" field, and the
546 1.2.6.2 jdolecek * low part is the data field.
547 1.2.6.2 jdolecek */
548 1.2.6.2 jdolecek
549 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_CMD);
550 1.2.6.2 jdolecek if (type == SMB_2BYTE_ADDR)
551 1.2.6.2 jdolecek WRITE_REG(reg, (devaddr >> 8) & 0x7);
552 1.2.6.2 jdolecek else /* SMB_1BYTE_ADDR */
553 1.2.6.2 jdolecek WRITE_REG(reg, devaddr & 0xff);
554 1.2.6.2 jdolecek
555 1.2.6.2 jdolecek /*
556 1.2.6.2 jdolecek * Write the data to the controller
557 1.2.6.2 jdolecek */
558 1.2.6.2 jdolecek
559 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_DATA);
560 1.2.6.2 jdolecek if (type == SMB_2BYTE_ADDR)
561 1.2.6.2 jdolecek WRITE_REG(reg, (devaddr & 0xff) | ((b & 0xff) << 8));
562 1.2.6.2 jdolecek else /* SMB_1BYTE_ADDR */
563 1.2.6.2 jdolecek WRITE_REG(reg, b & 0xff);
564 1.2.6.2 jdolecek
565 1.2.6.2 jdolecek /*
566 1.2.6.2 jdolecek * Start the command. Keep pounding on the device until it
567 1.2.6.2 jdolecek * submits or the timer expires, whichever comes first. The
568 1.2.6.2 jdolecek * datasheet says writes can take up to 10ms, so we'll give it 500.
569 1.2.6.2 jdolecek */
570 1.2.6.2 jdolecek
571 1.2.6.2 jdolecek reg = A_SMB_REGISTER(chan, R_SMB_START);
572 1.2.6.2 jdolecek if (type == SMB_2BYTE_ADDR)
573 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR3BYTE) | V_SMB_ADDR(slaveaddr));
574 1.2.6.2 jdolecek else /* SMB_1BYTE_ADDR */
575 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_WR2BYTE) | V_SMB_ADDR(slaveaddr));
576 1.2.6.2 jdolecek
577 1.2.6.2 jdolecek /*
578 1.2.6.2 jdolecek * Wait till the SMBus interface is done
579 1.2.6.2 jdolecek */
580 1.2.6.2 jdolecek
581 1.2.6.2 jdolecek err = time_waitready(chan);
582 1.2.6.2 jdolecek if (err < 0)
583 1.2.6.2 jdolecek return (err);
584 1.2.6.2 jdolecek
585 1.2.6.2 jdolecek /*
586 1.2.6.2 jdolecek * Pound on the device with a current address read
587 1.2.6.2 jdolecek * to poll for the write complete
588 1.2.6.2 jdolecek */
589 1.2.6.2 jdolecek
590 1.2.6.2 jdolecek err = -1;
591 1.2.6.2 jdolecek timer = 100000000; /* XXX */
592 1.2.6.2 jdolecek
593 1.2.6.2 jdolecek while (timer-- > 0) {
594 1.2.6.2 jdolecek WRITE_REG(reg, V_SMB_TT(K_SMB_TT_RD1BYTE) | V_SMB_ADDR(slaveaddr));
595 1.2.6.2 jdolecek
596 1.2.6.2 jdolecek err = time_waitready(chan);
597 1.2.6.2 jdolecek if (err == 0)
598 1.2.6.2 jdolecek break;
599 1.2.6.2 jdolecek }
600 1.2.6.2 jdolecek
601 1.2.6.2 jdolecek return (err);
602 1.2.6.2 jdolecek }
603