g2rtc.c revision 1.4
11.4Stsutsui/* $NetBSD: g2rtc.c,v 1.4 2009/12/12 14:44:09 tsutsui Exp $ */ 21.1Suwe 31.1Suwe/*- 41.1Suwe * Copyright (c) 2002 The NetBSD Foundation, Inc. 51.1Suwe * All rights reserved. 61.1Suwe * 71.1Suwe * Redistribution and use in source and binary forms, with or without 81.1Suwe * modification, are permitted provided that the following conditions 91.1Suwe * are met: 101.1Suwe * 1. Redistributions of source code must retain the above copyright 111.1Suwe * notice, this list of conditions and the following disclaimer. 121.1Suwe * 2. Redistributions in binary form must reproduce the above copyright 131.1Suwe * notice, this list of conditions and the following disclaimer in the 141.1Suwe * documentation and/or other materials provided with the distribution. 151.1Suwe * 161.1Suwe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 171.1Suwe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 181.1Suwe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 191.1Suwe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 201.1Suwe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 211.1Suwe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 221.1Suwe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 231.1Suwe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 241.1Suwe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 251.1Suwe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 261.1Suwe * POSSIBILITY OF SUCH DAMAGE. 271.1Suwe */ 281.1Suwe 291.1Suwe#include <sys/cdefs.h> 301.4Stsutsui__KERNEL_RCSID(0, "$NetBSD: g2rtc.c,v 1.4 2009/12/12 14:44:09 tsutsui Exp $"); 311.1Suwe 321.1Suwe#include <sys/param.h> 331.1Suwe#include <sys/systm.h> 341.2She#include <sys/device.h> 351.1Suwe 361.1Suwe#include <dev/clock_subr.h> 371.1Suwe 381.1Suwe#include <machine/bus.h> 391.1Suwe#include <dreamcast/dev/g2/g2busvar.h> 401.1Suwe 411.1Suwe 421.1Suwe#define G2RTC_REG_BASE 0x00710000 431.1Suwe#define G2RTC_REG_SIZE 12 441.1Suwe 451.1Suwe/* Offset by 20 years, 5 of them are leap */ 461.1Suwe#define G2RTC_OFFSET (20 * SECYR + 5 * SECDAY) 471.1Suwe 481.1Suwestruct g2rtc_softc { 491.1Suwe struct device sc_dev; 501.1Suwe 511.1Suwe bus_space_tag_t sc_bt; 521.1Suwe bus_space_handle_t sc_bh; 531.1Suwe}; 541.1Suwe 551.1Suwe/* autoconf glue */ 561.1Suwestatic int g2rtc_match(struct device *, struct cfdata *, void *); 571.1Suwestatic void g2rtc_attach(struct device *, struct device *, void *); 581.1Suwe 591.1SuweCFATTACH_DECL(g2rtc, sizeof(struct g2rtc_softc), 601.1Suwe g2rtc_match, g2rtc_attach, NULL, NULL); 611.1Suwe 621.1Suwe 631.1Suwe/* todr(9) methods */ 641.4Stsutsuistatic int g2rtc_todr_gettime(todr_chip_handle_t, struct timeval *); 651.4Stsutsuistatic int g2rtc_todr_settime(todr_chip_handle_t, struct timeval *); 661.1Suwe 671.1Suwestatic struct todr_chip_handle g2rtc_todr_handle = { 681.1Suwe .cookie = NULL, /* set on attach */ 691.1Suwe .todr_gettime = g2rtc_todr_gettime, 701.1Suwe .todr_settime = g2rtc_todr_settime, 711.1Suwe}; 721.1Suwe 731.1Suwe 741.1Suwestatic inline uint32_t g2rtc_read(bus_space_tag_t, bus_space_handle_t); 751.1Suwe 761.1Suwe 771.1Suwestatic int 781.1Suweg2rtc_match(struct device *parent, struct cfdata *cf, void *aux) 791.1Suwe{ 801.1Suwe static int g2rtc_matched = 0; 811.1Suwe 821.1Suwe if (g2rtc_matched) 831.1Suwe return 0; 841.1Suwe 851.1Suwe g2rtc_matched = 1; 861.1Suwe return 1; 871.1Suwe} 881.1Suwe 891.1Suwe 901.1Suwestatic void 911.1Suweg2rtc_attach(struct device *parent, struct device *self, void *aux) 921.1Suwe{ 931.1Suwe struct g2rtc_softc *sc = (void *)self; 941.1Suwe struct g2bus_attach_args *ga = aux; 951.1Suwe 961.1Suwe sc->sc_bt = ga->ga_memt; 971.1Suwe if (bus_space_map(sc->sc_bt, G2RTC_REG_BASE, G2RTC_REG_SIZE, 0, 981.1Suwe &sc->sc_bh) != 0) 991.1Suwe { 1001.1Suwe printf(": unable to map registers\n"); 1011.1Suwe return; 1021.1Suwe } 1031.1Suwe printf(": time-of-day clock\n"); 1041.1Suwe 1051.1Suwe g2rtc_todr_handle.cookie = sc; 1061.1Suwe todr_attach(&g2rtc_todr_handle); 1071.1Suwe} 1081.1Suwe 1091.1Suwe 1101.1Suwestatic inline uint32_t 1111.1Suweg2rtc_read(bus_space_tag_t bt, bus_space_handle_t bh) 1121.1Suwe{ 1131.1Suwe 1141.1Suwe return ((bus_space_read_4(bt, bh, 0) & 0xffff) << 16) 1151.1Suwe | (bus_space_read_4(bt, bh, 4) & 0xffff); 1161.1Suwe} 1171.1Suwe 1181.1Suwe 1191.1Suwe/* 1201.1Suwe * Get time-of-day and convert to `struct timeval'. 1211.1Suwe * Return 0 on success; an error number otherwise. 1221.1Suwe */ 1231.1Suwestatic int 1241.4Stsutsuig2rtc_todr_gettime(todr_chip_handle_t handle, struct timeval *tv) 1251.1Suwe{ 1261.1Suwe struct g2rtc_softc *sc = handle->cookie; 1271.1Suwe uint32_t new, old; 1281.1Suwe int i; 1291.1Suwe 1301.1Suwe for (old = 0;;) { 1311.1Suwe for (i = 0; i < 3; i++) { 1321.1Suwe new = g2rtc_read(sc->sc_bt, sc->sc_bh); 1331.1Suwe if (new != old) 1341.1Suwe break; 1351.1Suwe } 1361.1Suwe if (i < 3) 1371.1Suwe old = new; 1381.1Suwe else 1391.1Suwe break; 1401.1Suwe } 1411.1Suwe 1421.1Suwe tv->tv_sec = new - G2RTC_OFFSET; 1431.1Suwe tv->tv_usec = 0; 1441.1Suwe 1451.1Suwe return 0; 1461.1Suwe} 1471.1Suwe 1481.1Suwe 1491.1Suwe/* 1501.1Suwe * Set the time-of-day clock based on the value of the `struct timeval' arg. 1511.1Suwe * Return 0 on success; an error number otherwise. 1521.1Suwe */ 1531.1Suwestatic int 1541.4Stsutsuig2rtc_todr_settime(todr_chip_handle_t handle, struct timeval *tv) 1551.1Suwe{ 1561.1Suwe struct g2rtc_softc *sc = handle->cookie; 1571.1Suwe uint32_t secs; 1581.1Suwe int i, retry; 1591.1Suwe 1601.1Suwe secs = (uint32_t)tv->tv_sec + G2RTC_OFFSET; 1611.1Suwe 1621.1Suwe for (retry = 0; retry < 5; retry++) { 1631.1Suwe 1641.1Suwe /* Don't change the order */ 1651.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 8, 1); 1661.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 4, secs & 0xffff); 1671.1Suwe bus_space_write_4(sc->sc_bt, sc->sc_bh, 0, secs >> 16); 1681.1Suwe 1691.1Suwe /* verify */ 1701.1Suwe for (i = 0; i < 3; i++) 1711.1Suwe if (g2rtc_read(sc->sc_bt, sc->sc_bh) == secs) 1721.1Suwe return 0; /* ok */ 1731.1Suwe } 1741.1Suwe 1751.1Suwe return EIO; 1761.1Suwe 1771.1Suwe} 178