11.1Sjmcneill/* $NetBSD: rtcsram.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill#include <sys/cdefs.h> 301.1Sjmcneill__KERNEL_RCSID(0, "$NetBSD: rtcsram.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include <sys/param.h> 331.1Sjmcneill#include <sys/bus.h> 341.1Sjmcneill#include <sys/device.h> 351.1Sjmcneill#include <sys/systm.h> 361.1Sjmcneill#include <dev/clock_subr.h> 371.1Sjmcneill 381.1Sjmcneill#include <lib/libkern/libkern.h> 391.1Sjmcneill 401.1Sjmcneill#include "exi.h" 411.1Sjmcneill 421.1Sjmcneill#define WII_RTCSRAM_ID 0xfffff308 431.1Sjmcneill#define WII_RTCSRAM_FREQ EXI_FREQ_8MHZ 441.1Sjmcneill 451.1Sjmcneill#define RTC_BASE 0x20000000 461.1Sjmcneill#define SRAM_BASE 0x20000100 471.1Sjmcneill 481.1Sjmcneill#define WRITE_OFFSET 0x80000000 491.1Sjmcneill 501.1Sjmcneillstruct rtcsram_sram { 511.1Sjmcneill uint16_t checksum[2]; 521.1Sjmcneill uint32_t ead[2]; 531.1Sjmcneill int32_t counter_bias; 541.1Sjmcneill int8_t display_offset_h; 551.1Sjmcneill uint8_t ntd; 561.1Sjmcneill uint8_t language; 571.1Sjmcneill uint8_t flags; 581.1Sjmcneill uint16_t flash_id[12]; 591.1Sjmcneill uint32_t wireless_keyboard_id; 601.1Sjmcneill uint32_t wireless_pad_id[2]; 611.1Sjmcneill uint8_t last_dvd_errorcode; 621.1Sjmcneill uint8_t padding1; 631.1Sjmcneill uint16_t flash_id_checksum[2]; 641.1Sjmcneill uint16_t padding2; 651.1Sjmcneill} __aligned(32); 661.1SjmcneillCTASSERT(sizeof(struct rtcsram_sram) == 64); 671.1Sjmcneill 681.1Sjmcneillstruct rtcsram_softc { 691.1Sjmcneill device_t sc_dev; 701.1Sjmcneill struct todr_chip_handle sc_todr; 711.1Sjmcneill 721.1Sjmcneill uint8_t sc_chan; 731.1Sjmcneill uint8_t sc_device; 741.1Sjmcneill 751.1Sjmcneill struct rtcsram_sram sc_sram; 761.1Sjmcneill}; 771.1Sjmcneill 781.1Sjmcneillstatic int rtcsram_match(device_t, cfdata_t, void *); 791.1Sjmcneillstatic void rtcsram_attach(device_t, device_t, void *); 801.1Sjmcneill 811.1Sjmcneillstatic uint32_t rtcsram_read_4(struct rtcsram_softc *, uint32_t); 821.1Sjmcneillstatic void rtcsram_write_4(struct rtcsram_softc *, uint32_t, uint32_t); 831.1Sjmcneillstatic void rtcsram_read_buf(struct rtcsram_softc *, uint32_t, void *, 841.1Sjmcneill size_t); 851.1Sjmcneill 861.1Sjmcneillstatic int rtcsram_gettime(todr_chip_handle_t, struct timeval *); 871.1Sjmcneillstatic int rtcsram_settime(todr_chip_handle_t, struct timeval *); 881.1Sjmcneill 891.1SjmcneillCFATTACH_DECL_NEW(rtcsram, sizeof(struct rtcsram_softc), 901.1Sjmcneill rtcsram_match, rtcsram_attach, NULL, NULL); 911.1Sjmcneill 921.1Sjmcneillstatic int 931.1Sjmcneillrtcsram_match(device_t parent, cfdata_t cf, void *aux) 941.1Sjmcneill{ 951.1Sjmcneill struct exi_attach_args * const eaa = aux; 961.1Sjmcneill 971.1Sjmcneill return eaa->eaa_id == WII_RTCSRAM_ID; 981.1Sjmcneill} 991.1Sjmcneill 1001.1Sjmcneillstatic void 1011.1Sjmcneillrtcsram_attach(device_t parent, device_t self, void *aux) 1021.1Sjmcneill{ 1031.1Sjmcneill struct rtcsram_softc * const sc = device_private(self); 1041.1Sjmcneill struct exi_attach_args * const eaa = aux; 1051.1Sjmcneill 1061.1Sjmcneill aprint_naive("\n"); 1071.1Sjmcneill aprint_normal(": RTC/SRAM\n"); 1081.1Sjmcneill 1091.1Sjmcneill sc->sc_dev = self; 1101.1Sjmcneill sc->sc_chan = eaa->eaa_chan; 1111.1Sjmcneill sc->sc_device = eaa->eaa_device; 1121.1Sjmcneill 1131.1Sjmcneill rtcsram_read_buf(sc, SRAM_BASE, &sc->sc_sram, sizeof(sc->sc_sram)); 1141.1Sjmcneill hexdump(aprint_debug, device_xname(self), &sc->sc_sram, 1151.1Sjmcneill sizeof(sc->sc_sram)); 1161.1Sjmcneill 1171.1Sjmcneill sc->sc_todr.todr_dev = self; 1181.1Sjmcneill sc->sc_todr.todr_gettime = rtcsram_gettime; 1191.1Sjmcneill sc->sc_todr.todr_settime = rtcsram_settime; 1201.1Sjmcneill todr_attach(&sc->sc_todr); 1211.1Sjmcneill} 1221.1Sjmcneill 1231.1Sjmcneillstatic uint32_t 1241.1Sjmcneillrtcsram_read_4(struct rtcsram_softc *sc, uint32_t offset) 1251.1Sjmcneill{ 1261.1Sjmcneill uint32_t val; 1271.1Sjmcneill 1281.1Sjmcneill exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 1291.1Sjmcneill exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 1301.1Sjmcneill exi_recv_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val)); 1311.1Sjmcneill exi_unselect(sc->sc_chan); 1321.1Sjmcneill 1331.1Sjmcneill return val; 1341.1Sjmcneill} 1351.1Sjmcneill 1361.1Sjmcneillstatic void 1371.1Sjmcneillrtcsram_write_4(struct rtcsram_softc *sc, uint32_t offset, uint32_t val) 1381.1Sjmcneill{ 1391.1Sjmcneill offset |= WRITE_OFFSET; 1401.1Sjmcneill 1411.1Sjmcneill exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 1421.1Sjmcneill exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 1431.1Sjmcneill exi_send_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val)); 1441.1Sjmcneill exi_unselect(sc->sc_chan); 1451.1Sjmcneill} 1461.1Sjmcneill 1471.1Sjmcneillstatic void 1481.1Sjmcneillrtcsram_read_buf(struct rtcsram_softc *sc, uint32_t offset, void *data, 1491.1Sjmcneill size_t datalen) 1501.1Sjmcneill{ 1511.1Sjmcneill exi_select(sc->sc_chan, sc->sc_device, WII_RTCSRAM_FREQ); 1521.1Sjmcneill exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset)); 1531.1Sjmcneill exi_recv_dma(sc->sc_chan, sc->sc_device, data, datalen); 1541.1Sjmcneill exi_unselect(sc->sc_chan); 1551.1Sjmcneill} 1561.1Sjmcneill 1571.1Sjmcneillstatic int 1581.1Sjmcneillrtcsram_gettime(todr_chip_handle_t ch, struct timeval *tv) 1591.1Sjmcneill{ 1601.1Sjmcneill struct rtcsram_softc * const sc = device_private(ch->todr_dev); 1611.1Sjmcneill uint32_t val; 1621.1Sjmcneill 1631.1Sjmcneill val = rtcsram_read_4(sc, RTC_BASE); 1641.1Sjmcneill tv->tv_sec = (uint64_t)val; 1651.1Sjmcneill tv->tv_usec = 0; 1661.1Sjmcneill 1671.1Sjmcneill return 0; 1681.1Sjmcneill} 1691.1Sjmcneill 1701.1Sjmcneillstatic int 1711.1Sjmcneillrtcsram_settime(todr_chip_handle_t ch, struct timeval *tv) 1721.1Sjmcneill{ 1731.1Sjmcneill struct rtcsram_softc * const sc = device_private(ch->todr_dev); 1741.1Sjmcneill 1751.1Sjmcneill rtcsram_write_4(sc, RTC_BASE, tv->tv_sec); 1761.1Sjmcneill 1771.1Sjmcneill return 0; 1781.1Sjmcneill} 179