121308Sache/* $NetBSD: rtc.c,v 1.36 2022/07/21 10:09:21 andvar Exp $ */ 221308Sache 321308Sache/*- 421308Sache * Copyright (c) 1999 Shin Takemura. All rights reserved. 521308Sache * Copyright (c) 1999 SATO Kazumi. All rights reserved. 621308Sache * Copyright (c) 1999 PocketBSD Project. All rights reserved. 721308Sache * 821308Sache * Redistribution and use in source and binary forms, with or without 921308Sache * modification, are permitted provided that the following conditions 1058310Sache * are met: 1121308Sache * 1. Redistributions of source code must retain the above copyright 1221308Sache * notice, this list of conditions and the following disclaimer. 1321308Sache * 2. Redistributions in binary form must reproduce the above copyright 1421308Sache * notice, this list of conditions and the following disclaimer in the 1521308Sache * documentation and/or other materials provided with the distribution. 1621308Sache * 3. All advertising materials mentioning features or use of this software 1721308Sache * must display the following acknowledgement: 1821308Sache * This product includes software developed by the PocketBSD project 1921308Sache * and its contributors. 2021308Sache * 4. Neither the name of the project nor the names of its contributors 2158310Sache * may be used to endorse or promote products derived from this software 2221308Sache * without specific prior written permission. 2321308Sache * 2421308Sache * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2521308Sache * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2621308Sache * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2721308Sache * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2821308Sache * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2921308Sache * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3021308Sache * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3121308Sache * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3221308Sache * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3321308Sache * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3421308Sache * SUCH DAMAGE. 3521308Sache * 3621308Sache */ 3721308Sache 3821308Sache#include <sys/cdefs.h> 3921308Sache__KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.36 2022/07/21 10:09:21 andvar Exp $"); 4021308Sache 4121308Sache#include "opt_vr41xx.h" 4221308Sache 4321308Sache#include <sys/param.h> 4421308Sache#include <sys/systm.h> 4521308Sache#include <sys/timetc.h> 4621308Sache#include <sys/device.h> 4721308Sache#include <sys/cpu.h> 4821308Sache 4921308Sache#include <machine/sysconf.h> 5021308Sache#include <machine/bus.h> 5121308Sache 5221308Sache#include <dev/clock_subr.h> 5321308Sache 5421308Sache#include <hpcmips/vr/vr.h> 5521308Sache#include <hpcmips/vr/vrcpudef.h> 5621308Sache#include <hpcmips/vr/vripif.h> 5721308Sache#include <hpcmips/vr/vripreg.h> 5821308Sache#include <hpcmips/vr/rtcreg.h> 5921308Sache 6058310Sache/* 6158310Sache * for debugging definitions 6258310Sache * VRRTCDEBUG print rtc debugging information 6358310Sache */ 6421308Sache#ifdef VRRTCDEBUG 6521308Sache#ifndef VRRTCDEBUG_CONF 6621308Sache#define VRRTCDEBUG_CONF 0 6721308Sache#endif 6821308Sacheint vrrtc_debug = VRRTCDEBUG_CONF; 6921308Sache#define DPRINTF(arg) if (vrrtc_debug) printf arg; 7021308Sache#define DDUMP_REGS(arg) if (vrrtc_debug) vrrtc_dump_regs(arg); 7158310Sache#else /* VRRTCDEBUG */ 7258310Sache#define DPRINTF(arg) 7358310Sache#define DDUMP_REGS(arg) 7421308Sache#endif /* VRRTCDEBUG */ 7558310Sache 7621308Sachestruct vrrtc_softc { 7758310Sache device_t sc_dev; 7858310Sache bus_space_tag_t sc_iot; 7921308Sache bus_space_handle_t sc_ioh; 8021308Sache void *sc_ih; 8121308Sache#ifndef SINGLE_VRIP_BASE 8221308Sache int sc_rtcint_reg; 8321308Sache int sc_tclk_h_reg, sc_tclk_l_reg; 8421308Sache int sc_tclk_cnt_h_reg, sc_tclk_cnt_l_reg; 8521308Sache#endif /* SINGLE_VRIP_BASE */ 8621308Sache int64_t sc_epoch; 8721308Sache struct todr_chip_handle sc_todr; 8821308Sache struct timecounter sc_tc; 8921308Sache}; 9021308Sache 9121308Sachevoid vrrtc_init(device_t); 9221308Sacheint vrrtc_get(todr_chip_handle_t, struct timeval *); 9321308Sacheint vrrtc_set(todr_chip_handle_t, struct timeval *); 9421308Sacheuint32_t vrrtc_get_timecount(struct timecounter *); 9521308Sache 9621308Sachestruct platform_clock vr_clock = { 9721308Sache#define CLOCK_RATE 128 9821308Sache CLOCK_RATE, vrrtc_init, 9921308Sache}; 10021308Sache 10121308Sacheint vrrtc_match(device_t, cfdata_t, void *); 10221308Sachevoid vrrtc_attach(device_t, device_t, void *); 10321308Sacheint vrrtc_intr(void*, vaddr_t, uint32_t); 10421308Sachevoid vrrtc_dump_regs(struct vrrtc_softc *); 10521308Sache 10621308SacheCFATTACH_DECL_NEW(vrrtc, sizeof(struct vrrtc_softc), 10721308Sache vrrtc_match, vrrtc_attach, NULL, NULL); 10821308Sache 10921308Sacheint 11021308Sachevrrtc_match(device_t parent, cfdata_t cf, void *aux) 11121308Sache{ 11221308Sache 11321308Sache return 1; 11421308Sache} 11521308Sache 11621308Sache#ifndef SINGLE_VRIP_BASE 11721308Sache#define RTCINT_REG_W (sc->sc_rtcint_reg) 11821308Sache#define TCLK_H_REG_W (sc->sc_tclk_h_reg) 11921308Sache#define TCLK_L_REG_W (sc->sc_tclk_l_reg) 12021308Sache#define TCLK_CNT_H_REG_W (sc->sc_tclk_cnt_h_reg) 12121308Sache#define TCLK_CNT_L_REG_W (sc->sc_tclk_cnt_l_reg) 12221308Sache#endif /* SINGLE_VRIP_BASE */ 12321308Sache 12421308Sachevoid 12521308Sachevrrtc_attach(device_t parent, device_t self, void *aux) 12621308Sache{ 12721308Sache struct vrip_attach_args *va = aux; 12821308Sache struct vrrtc_softc *sc = device_private(self); 12921308Sache int year; 13021308Sache 13121308Sache#ifndef SINGLE_VRIP_BASE 13221308Sache if (va->va_addr == VR4102_RTC_ADDR) { 13321308Sache sc->sc_rtcint_reg = VR4102_RTCINT_REG_W; 13421308Sache sc->sc_tclk_h_reg = VR4102_TCLK_H_REG_W; 13521308Sache sc->sc_tclk_l_reg = VR4102_TCLK_L_REG_W; 13621308Sache sc->sc_tclk_cnt_h_reg = VR4102_TCLK_CNT_H_REG_W; 13721308Sache sc->sc_tclk_cnt_l_reg = VR4102_TCLK_CNT_L_REG_W; 13821308Sache } else if (va->va_addr == VR4122_RTC_ADDR) { 13921308Sache sc->sc_rtcint_reg = VR4122_RTCINT_REG_W; 14021308Sache sc->sc_tclk_h_reg = VR4122_TCLK_H_REG_W; 14121308Sache sc->sc_tclk_l_reg = VR4122_TCLK_L_REG_W; 14221308Sache sc->sc_tclk_cnt_h_reg = VR4122_TCLK_CNT_H_REG_W; 14321308Sache sc->sc_tclk_cnt_l_reg = VR4122_TCLK_CNT_L_REG_W; 14421308Sache } else if (va->va_addr == VR4181_RTC_ADDR) { 14521308Sache sc->sc_rtcint_reg = VR4181_RTCINT_REG_W; 14621308Sache sc->sc_tclk_h_reg = RTC_NO_REG_W; 14721308Sache sc->sc_tclk_l_reg = RTC_NO_REG_W; 14821308Sache sc->sc_tclk_cnt_h_reg = RTC_NO_REG_W; 14921308Sache sc->sc_tclk_cnt_l_reg = RTC_NO_REG_W; 15021308Sache } else { 15121308Sache panic("%s: unknown base address 0x%lx", 15221308Sache device_xname(self), va->va_addr); 15321308Sache } 15421308Sache#endif /* SINGLE_VRIP_BASE */ 15521308Sache 15621308Sache sc->sc_iot = va->va_iot; 15721308Sache if (bus_space_map(sc->sc_iot, va->va_addr, va->va_size, 15821308Sache 0 /* no flags */, &sc->sc_ioh)) { 15921308Sache printf("vrrtc_attach: can't map i/o space\n"); 16021308Sache return; 16121308Sache } 16221308Sache /* RTC interrupt handler is directly dispatched from CPU intr */ 16321308Sache vr_intr_establish(VR_INTR1, vrrtc_intr, sc); 16421308Sache /* But need to set level 1 interrupt mask register, 16521308Sache * so register fake interrurpt handler 16621308Sache */ 16721308Sache if (!(sc->sc_ih = vrip_intr_establish(va->va_vc, va->va_unit, 0, 16835486Sache IPL_CLOCK, 0, 0))) { 16935486Sache printf (":can't map interrupt.\n"); 17035486Sache return; 17135486Sache } 17235486Sache /* 17335486Sache * Rtc is attached to call this routine 17447558Sache * before cpu_initclock() calls clock_init(). 17535486Sache * So we must disable all interrupt for now. 17647558Sache */ 17735486Sache /* 17835486Sache * Disable all rtc interrupts 17947558Sache */ 18047558Sache /* Disable Elapse compare intr */ 18147558Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W, 0); 18247558Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W, 0); 18335486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W, 0); 18447558Sache /* Disable RTC Long1 intr */ 18535486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 18635486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W, 0); 18735486Sache /* Disable RTC Long2 intr */ 18835486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W, 0); 18935486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W, 0); 19035486Sache /* Disable RTC TCLK intr */ 19135486Sache if (TCLK_H_REG_W != RTC_NO_REG_W) { 19235486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W, 0); 19335486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W, 0); 19435486Sache } 19535486Sache /* 19635486Sache * Clear all rtc interrupts. 19735486Sache */ 19835486Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 19935486Sache 20021308Sache /* 20121308Sache * Figure out the epoch, which could be either forward or 20221308Sache * backwards in time. We assume that the start date will always 20321308Sache * be on Jan 1. 20421308Sache */ 20521308Sache for (year = EPOCHYEAR; year < POSIX_BASE_YEAR; year++) { 20621308Sache sc->sc_epoch += days_per_year(year) * SECS_PER_DAY; 20721308Sache } 20821308Sache for (year = POSIX_BASE_YEAR; year < EPOCHYEAR; year++) { 20926497Sache sc->sc_epoch -= days_per_year(year) * SECS_PER_DAY; 21021308Sache } 21121308Sache 21221308Sache /* 21321308Sache * Initialize MI todr(9) 21421308Sache */ 21521308Sache sc->sc_todr.todr_settime = vrrtc_set; 21621308Sache sc->sc_todr.todr_gettime = vrrtc_get; 21721308Sache sc->sc_todr.cookie = sc; 21821308Sache todr_attach(&sc->sc_todr); 21921308Sache 22021308Sache platform_clock_attach(self, &vr_clock); 22121308Sache} 22221308Sache 22321308Sacheint 22421308Sachevrrtc_intr(void *arg, vaddr_t pc, uint32_t status) 22521308Sache{ 22621308Sache struct vrrtc_softc *sc = arg; 22721308Sache struct clockframe cf; 22821308Sache 22921308Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCINT_REG_W, RTCINT_ALL); 23021308Sache cf.pc = pc; 23121308Sache cf.sr = status; 23221308Sache cf.intr = (curcpu()->ci_idepth > 1); 23321308Sache hardclock(&cf); 23421308Sache 23521308Sache return 0; 23621308Sache} 23721308Sache 23821308Sachevoid 23921308Sachevrrtc_init(device_t self) 24021308Sache{ 24121308Sache struct vrrtc_softc *sc = device_private(self); 24221308Sache 24321308Sache DDUMP_REGS(sc); 24421308Sache /* 24521308Sache * Set tick (CLOCK_RATE) 24621308Sache */ 24721308Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W, 0); 24821308Sache bus_space_write_2(sc->sc_iot, sc->sc_ioh, 24921308Sache RTCL1_L_REG_W, RTCL1_L_HZ / CLOCK_RATE); 25021308Sache 25121308Sache /* 25221308Sache * Initialize timecounter. 25321308Sache */ 25421308Sache sc->sc_tc.tc_get_timecount = vrrtc_get_timecount; 25521308Sache sc->sc_tc.tc_name = "vrrtc"; 25621308Sache sc->sc_tc.tc_counter_mask = 0xffff; 25721308Sache sc->sc_tc.tc_frequency = ETIME_L_HZ; 25821308Sache sc->sc_tc.tc_priv = sc; 25921308Sache sc->sc_tc.tc_quality = 100; 26021308Sache tc_init(&sc->sc_tc); 26121308Sache} 26221308Sache 26321308Sacheuint32_t 26421308Sachevrrtc_get_timecount(struct timecounter *tc) 26521308Sache{ 26621308Sache struct vrrtc_softc *sc = (struct vrrtc_softc *)tc->tc_priv; 26721308Sache bus_space_tag_t iot = sc->sc_iot; 26821308Sache bus_space_handle_t ioh = sc->sc_ioh; 26921308Sache 27021308Sache return bus_space_read_2(iot, ioh, ETIME_L_REG_W); 27121308Sache} 27221308Sache 27321308Sacheint 27421308Sachevrrtc_get(todr_chip_handle_t tch, struct timeval *tvp) 27521308Sache{ 27621308Sache struct vrrtc_softc *sc = (struct vrrtc_softc *)tch->cookie; 27721308Sache bus_space_tag_t iot = sc->sc_iot; 27821308Sache bus_space_handle_t ioh = sc->sc_ioh; 27921308Sache uint32_t timeh; /* elapse time (2*timeh sec) */ 28021308Sache uint32_t timel; /* timel/32768 sec */ 28121308Sache uint64_t sec, usec; 28221308Sache 28321308Sache timeh = bus_space_read_2(iot, ioh, ETIME_H_REG_W); 28421308Sache timeh = (timeh << 16) | bus_space_read_2(iot, ioh, ETIME_M_REG_W); 28521308Sache timel = bus_space_read_2(iot, ioh, ETIME_L_REG_W); 28621308Sache 28721308Sache DPRINTF(("clock_get: timeh %08x timel %08x\n", timeh, timel)); 28821308Sache 28921308Sache timeh -= EPOCHOFF; 29021308Sache sec = (uint64_t)timeh * 2; 29121308Sache sec -= sc->sc_epoch; 29221308Sache tvp->tv_sec = sec; 29321308Sache tvp->tv_sec += timel / ETIME_L_HZ; 29421308Sache 29521308Sache /* scale from 32kHz to 1MHz */ 29621308Sache usec = (timel % ETIME_L_HZ); 29721308Sache usec *= 1000000; 29821308Sache usec /= ETIME_L_HZ; 29921308Sache tvp->tv_usec = usec; 30021308Sache 30121308Sache return 0; 30221308Sache} 30321308Sache 30421308Sacheint 30521308Sachevrrtc_set(todr_chip_handle_t tch, struct timeval *tvp) 30621308Sache{ 30721308Sache struct vrrtc_softc *sc = (struct vrrtc_softc *)tch->cookie; 30821308Sache bus_space_tag_t iot = sc->sc_iot; 30921308Sache bus_space_handle_t ioh = sc->sc_ioh; 31021308Sache uint32_t timeh; /* elapse time (2*timeh sec) */ 31121308Sache uint32_t timel; /* timel/32768 sec */ 31221308Sache int64_t sec, cnt; 31321308Sache 31421308Sache sec = tvp->tv_sec + sc->sc_epoch; 31535486Sache sec += sc->sc_epoch; 31621308Sache timeh = EPOCHOFF + (sec / 2); 31721308Sache timel = sec % 2; 31821308Sache 31921308Sache cnt = tvp->tv_usec; 32021308Sache /* scale from 1MHz to 32kHz */ 32121308Sache cnt *= ETIME_L_HZ; 32221308Sache cnt /= 1000000; 32321308Sache timel += (uint32_t)cnt; 32421308Sache 32521308Sache bus_space_write_2(iot, ioh, ETIME_H_REG_W, (timeh >> 16) & 0xffff); 32635486Sache bus_space_write_2(iot, ioh, ETIME_M_REG_W, timeh & 0xffff); 32735486Sache bus_space_write_2(iot, ioh, ETIME_L_REG_W, timel); 32821308Sache 32921308Sache return 0; 33021308Sache} 33121308Sache 33221308Sachevoid 33321308Sachevrrtc_dump_regs(struct vrrtc_softc *sc) 33421308Sache{ 33535486Sache int timeh; 33621308Sache int timel; 33721308Sache 33835486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_H_REG_W); 33921308Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_M_REG_W); 34021308Sache timel = (timel << 16) 34121308Sache | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ETIME_L_REG_W); 34235486Sache printf("clock_init() Elapse Time %04x%04x\n", timeh, timel); 34335486Sache 34435486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_H_REG_W); 34521308Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_M_REG_W); 34621308Sache timel = (timel << 16) 34721308Sache | bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECMP_L_REG_W); 34821308Sache printf("clock_init() Elapse Compare %04x%04x\n", timeh, timel); 34935486Sache 35035486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_H_REG_W); 35121308Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_L_REG_W); 35235486Sache printf("clock_init() LONG1 %04x%04x\n", timeh, timel); 35335486Sache 35435486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_H_REG_W); 35535486Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL1_CNT_L_REG_W); 35635486Sache printf("clock_init() LONG1 CNTL %04x%04x\n", timeh, timel); 35735486Sache 35835486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_H_REG_W); 35935486Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_L_REG_W); 36035486Sache printf("clock_init() LONG2 %04x%04x\n", timeh, timel); 36135486Sache 36235486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_H_REG_W); 36335486Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, RTCL2_CNT_L_REG_W); 36435486Sache printf("clock_init() LONG2 CNTL %04x%04x\n", timeh, timel); 36535486Sache 36635486Sache if (TCLK_H_REG_W != RTC_NO_REG_W) { 36735486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_H_REG_W); 36835486Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, TCLK_L_REG_W); 36935486Sache printf("clock_init() TCLK %04x%04x\n", timeh, timel); 37035486Sache 37135486Sache timeh = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 37235486Sache TCLK_CNT_H_REG_W); 37335486Sache timel = bus_space_read_2(sc->sc_iot, sc->sc_ioh, 37435486Sache TCLK_CNT_L_REG_W); 37535486Sache printf("clock_init() TCLK CNTL %04x%04x\n", timeh, timel); 37635486Sache } 37735486Sache} 37835486Sache