1 /* $NetBSD: dpclock.c,v 1.1 2009/02/12 06:33:57 rumble Exp $ */
4 * Copyright (c) 2001 Erik Reid
5 * Copyright (c) 2001 Rafal K. Boni
6 * Copyright (c) 2001 Christopher Sekiya
7 * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
10 * Portions of this code are derived from software contributed to The
11 * NetBSD Foundation by Jason R. Thorpe of the Numerical Aerospace
12 * Simulation Facility, NASA Ames Research Center.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. The name of the author may not be used to endorse or promote products
23 * derived from this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
42 #include <machine/bus.h>
43 #include <machine/autoconf.h>
44 #include <machine/sysconf.h>
45 #include <machine/machtype.h>
47 #include <dev/clock_subr.h>
48 #include <sgimips/dev/dp8573areg.h>
50 #include <sgimips/sgimips/clockvar.h>
52 struct dpclock_softc
{
55 struct todr_chip_handle sc_todrch
;
58 bus_space_tag_t sc_rtct
;
59 bus_space_handle_t sc_rtch
;
62 static int dpclock_match(struct device
*, struct cfdata
*, void *);
63 static void dpclock_attach(struct device
*, struct device
*, void *);
64 static int dpclock_gettime(struct todr_chip_handle
*, struct timeval
*);
65 static int dpclock_settime(struct todr_chip_handle
*, struct timeval
*);
67 CFATTACH_DECL(dpclock
, sizeof(struct dpclock_softc
),
68 dpclock_match
, dpclock_attach
, NULL
, NULL
);
71 dpclock_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
73 struct mainbus_attach_args
*ma
= aux
;
76 case MACH_SGI_IP6
| MACH_SGI_IP10
:
77 if (ma
->ma_addr
== 0x1fbc0000)
83 if (ma
->ma_addr
== 0x1fb80e00)
92 dpclock_attach(struct device
*parent
, struct device
*self
, void *aux
)
94 struct dpclock_softc
*sc
= (void *)self
;
95 struct mainbus_attach_args
*ma
= aux
;
101 * All machines have one byte register per word. IP6/IP10 use
102 * the MSB, others the LSB.
104 if (mach_type
== MACH_SGI_IP12
|| mach_type
== MACH_SGI_IP20
)
105 sc
->sc_rtct
= SGIMIPS_BUS_SPACE_HPC
;
107 sc
->sc_rtct
= SGIMIPS_BUS_SPACE_IP6_DPCLOCK
;
109 if ((err
= bus_space_map(sc
->sc_rtct
, ma
->ma_addr
, 0x1ffff,
110 BUS_SPACE_MAP_LINEAR
, &sc
->sc_rtch
)) != 0) {
111 printf(": unable to map RTC registers, error = %d\n", err
);
115 sc
->sc_todrch
.cookie
= sc
;
116 sc
->sc_todrch
.todr_gettime
= dpclock_gettime
;
117 sc
->sc_todrch
.todr_settime
= dpclock_settime
;
118 sc
->sc_todrch
.todr_setwen
= NULL
;
120 todr_attach(&sc
->sc_todrch
);
124 * Get the time of day, based on the clock's value and/or the base value.
127 dpclock_gettime(struct todr_chip_handle
*todrch
, struct timeval
*tv
)
129 struct dpclock_softc
*sc
= (struct dpclock_softc
*)todrch
->cookie
;
130 struct clock_ymdhms dt
;
136 i
= bus_space_read_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
);
137 j
= i
| DP8573A_TIMESAVE_CTL_EN
;
138 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
, j
);
139 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
, i
);
142 for (i
= 0; i
< 32; i
++)
143 regs
[i
] = bus_space_read_1(sc
->sc_rtct
, sc
->sc_rtch
, i
);
145 dt
.dt_sec
= FROMBCD(regs
[DP8573A_SAVE_SEC
]);
146 dt
.dt_min
= FROMBCD(regs
[DP8573A_SAVE_MIN
]);
148 if (regs
[DP8573A_RT_MODE
] & DP8573A_RT_MODE_1224
) {
149 dt
.dt_hour
= FROMBCD(regs
[DP8573A_SAVE_HOUR
] &
150 DP8573A_HOUR_12HR_MASK
) +
151 ((regs
[DP8573A_SAVE_HOUR
] & DP8573A_RT_MODE_1224
) ? 0 : 12);
154 * In AM/PM mode, hour range is 01-12, so adding in 12 hours
155 * for PM gives us 01-24, whereas we want 00-23, so map hour
159 if (dt
.dt_hour
== 24)
162 dt
.dt_hour
= FROMBCD(regs
[DP8573A_SAVE_HOUR
] &
163 DP8573A_HOUR_24HR_MASK
);
166 dt
.dt_wday
= FROMBCD(regs
[DP8573A_DOW
]); /* Not from time saved */
167 dt
.dt_day
= FROMBCD(regs
[DP8573A_SAVE_DOM
]);
168 dt
.dt_mon
= FROMBCD(regs
[DP8573A_SAVE_MONTH
]);
169 dt
.dt_year
= FROM_IRIX_YEAR(FROMBCD(regs
[DP8573A_YEAR
]));
171 /* simple sanity checks */
172 if (dt
.dt_mon
> 12 || dt
.dt_day
> 31 ||
173 dt
.dt_hour
>= 24 || dt
.dt_min
>= 60 || dt
.dt_sec
>= 60)
176 tv
->tv_sec
= (long)clock_ymdhms_to_secs(&dt
);
177 if (tv
->tv_sec
== -1)
185 * Reset the TODR based on the time value.
188 dpclock_settime(struct todr_chip_handle
*todrch
, struct timeval
*tv
)
190 struct dpclock_softc
*sc
= (struct dpclock_softc
*)todrch
->cookie
;
191 struct clock_ymdhms dt
;
196 clock_secs_to_ymdhms((time_t)(tv
->tv_sec
+ (tv
->tv_usec
> 500000)),&dt
);
199 i
= bus_space_read_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
);
200 j
= i
| DP8573A_TIMESAVE_CTL_EN
;
201 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
, j
);
202 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_TIMESAVE_CTL
, i
);
205 for (i
= 0; i
< 32; i
++)
206 regs
[i
] = bus_space_read_1(sc
->sc_rtct
, sc
->sc_rtch
, i
);
208 regs
[DP8573A_SUBSECOND
] = 0;
209 regs
[DP8573A_SECOND
] = TOBCD(dt
.dt_sec
);
210 regs
[DP8573A_MINUTE
] = TOBCD(dt
.dt_min
);
211 regs
[DP8573A_HOUR
] = TOBCD(dt
.dt_hour
) & DP8573A_HOUR_24HR_MASK
;
212 regs
[DP8573A_DOW
] = TOBCD(dt
.dt_wday
);
213 regs
[DP8573A_DOM
] = TOBCD(dt
.dt_day
);
214 regs
[DP8573A_MONTH
] = TOBCD(dt
.dt_mon
);
215 regs
[DP8573A_YEAR
] = TOBCD(TO_IRIX_YEAR(dt
.dt_year
));
218 i
= bus_space_read_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_RT_MODE
);
219 j
= i
& ~DP8573A_RT_MODE_CLKSS
;
220 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_RT_MODE
, j
);
222 for (i
= 0; i
< 10; i
++)
223 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_COUNTERS
+i
,
224 regs
[DP8573A_COUNTERS
+ i
]);
226 bus_space_write_1(sc
->sc_rtct
, sc
->sc_rtch
, DP8573A_RT_MODE
, i
);