xref: /netbsd-src/sys/arch/sparc/dev/rtc.c (revision 1dc652ef5a0bffbd0917f95e0797bad8c6fc8efd)
1 /*	$NetBSD: rtc.c,v 1.21 2023/12/20 05:33:18 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 2001 Valeriy E. Ushakov
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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * `rtc' is a DS1287A (== MC146818A) time-of-day clock at EBus.
32  * In Krups it's not used to store idprom so this driver doesn't
33  * support it.  Don't know about other ms-IIep systems.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.21 2023/12/20 05:33:18 thorpej Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/systm.h>
43 #ifdef GPROF
44 #include <sys/gmon.h>
45 #endif
46 
47 #include <sys/bus.h>
48 #include <machine/autoconf.h>
49 
50 #include <dev/clock_subr.h>
51 #include <dev/ic/mc146818reg.h>
52 
53 #include <dev/ebus/ebusreg.h>
54 #include <dev/ebus/ebusvar.h>
55 
56 struct rtc_ebus_softc {
57 	bus_space_tag_t		sc_bt;	/* parent bus tag */
58 	bus_space_handle_t	sc_bh;	/* handle for registers */
59 	struct todr_chip_handle	sc_todr;/* TODR handle */
60 };
61 
62 static int	rtcmatch_ebus(device_t, cfdata_t, void *);
63 static void	rtcattach_ebus(device_t, device_t, void *);
64 
65 CFATTACH_DECL_NEW(rtc_ebus, sizeof(struct rtc_ebus_softc),
66     rtcmatch_ebus, rtcattach_ebus, NULL, NULL);
67 
68 /* todr(9) methods */
69 static int rtc_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
70 static int rtc_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
71 
72 int rtc_auto_century_adjust = 1; /* XXX: do we ever want not to? */
73 
74 /*
75  * MD read/write functions declared in mc146818reg.h
76  */
77 #define	RTC_ADDR	0
78 #define	RTC_DATA	1
79 
80 u_int
mc146818_read(void * cookie,u_int reg)81 mc146818_read(void *cookie, u_int reg)
82 {
83 	struct rtc_ebus_softc *sc = cookie;
84 
85 	bus_space_write_1(sc->sc_bt, sc->sc_bh, RTC_ADDR, reg);
86 	return (bus_space_read_1(sc->sc_bt, sc->sc_bh, RTC_DATA));
87 }
88 
89 void
mc146818_write(void * cookie,u_int reg,u_int datum)90 mc146818_write(void *cookie, u_int reg, u_int datum)
91 {
92 	struct rtc_ebus_softc *sc = cookie;
93 
94 	bus_space_write_1(sc->sc_bt, sc->sc_bh, RTC_ADDR, reg);
95 	bus_space_write_1(sc->sc_bt, sc->sc_bh, RTC_DATA, datum);
96 }
97 
98 
99 static int
rtcmatch_ebus(device_t parent,cfdata_t cf,void * aux)100 rtcmatch_ebus(device_t parent, cfdata_t cf, void *aux)
101 {
102 	struct ebus_attach_args *ea = aux;
103 
104 	return (strcmp(cf->cf_name, ea->ea_name) == 0);
105 }
106 
107 static void
rtcattach_ebus(device_t parent,device_t self,void * aux)108 rtcattach_ebus(device_t parent, device_t self, void *aux)
109 {
110 	struct rtc_ebus_softc *sc = device_private(self);
111 	struct ebus_attach_args *ea = aux;
112 	todr_chip_handle_t handle;
113 
114 	sc->sc_bt = ea->ea_bustag;
115 	if (bus_space_map(sc->sc_bt, EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
116 			  ea->ea_reg[0].size, 0, &sc->sc_bh) != 0)
117 	{
118 		printf(": unable to map registers\n");
119 		return;
120 	}
121 
122 	/* XXX: no "model" property in Krups */
123 	printf(": time-of-day clock\n");
124 
125 	/*
126 	 * Turn interrupts off (clear MC_REGB_?IE bits), just in case
127 	 * (although they shouldn't be wired to an interrupt
128 	 * controller on sparcs).
129 	 */
130 	mc146818_write(sc, MC_REGB, MC_REGB_BINARY | MC_REGB_24HR);
131 
132 	/* setup our todr_handle */
133 	handle = &sc->sc_todr;
134 	handle->cookie = sc;
135 	handle->bus_cookie = NULL; /* unused */
136 	handle->todr_gettime = NULL;
137 	handle->todr_settime = NULL;
138 	handle->todr_gettime_ymdhms = rtc_gettime_ymdhms;
139 	handle->todr_settime_ymdhms = rtc_settime_ymdhms;
140 	handle->todr_setwen = NULL; /* not necessary, no idprom to protect */
141 
142 	todr_attach(handle);
143 }
144 
145 
146 static int
rtc_gettime_ymdhms(todr_chip_handle_t handle,struct clock_ymdhms * dt)147 rtc_gettime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
148 {
149 	struct rtc_ebus_softc *sc = handle->cookie;
150 	u_int year;
151 
152 	/* update in progress; spin loop */
153 	while (mc146818_read(sc, MC_REGA) & MC_REGA_UIP)
154 		continue;
155 
156 	/* stop updates (XXX: do we need that???) */
157 	mc146818_write(sc, MC_REGB,
158 		       (mc146818_read(sc, MC_REGB) | MC_REGB_SET));
159 
160 	/* read time */
161 	dt->dt_sec  = mc146818_read(sc, MC_SEC);
162 	dt->dt_min  = mc146818_read(sc, MC_MIN);
163 	dt->dt_hour = mc146818_read(sc, MC_HOUR);
164 	dt->dt_day  = mc146818_read(sc, MC_DOM);
165 	dt->dt_mon  = mc146818_read(sc, MC_MONTH);
166 	year        = mc146818_read(sc, MC_YEAR);
167 
168 	/* reenable updates */
169 	mc146818_write(sc, MC_REGB,
170 		       (mc146818_read(sc, MC_REGB) & ~MC_REGB_SET));
171 
172 	/* year in the century 0..99: adjust to AD */
173 	year += 1900;
174 	if (year < POSIX_BASE_YEAR && rtc_auto_century_adjust != 0)
175 		year += 100;
176 	dt->dt_year = year;
177 
178 	return (0);
179 }
180 
181 static int
rtc_settime_ymdhms(todr_chip_handle_t handle,struct clock_ymdhms * dt)182 rtc_settime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
183 {
184 	struct rtc_ebus_softc *sc = handle->cookie;
185 	u_int year;
186 
187 	year = dt->dt_year - 1900;
188 	if (year >= 100 && rtc_auto_century_adjust != 0)
189 		year -= 100;
190 
191 	/* stop updates */
192 	mc146818_write(sc, MC_REGB,
193 		       (mc146818_read(sc, MC_REGB) | MC_REGB_SET));
194 
195 	mc146818_write(sc, MC_SEC,   dt->dt_sec);
196 	mc146818_write(sc, MC_MIN,   dt->dt_min);
197 	mc146818_write(sc, MC_HOUR,  dt->dt_hour);
198 	mc146818_write(sc, MC_DOW,   dt->dt_wday + 1);
199 	mc146818_write(sc, MC_DOM,   dt->dt_day);
200 	mc146818_write(sc, MC_MONTH, dt->dt_mon);
201 	mc146818_write(sc, MC_YEAR,  year);
202 
203 	/* reenable updates */
204 	mc146818_write(sc, MC_REGB,
205 		       (mc146818_read(sc, MC_REGB) & ~MC_REGB_SET));
206 	return (0);
207 }
208