xref: /netbsd-src/sys/arch/evbppc/wii/dev/rtcsram.c (revision abdf7c82e8c2eeab4f0a4eb8f84e66cb92c19a4e)
1 /* $NetBSD: rtcsram.c,v 1.2 2024/02/10 11:00:15 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.2 2024/02/10 11:00:15 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 
50 struct rtcsram_sram {
51 	uint16_t	checksum[2];
52 	uint16_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);
66 CTASSERT(sizeof(struct rtcsram_sram) == 64);
67 
68 struct rtcsram_softc {
69 	struct todr_chip_handle	sc_todr;
70 
71 	uint8_t			sc_chan;
72 	uint8_t			sc_device;
73 
74 	struct rtcsram_sram	sc_sram;
75 };
76 
77 static int	rtcsram_match(device_t, cfdata_t, void *);
78 static void	rtcsram_attach(device_t, device_t, void *);
79 
80 static uint32_t	rtcsram_read_4(struct rtcsram_softc *, uint32_t);
81 static void	rtcsram_write_4(struct rtcsram_softc *, uint32_t, uint32_t);
82 static void	rtcsram_read_buf(struct rtcsram_softc *, uint32_t, void *,
83 				 size_t);
84 
85 static int	rtcsram_gettime(todr_chip_handle_t, struct timeval *);
86 static int	rtcsram_settime(todr_chip_handle_t, struct timeval *);
87 
88 CFATTACH_DECL_NEW(rtcsram, sizeof(struct rtcsram_softc),
89 	rtcsram_match, rtcsram_attach, NULL, NULL);
90 
91 static int
rtcsram_match(device_t parent,cfdata_t cf,void * aux)92 rtcsram_match(device_t parent, cfdata_t cf, void *aux)
93 {
94 	struct exi_attach_args * const eaa = aux;
95 
96 	return eaa->eaa_id == WII_RTCSRAM_ID;
97 }
98 
99 static void
rtcsram_attach(device_t parent,device_t self,void * aux)100 rtcsram_attach(device_t parent, device_t self, void *aux)
101 {
102 	struct rtcsram_softc * const sc = device_private(self);
103 	struct exi_attach_args * const eaa = aux;
104 
105 	aprint_naive("\n");
106 	aprint_normal(": RTC/SRAM\n");
107 
108 	sc->sc_chan = eaa->eaa_chan;
109 	sc->sc_device = eaa->eaa_device;
110 
111 	/* Read RTC counter bias from SRAM. */
112 	rtcsram_read_buf(sc, SRAM_BASE, &sc->sc_sram, sizeof(sc->sc_sram));
113 	aprint_debug_dev(self, "counter bias %d\n", sc->sc_sram.counter_bias);
114 	hexdump(aprint_debug, device_xname(self), &sc->sc_sram,
115 	    sizeof(sc->sc_sram));
116 
117 	sc->sc_todr.cookie = sc;
118 	sc->sc_todr.todr_gettime = rtcsram_gettime;
119 	sc->sc_todr.todr_settime = rtcsram_settime;
120 	todr_attach(&sc->sc_todr);
121 }
122 
123 static uint32_t
rtcsram_read_4(struct rtcsram_softc * sc,uint32_t offset)124 rtcsram_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 
136 static void
rtcsram_write_4(struct rtcsram_softc * sc,uint32_t offset,uint32_t val)137 rtcsram_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 
147 static void
rtcsram_read_buf(struct rtcsram_softc * sc,uint32_t offset,void * data,size_t datalen)148 rtcsram_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 
157 static int
rtcsram_gettime(todr_chip_handle_t ch,struct timeval * tv)158 rtcsram_gettime(todr_chip_handle_t ch, struct timeval *tv)
159 {
160 	struct rtcsram_softc * const sc = ch->cookie;
161 	uint32_t val;
162 
163 	val = rtcsram_read_4(sc, RTC_BASE);
164 	tv->tv_sec = (uint64_t)val + sc->sc_sram.counter_bias;
165 	tv->tv_usec = 0;
166 
167 	return 0;
168 }
169 
170 static int
rtcsram_settime(todr_chip_handle_t ch,struct timeval * tv)171 rtcsram_settime(todr_chip_handle_t ch, struct timeval *tv)
172 {
173 	struct rtcsram_softc * const sc = ch->cookie;
174 
175 	rtcsram_write_4(sc, RTC_BASE, tv->tv_sec - sc->sc_sram.counter_bias);
176 
177 	return 0;
178 }
179