xref: /netbsd-src/sys/arch/mvmeppc/isa/mkclock_isa.c (revision b59f66e17c500a0d8ac8904c4c2fe7f387334983)
1 /*	$NetBSD: mkclock_isa.c,v 1.15 2014/11/20 16:34:25 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Klaus J. Klein.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Mostek MK48T18 time-of-day chip attachment to ISA bus, using two
34  * 8-bit ports for address selection and one 8-bit port for data.
35  */
36 
37 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
38 __KERNEL_RCSID(0, "$NetBSD: mkclock_isa.c,v 1.15 2014/11/20 16:34:25 christos Exp $");
39 
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 
45 #include <sys/bus.h>
46 
47 #include <dev/clock_subr.h>
48 #include <dev/ic/mk48txxreg.h>
49 #include <dev/ic/mk48txxvar.h>
50 
51 #include <dev/isa/isavar.h>
52 
53 
54 /* Offsets of registers into ISA I/O space */
55 #define	MKCLOCK_STB0	0		/* Address low		*/
56 #define	MKCLOCK_STB1	1		/* Address high		*/
57 #define	MKCLOCK_DATA	3		/* Data port		*/
58 
59 #define	MKCLOCK_NPORTS	(MKCLOCK_DATA - MKCLOCK_STB0 + 1)
60 
61 
62 /* Autoconfiguration interface */
63 int	mkclock_isa_match(device_t, cfdata_t, void *);
64 void	mkclock_isa_attach(device_t, device_t, void *);
65 
66 CFATTACH_DECL_NEW(mkclock_isa, sizeof(struct mk48txx_softc),
67     mkclock_isa_match, mkclock_isa_attach, NULL, NULL);
68 
69 
70 /* mk48txx interface */
71 uint8_t	mkclock_isa_nvrd(struct mk48txx_softc *, int);
72 void	mkclock_isa_nvwr(struct mk48txx_softc *, int, uint8_t);
73 
74 
75 int
mkclock_isa_match(device_t parent,cfdata_t cf,void * aux)76 mkclock_isa_match(device_t parent, cfdata_t cf, void *aux)
77 {
78 	struct isa_attach_args *ia = aux;
79 	struct mk48txx_softc mk48txx, *sc;
80 	uint8_t csr, ocsr;
81 	unsigned int t1, t2;
82 	int found;
83 
84 	found = 0;
85 
86 	if (ia->ia_nio < 1 ||
87 	    (ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT &&
88 	     ia->ia_io[0].ir_addr != 0x74))
89 		return (0);
90 
91         if (ia->ia_niomem > 0 &&
92 	    (ia->ia_iomem[0].ir_addr != ISA_UNKNOWN_IOMEM))
93 		return (0);
94 
95 	if (ia->ia_nirq > 0 &&
96 	    (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ))
97 		return (0);
98 
99 	if (ia->ia_ndrq > 0 &&
100 	    (ia->ia_drq[0].ir_drq != ISA_UNKNOWN_DRQ))
101 		return (0);
102 
103 	/*
104 	 * Map I/O space, then try to determine if it's really there.
105 	 */
106 	sc = &mk48txx;
107 	sc->sc_bst = ia->ia_iot;
108 	if (bus_space_map(sc->sc_bst, 0x74, MKCLOCK_NPORTS, 0, &sc->sc_bsh))
109 		return (0);
110 
111 	/* Supposedly no control bits are set after POST; check for this. */
112 	ocsr = mkclock_isa_nvrd(sc, MK48T18_CLKOFF + MK48TXX_ICSR);
113 	if (ocsr != 0)
114 		goto unmap;
115 
116 	/* Set clock data to read mode, prohibiting updates from clock. */
117 	csr = ocsr | MK48TXX_CSR_READ;
118 	mkclock_isa_nvwr(sc, MK48T18_CLKOFF + MK48TXX_ICSR, csr);
119 	/* Compare. */
120 	if (mkclock_isa_nvrd(sc, MK48T18_CLKOFF + MK48TXX_ICSR) != csr)
121 		goto restore;
122 
123 	/* Read from the seconds counter. */
124 	t1 = bcdtobin(mkclock_isa_nvrd(sc, MK48T18_CLKOFF + MK48TXX_ISEC));
125 	if (t1 > 59)
126 		goto restore;
127 
128 	/* Make it tick again, wait, then look again. */
129 	mkclock_isa_nvwr(sc, MK48T18_CLKOFF + MK48TXX_ICSR, ocsr);
130 	DELAY(1100000);
131 	mkclock_isa_nvwr(sc, MK48T18_CLKOFF + MK48TXX_ICSR, csr);
132 	t2 = bcdtobin(mkclock_isa_nvrd(sc, MK48T18_CLKOFF + MK48TXX_ISEC));
133 	if (t2 > 59)
134 		goto restore;
135 
136 	/* If [1,2) seconds have passed since, call it a clock. */
137 	if ((t1 + 1) % 60 == t2 || (t1 + 2) % 60 == t2)
138 		found = 1;
139 
140  restore:
141 	mkclock_isa_nvwr(sc, MK48T18_CLKOFF + MK48TXX_ICSR, ocsr);
142  unmap:
143 	bus_space_unmap(sc->sc_bst, sc->sc_bsh, MKCLOCK_NPORTS);
144 
145 	if (found) {
146 		ia->ia_nio = 1;
147 		ia->ia_io[0].ir_addr = 0x74;
148 		ia->ia_io[0].ir_size = MKCLOCK_NPORTS;
149 
150 		ia->ia_niomem = 0;
151 		ia->ia_nirq = 0;
152 		ia->ia_ndrq = 0;
153 	}
154 
155 	return (found);
156 }
157 
158 void
mkclock_isa_attach(device_t parent,device_t self,void * aux)159 mkclock_isa_attach(device_t parent, device_t self, void *aux)
160 {
161 	struct mk48txx_softc *sc = device_private(self);
162 	struct isa_attach_args *ia = aux;
163 
164 	sc->sc_dev = self;
165 
166 	/* Map I/O space. */
167 	sc->sc_bst = ia->ia_iot;
168 	if (bus_space_map(sc->sc_bst, ia->ia_io[0].ir_addr,
169 	    ia->ia_io[0].ir_size, 0, &sc->sc_bsh))
170 		panic("mkclock_isa_attach: couldn't map clock I/O space");
171 
172 	/* Attach to MI mk48txx driver. */
173 	sc->sc_model = "mk48t18";
174 	sc->sc_year0 = 1968;
175 	sc->sc_nvrd = mkclock_isa_nvrd;
176 	sc->sc_nvwr = mkclock_isa_nvwr;
177 
178 	mk48txx_attach(sc);
179 
180 	aprint_normal(" Timekeeper NVRAM/RTC\n");
181 }
182 
183 /*
184  * Bus access methods for MI mk48txx driver.
185  */
186 uint8_t
mkclock_isa_nvrd(struct mk48txx_softc * sc,int off)187 mkclock_isa_nvrd(struct mk48txx_softc *sc, int off)
188 {
189 	bus_space_tag_t iot;
190 	bus_space_handle_t ioh;
191 	uint8_t datum;
192 	int s;
193 
194 	iot = sc->sc_bst;
195 	ioh = sc->sc_bsh;
196 
197 	s = splclock();
198 	bus_space_write_1(iot, ioh, MKCLOCK_STB0, off & 0xff);
199 	bus_space_write_1(iot, ioh, MKCLOCK_STB1, off >> 8);
200 	datum = bus_space_read_1(iot, ioh, MKCLOCK_DATA);
201 	splx(s);
202 
203 	return (datum);
204 }
205 
206 void
mkclock_isa_nvwr(struct mk48txx_softc * sc,int off,uint8_t datum)207 mkclock_isa_nvwr(struct mk48txx_softc *sc, int off, uint8_t datum)
208 {
209 	bus_space_tag_t iot;
210 	bus_space_handle_t ioh;
211 	int s;
212 
213 	iot = sc->sc_bst;
214 	ioh = sc->sc_bsh;
215 
216 	s = splclock();
217 	bus_space_write_1(iot, ioh, MKCLOCK_STB0, off & 0xff);
218 	bus_space_write_1(iot, ioh, MKCLOCK_STB1, off >> 8);
219 	bus_space_write_1(iot, ioh, MKCLOCK_DATA, datum);
220 	splx(s);
221 }
222