Home | History | Annotate | Line # | Download | only in sbmips
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