1 1.9 thorpej /* $NetBSD: pxa2x0_rtc.c,v 1.9 2025/09/07 21:45:12 thorpej Exp $ */ 2 1.1 nonaka 3 1.1 nonaka /* 4 1.1 nonaka * Copyright (c) 2007 NONAKA Kimihiro <nonaka (at) netbsd.org> 5 1.1 nonaka * 6 1.1 nonaka * Redistribution and use in source and binary forms, with or without 7 1.1 nonaka * modification, are permitted provided that the following conditions 8 1.1 nonaka * are met: 9 1.1 nonaka * 1. Redistributions of source code must retain the above copyright 10 1.1 nonaka * notice, this list of conditions and the following disclaimer. 11 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 nonaka * notice, this list of conditions and the following disclaimer in the 13 1.1 nonaka * documentation and/or other materials provided with the distribution. 14 1.1 nonaka * 15 1.1 nonaka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 1.1 nonaka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 1.1 nonaka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 1.1 nonaka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 1.1 nonaka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 1.1 nonaka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 1.1 nonaka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 1.1 nonaka */ 23 1.1 nonaka 24 1.1 nonaka #include <sys/cdefs.h> 25 1.9 thorpej __KERNEL_RCSID(0, "$NetBSD: pxa2x0_rtc.c,v 1.9 2025/09/07 21:45:12 thorpej Exp $"); 26 1.1 nonaka 27 1.1 nonaka #include <sys/param.h> 28 1.1 nonaka #include <sys/systm.h> 29 1.1 nonaka #include <sys/device.h> 30 1.1 nonaka #include <sys/kernel.h> 31 1.1 nonaka 32 1.1 nonaka #include <dev/clock_subr.h> 33 1.1 nonaka 34 1.5 dyoung #include <sys/bus.h> 35 1.1 nonaka 36 1.1 nonaka #include <arm/xscale/pxa2x0cpu.h> 37 1.1 nonaka #include <arm/xscale/pxa2x0reg.h> 38 1.1 nonaka #include <arm/xscale/pxa2x0var.h> 39 1.1 nonaka 40 1.1 nonaka #ifdef PXARTC_DEBUG 41 1.1 nonaka #define DPRINTF(s) printf s 42 1.1 nonaka #else 43 1.1 nonaka #define DPRINTF(s) 44 1.1 nonaka #endif 45 1.1 nonaka 46 1.1 nonaka struct pxartc_softc { 47 1.4 nonaka device_t sc_dev; 48 1.1 nonaka bus_space_tag_t sc_iot; 49 1.1 nonaka bus_space_handle_t sc_ioh; 50 1.1 nonaka 51 1.1 nonaka struct todr_chip_handle sc_todr; 52 1.1 nonaka 53 1.1 nonaka int sc_flags; 54 1.1 nonaka #define FLAG_WRISTWATCH (1 << 0) 55 1.1 nonaka }; 56 1.1 nonaka 57 1.6 chs static int pxartc_match(device_t, cfdata_t, void *); 58 1.6 chs static void pxartc_attach(device_t, device_t, void *); 59 1.1 nonaka 60 1.4 nonaka CFATTACH_DECL_NEW(pxartc, sizeof(struct pxartc_softc), 61 1.1 nonaka pxartc_match, pxartc_attach, NULL, NULL); 62 1.1 nonaka 63 1.1 nonaka /* todr(9) interface */ 64 1.3 tsutsui static int pxartc_todr_gettime(todr_chip_handle_t, struct timeval *); 65 1.3 tsutsui static int pxartc_todr_settime(todr_chip_handle_t, struct timeval *); 66 1.7 thorpej static int pxartc_wristwatch_gettime(todr_chip_handle_t, struct clock_ymdhms *); 67 1.7 thorpej static int pxartc_wristwatch_settime(todr_chip_handle_t, struct clock_ymdhms *); 68 1.1 nonaka 69 1.1 nonaka static int 70 1.6 chs pxartc_match(device_t parent, cfdata_t cf, void *aux) 71 1.1 nonaka { 72 1.1 nonaka struct pxaip_attach_args *pxa = aux; 73 1.1 nonaka 74 1.2 kiyohara if (strcmp(pxa->pxa_name, cf->cf_name) != 0) 75 1.2 kiyohara return 0; 76 1.1 nonaka 77 1.4 nonaka if (pxa->pxa_size == 0) { 78 1.4 nonaka pxa->pxa_size = 79 1.4 nonaka CPU_IS_PXA270 ? PXA270_RTC_SIZE : PXA250_RTC_SIZE; 80 1.4 nonaka } 81 1.1 nonaka return 1; 82 1.1 nonaka } 83 1.1 nonaka 84 1.1 nonaka static void 85 1.6 chs pxartc_attach(device_t parent, device_t self, void *aux) 86 1.1 nonaka { 87 1.4 nonaka struct pxartc_softc *sc = device_private(self); 88 1.1 nonaka struct pxaip_attach_args *pxa = aux; 89 1.1 nonaka 90 1.4 nonaka sc->sc_dev = self; 91 1.1 nonaka sc->sc_iot = pxa->pxa_iot; 92 1.1 nonaka 93 1.4 nonaka aprint_normal(": Real-time Clock\n"); 94 1.1 nonaka 95 1.2 kiyohara if (bus_space_map(sc->sc_iot, pxa->pxa_addr, pxa->pxa_size, 0, 96 1.1 nonaka &sc->sc_ioh)) { 97 1.1 nonaka aprint_error("%s: couldn't map registers\n", 98 1.4 nonaka device_xname(sc->sc_dev)); 99 1.1 nonaka return; 100 1.1 nonaka } 101 1.1 nonaka 102 1.7 thorpej memset(&sc->sc_todr, 0, sizeof(sc->sc_todr)); 103 1.9 thorpej sc->sc_todr.todr_dev = self; 104 1.1 nonaka if (pxa->pxa_size == PXA270_RTC_SIZE) { 105 1.1 nonaka aprint_normal("%s: using wristwatch register\n", 106 1.4 nonaka device_xname(sc->sc_dev)); 107 1.1 nonaka sc->sc_flags |= FLAG_WRISTWATCH; 108 1.7 thorpej sc->sc_todr.todr_gettime_ymdhms = pxartc_wristwatch_gettime; 109 1.7 thorpej sc->sc_todr.todr_settime_ymdhms = pxartc_wristwatch_settime; 110 1.7 thorpej } else { 111 1.7 thorpej sc->sc_todr.todr_gettime = pxartc_todr_gettime; 112 1.7 thorpej sc->sc_todr.todr_settime = pxartc_todr_settime; 113 1.1 nonaka } 114 1.1 nonaka 115 1.1 nonaka todr_attach(&sc->sc_todr); 116 1.1 nonaka } 117 1.1 nonaka 118 1.1 nonaka static int 119 1.3 tsutsui pxartc_todr_gettime(todr_chip_handle_t ch, struct timeval *tv) 120 1.1 nonaka { 121 1.9 thorpej struct pxartc_softc *sc = device_private(ch->todr_dev); 122 1.1 nonaka 123 1.7 thorpej tv->tv_sec = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RTC_RCNR); 124 1.7 thorpej tv->tv_usec = 0; 125 1.1 nonaka #ifdef PXARTC_DEBUG 126 1.8 andvar struct clock_ymdhms dt; 127 1.7 thorpej DPRINTF(("%s: RCNR = %08llx\n", device_xname(sc->sc_dev), 128 1.7 thorpej tv->tv_sec)); 129 1.7 thorpej clock_secs_to_ymdhms(tv->tv_sec, &dt); 130 1.8 andvar DPRINTF(("%s: %02lld/%02d/%02d %02d:%02d:%02d\n", 131 1.7 thorpej device_xname(sc->sc_dev), 132 1.7 thorpej dt.dt_year, dt.dt_mon, dt.dt_day, 133 1.7 thorpej dt.dt_hour, dt.dt_min, dt.dt_sec)); 134 1.1 nonaka #endif 135 1.1 nonaka return 0; 136 1.1 nonaka } 137 1.1 nonaka 138 1.1 nonaka static int 139 1.3 tsutsui pxartc_todr_settime(todr_chip_handle_t ch, struct timeval *tv) 140 1.1 nonaka { 141 1.9 thorpej struct pxartc_softc *sc = device_private(ch->todr_dev); 142 1.1 nonaka 143 1.1 nonaka #ifdef PXARTC_DEBUG 144 1.8 andvar struct clock_ymdhms dt; 145 1.7 thorpej DPRINTF(("%s: RCNR = %08llx\n", device_xname(sc->sc_dev), 146 1.7 thorpej tv->tv_sec)); 147 1.7 thorpej clock_secs_to_ymdhms(tv->tv_sec, &dt); 148 1.8 andvar DPRINTF(("%s: %02lld/%02d/%02d %02d:%02d:%02d\n", 149 1.7 thorpej device_xname(sc->sc_dev), 150 1.7 thorpej dt.dt_year, dt.dt_mon, dt.dt_day, 151 1.7 thorpej dt.dt_hour, dt.dt_min, dt.dt_sec)); 152 1.1 nonaka #endif 153 1.7 thorpej bus_space_write_4(sc->sc_iot, sc->sc_ioh, RTC_RCNR, tv->tv_sec); 154 1.1 nonaka #ifdef PXARTC_DEBUG 155 1.7 thorpej { 156 1.1 nonaka uint32_t cntr; 157 1.1 nonaka delay(1); 158 1.1 nonaka cntr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RTC_RCNR); 159 1.4 nonaka DPRINTF(("%s: new RCNR = %08x\n", device_xname(sc->sc_dev), 160 1.4 nonaka cntr)); 161 1.1 nonaka clock_secs_to_ymdhms(cntr, &dt); 162 1.8 andvar DPRINTF(("%s: %02lld/%02d/%02d %02d:%02d:%02d\n", 163 1.4 nonaka device_xname(sc->sc_dev), 164 1.1 nonaka dt.dt_year, dt.dt_mon, dt.dt_day, 165 1.1 nonaka dt.dt_hour, dt.dt_min, dt.dt_sec)); 166 1.7 thorpej } 167 1.1 nonaka #endif 168 1.1 nonaka return 0; 169 1.1 nonaka } 170 1.1 nonaka 171 1.1 nonaka static int 172 1.7 thorpej pxartc_wristwatch_gettime(todr_chip_handle_t ch, struct clock_ymdhms *dt) 173 1.1 nonaka { 174 1.9 thorpej struct pxartc_softc *sc = device_private(ch->todr_dev); 175 1.1 nonaka uint32_t dayr, yearr; 176 1.1 nonaka int s; 177 1.1 nonaka 178 1.7 thorpej DPRINTF(("%s: pxartc_wristwatch_gettime()\n", 179 1.7 thorpej device_xname(sc->sc_dev))); 180 1.1 nonaka 181 1.1 nonaka s = splhigh(); 182 1.1 nonaka dayr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RTC_RDCR); 183 1.1 nonaka yearr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, RTC_RYCR); 184 1.1 nonaka splx(s); 185 1.1 nonaka 186 1.4 nonaka DPRINTF(("%s: RDCR = %08x, RYCR = %08x\n", device_xname(sc->sc_dev), 187 1.1 nonaka dayr, yearr)); 188 1.1 nonaka 189 1.1 nonaka dt->dt_sec = (dayr >> RDCR_SECOND_SHIFT) & RDCR_SECOND_MASK; 190 1.1 nonaka dt->dt_min = (dayr >> RDCR_MINUTE_SHIFT) & RDCR_MINUTE_MASK; 191 1.1 nonaka dt->dt_hour = (dayr >> RDCR_HOUR_SHIFT) & RDCR_HOUR_MASK; 192 1.1 nonaka dt->dt_day = (yearr >> RYCR_DOM_SHIFT) & RYCR_DOM_MASK; 193 1.1 nonaka dt->dt_mon = (yearr >> RYCR_MONTH_SHIFT) & RYCR_MONTH_MASK; 194 1.1 nonaka dt->dt_year = (yearr >> RYCR_YEAR_SHIFT) & RYCR_YEAR_MASK; 195 1.1 nonaka 196 1.8 andvar DPRINTF(("%s: %02lld/%02d/%02d %02d:%02d:%02d\n", 197 1.4 nonaka device_xname(sc->sc_dev), 198 1.1 nonaka dt->dt_year, dt->dt_mon, dt->dt_day, 199 1.1 nonaka dt->dt_hour, dt->dt_min, dt->dt_sec)); 200 1.1 nonaka 201 1.7 thorpej return 0; 202 1.1 nonaka } 203 1.1 nonaka 204 1.1 nonaka static int 205 1.7 thorpej pxartc_wristwatch_settime(todr_chip_handle_t ch, struct clock_ymdhms *dt) 206 1.1 nonaka { 207 1.9 thorpej struct pxartc_softc *sc = device_private(ch->todr_dev); 208 1.1 nonaka uint32_t dayr, yearr; 209 1.1 nonaka uint32_t wom; /* week of month: 1=first week of month */ 210 1.1 nonaka int s; 211 1.1 nonaka 212 1.7 thorpej DPRINTF(("%s: pxartc_wristwatch_settime()\n", 213 1.7 thorpej device_xname(sc->sc_dev))); 214 1.1 nonaka 215 1.8 andvar DPRINTF(("%s: %02lld/%02d/%02d %02d:%02d:%02d\n", 216 1.4 nonaka device_xname(sc->sc_dev), 217 1.1 nonaka dt->dt_year, dt->dt_mon, dt->dt_day, 218 1.1 nonaka dt->dt_hour, dt->dt_min, dt->dt_sec)); 219 1.1 nonaka 220 1.1 nonaka dayr = (dt->dt_sec & RDCR_SECOND_MASK) << RDCR_SECOND_SHIFT; 221 1.1 nonaka dayr |= (dt->dt_min & RDCR_MINUTE_MASK) << RDCR_MINUTE_SHIFT; 222 1.1 nonaka dayr |= (dt->dt_hour & RDCR_HOUR_MASK) << RDCR_HOUR_SHIFT; 223 1.1 nonaka dayr |= ((dt->dt_wday + 1) & RDCR_DOW_MASK) << RDCR_DOW_SHIFT; 224 1.1 nonaka wom = ((dt->dt_day - 1 + 6 - dt->dt_wday) / 7) + 1; 225 1.1 nonaka dayr |= (wom & RDCR_WOM_MASK) << RDCR_WOM_SHIFT; 226 1.1 nonaka yearr = (dt->dt_day & RYCR_DOM_MASK) << RYCR_DOM_SHIFT; 227 1.1 nonaka yearr |= (dt->dt_mon & RYCR_MONTH_MASK) << RYCR_MONTH_SHIFT; 228 1.1 nonaka yearr |= (dt->dt_year & RYCR_YEAR_MASK) << RYCR_YEAR_SHIFT; 229 1.1 nonaka 230 1.4 nonaka DPRINTF(("%s: RDCR = %08x, RYCR = %08x\n", device_xname(sc->sc_dev), 231 1.1 nonaka dayr, yearr)); 232 1.1 nonaka 233 1.1 nonaka /* 234 1.1 nonaka * We must write RYCR register before write RDCR register. 235 1.1 nonaka * 236 1.1 nonaka * See PXA270 Processor Family Developer's Manual p.946 237 1.1 nonaka * 21.4.2.3.1 Writing RDCR and RYCR Counter Registers with Valid Data. 238 1.1 nonaka */ 239 1.1 nonaka s = splhigh(); 240 1.1 nonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, RTC_RYCR, yearr); 241 1.1 nonaka bus_space_write_4(sc->sc_iot, sc->sc_ioh, RTC_RDCR, dayr); 242 1.1 nonaka splx(s); 243 1.1 nonaka 244 1.1 nonaka #ifdef PXARTC_DEBUG 245 1.1 nonaka { 246 1.1 nonaka struct clock_ymdhms dummy; 247 1.8 andvar pxartc_wristwatch_gettime(ch, &dummy); 248 1.1 nonaka } 249 1.1 nonaka #endif 250 1.1 nonaka 251 1.7 thorpej return 0; 252 1.1 nonaka } 253