rtcsram.c revision 1.1
1/* $NetBSD: rtcsram.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $ */ 2 3/*- 4 * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca> 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 AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: rtcsram.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $"); 31 32#include <sys/param.h> 33#include <sys/bus.h> 34#include <sys/device.h> 35#include <sys/systm.h> 36#include <dev/clock_subr.h> 37 38#include <lib/libkern/libkern.h> 39 40#include "exi.h" 41 42#define WII_RTCSRAM_ID 0xfffff308 43#define WII_RTCSRAM_FREQ EXI_FREQ_8MHZ 44 45#define RTC_BASE 0x20000000 46#define SRAM_BASE 0x20000100 47 48#define WRITE_OFFSET 0x80000000 49 50struct rtcsram_sram { 51 uint16_t checksum[2]; 52 uint32_t ead[2]; 53 int32_t counter_bias; 54 int8_t display_offset_h; 55 uint8_t ntd; 56 uint8_t language; 57 uint8_t flags; 58 uint16_t flash_id[12]; 59 uint32_t wireless_keyboard_id; 60 uint32_t wireless_pad_id[2]; 61 uint8_t last_dvd_errorcode; 62 uint8_t padding1; 63 uint16_t flash_id_checksum[2]; 64 uint16_t padding2; 65} __aligned(32); 66CTASSERT(sizeof(struct rtcsram_sram) == 64); 67 68struct rtcsram_softc { 69 device_t sc_dev; 70 struct todr_chip_handle sc_todr; 71 72 uint8_t sc_chan; 73 uint8_t sc_device; 74 75 struct rtcsram_sram sc_sram; 76}; 77 78static int rtcsram_match(device_t, cfdata_t, void *); 79static void rtcsram_attach(device_t, device_t, void *); 80 81static uint32_t rtcsram_read_4(struct rtcsram_softc *, uint32_t); 82static void rtcsram_write_4(struct rtcsram_softc *, uint32_t, uint32_t); 83static void rtcsram_read_buf(struct rtcsram_softc *, uint32_t, void *, 84 size_t); 85 86static int rtcsram_gettime(todr_chip_handle_t, struct timeval *); 87static int rtcsram_settime(todr_chip_handle_t, struct timeval *); 88 89CFATTACH_DECL_NEW(rtcsram, sizeof(struct rtcsram_softc), 90 rtcsram_match, rtcsram_attach, NULL, NULL); 91 92static int 93rtcsram_match(device_t parent, cfdata_t cf, void *aux) 94{ 95 struct exi_attach_args * const eaa = aux; 96 97 return eaa->eaa_id == WII_RTCSRAM_ID; 98} 99 100static void 101rtcsram_attach(device_t parent, device_t self, void *aux) 102{ 103 struct rtcsram_softc * const sc = device_private(self); 104 struct exi_attach_args * const eaa = aux; 105 106 aprint_naive("\n"); 107 aprint_normal(": RTC/SRAM\n"); 108 109 sc->sc_dev = self; 110 sc->sc_chan = eaa->eaa_chan; 111 sc->sc_device = eaa->eaa_device; 112 113 rtcsram_read_buf(sc, SRAM_BASE, &sc->sc_sram, sizeof(sc->sc_sram)); 114 hexdump(aprint_debug, device_xname(self), &sc->sc_sram, 115 sizeof(sc->sc_sram)); 116 117 sc->sc_todr.todr_dev = self; 118 sc->sc_todr.todr_gettime = rtcsram_gettime; 119 sc->sc_todr.todr_settime = rtcsram_settime; 120 todr_attach(&sc->sc_todr); 121} 122 123static uint32_t 124rtcsram_read_4(struct rtcsram_softc *sc, uint32_t offset) 125{ 126 uint32_t val; 127 128 exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 129 exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 130 exi_recv_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val)); 131 exi_unselect(sc->sc_chan); 132 133 return val; 134} 135 136static void 137rtcsram_write_4(struct rtcsram_softc *sc, uint32_t offset, uint32_t val) 138{ 139 offset |= WRITE_OFFSET; 140 141 exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 142 exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 143 exi_send_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val)); 144 exi_unselect(sc->sc_chan); 145} 146 147static void 148rtcsram_read_buf(struct rtcsram_softc *sc, uint32_t offset, void *data, 149 size_t datalen) 150{ 151 exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 152 exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 153 exi_recv_dma(sc->sc_chan, sc->sc_device, data, datalen); 154 exi_unselect(sc->sc_chan); 155} 156 157static int 158rtcsram_gettime(todr_chip_handle_t ch, struct timeval *tv) 159{ 160 struct rtcsram_softc * const sc = device_private(ch->todr_dev); 161 uint32_t val; 162 163 val = rtcsram_read_4(sc, RTC_BASE); 164 tv->tv_sec = (uint64_t)val; 165 tv->tv_usec = 0; 166 167 return 0; 168} 169 170static int 171rtcsram_settime(todr_chip_handle_t ch, struct timeval *tv) 172{ 173 struct rtcsram_softc * const sc = device_private(ch->todr_dev); 174 175 rtcsram_write_4(sc, RTC_BASE, tv->tv_sec); 176 177 return 0; 178} 179