imxrtc.c revision 1.1
1/* $OpenBSD: imxrtc.c,v 1.1 2018/06/16 14:11:35 kettenis Exp $ */ 2/* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/systm.h> 20#include <sys/device.h> 21 22#include <machine/intr.h> 23#include <machine/bus.h> 24#include <machine/fdt.h> 25 26#include <dev/ofw/openfirm.h> 27#include <dev/ofw/fdt.h> 28#include <dev/ofw/ofw_misc.h> 29 30#include <dev/clock_subr.h> 31 32extern todr_chip_handle_t todr_handle; 33 34/* Registers. */ 35#define LPCR 0x38 36#define LPCR_SRTC_ENV (1 << 0) 37#define LPSR 0x4c 38#define LPSRTCMR 0x50 39#define LPSRTCLR 0x54 40 41#define HREAD4(sc, reg) \ 42 (regmap_read_4((sc)->sc_rm, (reg))) 43#define HWRITE4(sc, reg, val) \ 44 regmap_write_4((sc)->sc_rm, (reg), (val)) 45 46struct imxrtc_softc { 47 struct device sc_dev; 48 struct regmap *sc_rm; 49 50 struct todr_chip_handle sc_todr; 51}; 52 53int imxrtc_match(struct device *, void *, void *); 54void imxrtc_attach(struct device *, struct device *, void *); 55 56struct cfattach imxrtc_ca = { 57 sizeof (struct imxrtc_softc), imxrtc_match, imxrtc_attach 58}; 59 60struct cfdriver imxrtc_cd = { 61 NULL, "imxrtc", DV_DULL 62}; 63 64int imxrtc_gettime(struct todr_chip_handle *, struct timeval *); 65int imxrtc_settime(struct todr_chip_handle *, struct timeval *); 66 67int 68imxrtc_match(struct device *parent, void *match, void *aux) 69{ 70 struct fdt_attach_args *faa = aux; 71 72 return OF_is_compatible(faa->fa_node, "fsl,sec-v4.0-mon-rtc-lp"); 73} 74 75void 76imxrtc_attach(struct device *parent, struct device *self, void *aux) 77{ 78 struct imxrtc_softc *sc = (struct imxrtc_softc *)self; 79 struct fdt_attach_args *faa = aux; 80 uint32_t regmap; 81 82 regmap = OF_getpropint(faa->fa_node, "regmap", 0); 83 sc->sc_rm = regmap_byphandle(regmap); 84 if (sc->sc_rm == NULL) { 85 printf(": no registers\n"); 86 return; 87 } 88 89 printf("\n"); 90 91 sc->sc_todr.cookie = sc; 92 sc->sc_todr.todr_gettime = imxrtc_gettime; 93 sc->sc_todr.todr_settime = imxrtc_settime; 94 todr_handle = &sc->sc_todr; 95} 96 97int 98imxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 99{ 100 struct imxrtc_softc *sc = handle->cookie; 101 uint64_t mr, lr, srtc, srtc2; 102 uint32_t cr; 103 int retries; 104 int s; 105 106 cr = HREAD4(sc, LPCR); 107 if ((cr & LPCR_SRTC_ENV) == 0) 108 return EINVAL; 109 110 /* 111 * Read counters until we read back the same values twice. 112 * This shouldn't take more than two attempts; throw in an 113 * extra round just in case. 114 */ 115 s = splhigh(); 116 mr = HREAD4(sc, LPSRTCMR); 117 lr = HREAD4(sc, LPSRTCLR); 118 srtc = (mr << 32) | lr; 119 for (retries = 3; retries > 0; retries--) { 120 mr = HREAD4(sc, LPSRTCMR); 121 lr = HREAD4(sc, LPSRTCLR); 122 srtc2 = (mr << 32) | lr; 123 if (srtc == srtc2) 124 break; 125 srtc = srtc2; 126 } 127 splx(s); 128 if (retries == 0) 129 return EIO; 130 131 tv->tv_sec = srtc / 32768; 132 tv->tv_usec = ((srtc % 32768) * 1000000U) / 32768U; 133 return 0; 134} 135 136int 137imxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 138{ 139 struct imxrtc_softc *sc = handle->cookie; 140 uint64_t srtc; 141 uint32_t cr; 142 int timeout; 143 144 /* Disable RTC. */ 145 cr = HREAD4(sc, LPCR); 146 cr &= ~LPCR_SRTC_ENV; 147 HWRITE4(sc, LPCR, cr); 148 for (timeout = 1000000; timeout > 0; timeout--) { 149 if ((HREAD4(sc, LPCR) & LPCR_SRTC_ENV) == 0) 150 break; 151 } 152 153 srtc = tv->tv_sec * 32768 + (tv->tv_usec * 32768U / 1000000U); 154 HWRITE4(sc, LPSRTCMR, srtc >> 32); 155 HWRITE4(sc, LPSRTCLR, srtc & 0xffffffff); 156 157 /* Enable RTC. */ 158 cr |= LPCR_SRTC_ENV; 159 HWRITE4(sc, LPCR, cr); 160 for (timeout = 1000000; timeout > 0; timeout--) { 161 if (HREAD4(sc, LPCR) & LPCR_SRTC_ENV) 162 break; 163 } 164 165 return 0; 166} 167