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