jcs's openbsd hax
openbsd
at jcs 165 lines 4.2 kB view raw
1/* $OpenBSD: imxrtc.c,v 1.3 2022/10/17 19:09:46 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 32/* Registers. */ 33#define LPCR 0x38 34#define LPCR_SRTC_ENV (1 << 0) 35#define LPSR 0x4c 36#define LPSRTCMR 0x50 37#define LPSRTCLR 0x54 38 39#define HREAD4(sc, reg) \ 40 (regmap_read_4((sc)->sc_rm, (reg))) 41#define HWRITE4(sc, reg, val) \ 42 regmap_write_4((sc)->sc_rm, (reg), (val)) 43 44struct imxrtc_softc { 45 struct device sc_dev; 46 struct regmap *sc_rm; 47 48 struct todr_chip_handle sc_todr; 49}; 50 51int imxrtc_match(struct device *, void *, void *); 52void imxrtc_attach(struct device *, struct device *, void *); 53 54const struct cfattach imxrtc_ca = { 55 sizeof (struct imxrtc_softc), imxrtc_match, imxrtc_attach 56}; 57 58struct cfdriver imxrtc_cd = { 59 NULL, "imxrtc", DV_DULL 60}; 61 62int imxrtc_gettime(struct todr_chip_handle *, struct timeval *); 63int imxrtc_settime(struct todr_chip_handle *, struct timeval *); 64 65int 66imxrtc_match(struct device *parent, void *match, void *aux) 67{ 68 struct fdt_attach_args *faa = aux; 69 70 return OF_is_compatible(faa->fa_node, "fsl,sec-v4.0-mon-rtc-lp"); 71} 72 73void 74imxrtc_attach(struct device *parent, struct device *self, void *aux) 75{ 76 struct imxrtc_softc *sc = (struct imxrtc_softc *)self; 77 struct fdt_attach_args *faa = aux; 78 uint32_t regmap; 79 80 regmap = OF_getpropint(faa->fa_node, "regmap", 0); 81 sc->sc_rm = regmap_byphandle(regmap); 82 if (sc->sc_rm == NULL) { 83 printf(": no registers\n"); 84 return; 85 } 86 87 printf("\n"); 88 89 sc->sc_todr.cookie = sc; 90 sc->sc_todr.todr_gettime = imxrtc_gettime; 91 sc->sc_todr.todr_settime = imxrtc_settime; 92 sc->sc_todr.todr_quality = 0; 93 todr_attach(&sc->sc_todr); 94} 95 96int 97imxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 98{ 99 struct imxrtc_softc *sc = handle->cookie; 100 uint64_t mr, lr, srtc, srtc2; 101 uint32_t cr; 102 int retries; 103 int s; 104 105 cr = HREAD4(sc, LPCR); 106 if ((cr & LPCR_SRTC_ENV) == 0) 107 return EINVAL; 108 109 /* 110 * Read counters until we read back the same values twice. 111 * This shouldn't take more than two attempts; throw in an 112 * extra round just in case. 113 */ 114 s = splhigh(); 115 mr = HREAD4(sc, LPSRTCMR); 116 lr = HREAD4(sc, LPSRTCLR); 117 srtc = (mr << 32) | lr; 118 for (retries = 3; retries > 0; retries--) { 119 mr = HREAD4(sc, LPSRTCMR); 120 lr = HREAD4(sc, LPSRTCLR); 121 srtc2 = (mr << 32) | lr; 122 if (srtc == srtc2) 123 break; 124 srtc = srtc2; 125 } 126 splx(s); 127 if (retries == 0) 128 return EIO; 129 130 tv->tv_sec = srtc / 32768; 131 tv->tv_usec = ((srtc % 32768) * 1000000U) / 32768U; 132 return 0; 133} 134 135int 136imxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 137{ 138 struct imxrtc_softc *sc = handle->cookie; 139 uint64_t srtc; 140 uint32_t cr; 141 int timeout; 142 143 /* Disable RTC. */ 144 cr = HREAD4(sc, LPCR); 145 cr &= ~LPCR_SRTC_ENV; 146 HWRITE4(sc, LPCR, cr); 147 for (timeout = 1000000; timeout > 0; timeout--) { 148 if ((HREAD4(sc, LPCR) & LPCR_SRTC_ENV) == 0) 149 break; 150 } 151 152 srtc = tv->tv_sec * 32768 + (tv->tv_usec * 32768U / 1000000U); 153 HWRITE4(sc, LPSRTCMR, srtc >> 32); 154 HWRITE4(sc, LPSRTCLR, srtc & 0xffffffff); 155 156 /* Enable RTC. */ 157 cr |= LPCR_SRTC_ENV; 158 HWRITE4(sc, LPCR, cr); 159 for (timeout = 1000000; timeout > 0; timeout--) { 160 if (HREAD4(sc, LPCR) & LPCR_SRTC_ENV) 161 break; 162 } 163 164 return 0; 165}