Home | History | Annotate | Line # | Download | only in marvell
      1 /*	$NetBSD: mvsocrtc.c,v 1.5 2025/09/07 21:45:11 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * Driver for real time clock unit on Marvell kirkwood and possibly other
     31  * SoCs.  Supports only the time/date keeping functions.  No support for
     32  * the rtc unit alarm / interrupt functions.
     33  *
     34  * Written 10/2010 by Brett Slager -- all rights assigned to the NetBSD
     35  * Foundation.
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 __KERNEL_RCSID(0, "$NetBSD: mvsocrtc.c,v 1.5 2025/09/07 21:45:11 thorpej Exp $");
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/device.h>
     44 #include <sys/kernel.h>
     45 
     46 #include <dev/clock_subr.h>
     47 
     48 #include <sys/bus.h>
     49 
     50 #include <arm/marvell/mvsocrtcreg.h>
     51 #include <dev/marvell/marvellvar.h>
     52 
     53 struct mvsocrtc_softc {
     54 	device_t		sc_dev;
     55 	bus_space_tag_t		sc_iot;
     56 	bus_space_handle_t	sc_ioh;
     57 	struct todr_chip_handle	sc_todr;
     58 };
     59 
     60 static int mvsocrtc_match(device_t, cfdata_t, void *);
     61 static void mvsocrtc_attach(device_t, device_t, void *);
     62 static int mvsocrtc_todr_gettime(todr_chip_handle_t, struct clock_ymdhms *);
     63 static int mvsocrtc_todr_settime(todr_chip_handle_t, struct clock_ymdhms *);
     64 
     65 CFATTACH_DECL_NEW(mvsocrtc, sizeof(struct mvsocrtc_softc), mvsocrtc_match,
     66     mvsocrtc_attach, NULL, NULL);
     67 
     68 static int
     69 mvsocrtc_match(device_t parent, cfdata_t cf, void *aux)
     70 {
     71 	struct marvell_attach_args * const mva = aux;
     72 
     73 	if (strcmp(mva->mva_name, cf->cf_name) != 0)
     74 		return 0;
     75 	if (mva->mva_offset == MVA_OFFSET_DEFAULT)
     76 		return 0;
     77 
     78 	mva->mva_size = MVSOCRTC_SIZE;
     79 	return 1;
     80 }
     81 
     82 static void
     83 mvsocrtc_attach(device_t parent, device_t self, void *aux)
     84 {
     85 	struct mvsocrtc_softc * const sc = device_private(self);
     86 	struct marvell_attach_args * const mva = aux;
     87 
     88 	sc->sc_dev = self;
     89 	sc->sc_iot = mva->mva_iot;
     90 
     91 	aprint_normal(": Marvell SoC Real Time Clock\n");
     92 	aprint_naive("\n");
     93 
     94 	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset,
     95 	   mva->mva_size, &sc->sc_ioh)) {
     96 		aprint_error_dev(self, "failed to subregion register space\n");
     97 		return;
     98 	}
     99 
    100 	sc->sc_todr.todr_dev = self;
    101 	sc->sc_todr.todr_gettime_ymdhms = mvsocrtc_todr_gettime;
    102 	sc->sc_todr.todr_settime_ymdhms = mvsocrtc_todr_settime;
    103 
    104 	todr_attach(&sc->sc_todr);
    105 }
    106 
    107 static int
    108 mvsocrtc_todr_gettime(todr_chip_handle_t ch, struct clock_ymdhms *dt)
    109 {
    110 	struct mvsocrtc_softc * const sc = device_private(ch->todr_dev);
    111 	bool tried = false;
    112 	uint32_t rtcdate, rtctime;
    113 	uint8_t rtcday, rtchour, rtcmin, rtcmonth, rtcsec, rtcyear;
    114 
    115 again:
    116 	/* read the rtc date and time registers */
    117 	rtcdate = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSOCRTC_DATE);
    118 	rtctime = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSOCRTC_TIME);
    119 
    120 	rtcyear = (rtcdate >> MVSOCRTC_YEAR_OFFSET) & MVSOCRTC_YEAR_MASK;
    121 	rtcmonth = (rtcdate >> MVSOCRTC_MONTH_OFFSET) & MVSOCRTC_MONTH_MASK;
    122 	rtcday = (rtcdate >> MVSOCRTC_DAY_OFFSET) & MVSOCRTC_DAY_MASK;
    123 
    124 	rtchour = (rtctime >> MVSOCRTC_HOUR_OFFSET) & MVSOCRTC_HOUR_MASK;
    125 	rtcmin = (rtctime >> MVSOCRTC_MINUTE_OFFSET) & MVSOCRTC_MINUTE_MASK;
    126 	rtcsec = (rtctime >> MVSOCRTC_SECOND_OFFSET) & MVSOCRTC_SECOND_MASK;
    127 
    128 	/*
    129 	 * if seconds == 0, we may have read while the registers were
    130 	 * updating.  Read again to get consistant data.
    131 	 */
    132 	if (rtcsec == 0 && !tried) {
    133 		tried = true;
    134 		goto again;
    135 	}
    136 
    137 	/*
    138 	 * Assume year "00" to be year 2000.
    139 	 * XXXX this assumption will fail in 2100, but somehow I don't think
    140 	 * I or the hardware will be functioning to see it.
    141 	 */
    142 	dt->dt_year = bcdtobin(rtcyear) + 2000;
    143 	dt->dt_mon = bcdtobin(rtcmonth);
    144 	dt->dt_day = bcdtobin(rtcday);
    145 	dt->dt_hour = bcdtobin(rtchour);
    146 	dt->dt_min = bcdtobin(rtcmin);
    147 	dt->dt_sec = bcdtobin(rtcsec);
    148 
    149 	return 0;
    150 }
    151 
    152 static int
    153 mvsocrtc_todr_settime(todr_chip_handle_t ch, struct clock_ymdhms *dt)
    154 {
    155 	struct mvsocrtc_softc * const sc = device_private(ch->todr_dev);
    156 	uint32_t reg;
    157 
    158 	/* compose & write time register contents */
    159 	reg = (bintobcd(dt->dt_sec) << MVSOCRTC_SECOND_OFFSET) |
    160 	   (bintobcd(dt->dt_min) << MVSOCRTC_MINUTE_OFFSET) |
    161 	   (bintobcd(dt->dt_hour) << MVSOCRTC_HOUR_OFFSET) |
    162 	   (bintobcd(dt->dt_wday) << MVSOCRTC_WDAY_OFFSET);
    163 
    164 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSOCRTC_TIME, reg);
    165 
    166 	/* compose & write date register contents */
    167 	reg = (bintobcd(dt->dt_day) << MVSOCRTC_DAY_OFFSET) |
    168 	   (bintobcd(dt->dt_mon) << MVSOCRTC_MONTH_OFFSET) |
    169 	   (bintobcd(dt->dt_year % 100) << MVSOCRTC_YEAR_OFFSET);
    170 
    171 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSOCRTC_DATE, reg);
    172 
    173 	return 0;
    174 }
    175