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