1/* $NetBSD: mkclock.c,v 1.13 2023/12/20 05:33:58 thorpej Exp $ */ 2 3/* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1994 Gordon W. Ross 7 * Copyright (c) 1993 Adam Glass 8 * Copyright (c) 1996 Paul Kranenburg 9 * Copyright (c) 1996 10 * The President and Fellows of Harvard College. All rights reserved. 11 * 12 * This software was developed by the Computer Systems Engineering group 13 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 * contributed to Berkeley. 15 * 16 * All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Harvard University. 19 * This product includes software developed by the University of 20 * California, Lawrence Berkeley Laboratory. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 26 * 1. Redistributions of source code must retain the above copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * This product includes software developed by the University of 34 * California, Berkeley and its contributors. 35 * This product includes software developed by Paul Kranenburg. 36 * This product includes software developed by Harvard University. 37 * 4. Neither the name of the University nor the names of its contributors 38 * may be used to endorse or promote products derived from this software 39 * without specific prior written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * @(#)clock.c 8.1 (Berkeley) 6/11/93 54 * 55 */ 56 57#include <sys/cdefs.h> 58__KERNEL_RCSID(0, "$NetBSD: mkclock.c,v 1.13 2023/12/20 05:33:58 thorpej Exp $"); 59 60/* 61 * Clock driver for 'mkclock' - Mostek MK48Txx TOD clock. 62 */ 63 64#include <sys/param.h> 65#include <sys/kernel.h> 66#include <sys/device.h> 67#include <sys/proc.h> 68#include <sys/resourcevar.h> 69#include <sys/systm.h> 70 71#include <uvm/uvm_extern.h> 72 73#include <sys/bus.h> 74#include <machine/autoconf.h> 75#include <machine/eeprom.h> 76#include <machine/cpu.h> 77 78#include <dev/clock_subr.h> 79#include <dev/ic/mk48txxreg.h> 80#include <dev/ic/mk48txxvar.h> 81 82#include <dev/sbus/sbusvar.h> 83#include <dev/ebus/ebusreg.h> 84#include <dev/ebus/ebusvar.h> 85 86#include <sparc64/dev/fhcvar.h> 87 88/* 89 * clock (eeprom) attaches at the sbus or the ebus (PCI) 90 */ 91static int mkclock_sbus_match(device_t, cfdata_t, void *); 92static void mkclock_sbus_attach(device_t, device_t, void *); 93 94static int mkclock_ebus_match(device_t, cfdata_t, void *); 95static void mkclock_ebus_attach(device_t, device_t, void *); 96 97static int mkclock_fhc_match(device_t, cfdata_t, void *); 98static void mkclock_fhc_attach(device_t, device_t, void *); 99 100static void mkclock_attach(struct mk48txx_softc *, int); 101 102static int mkclock_wenable(struct todr_chip_handle *, int); 103 104 105CFATTACH_DECL_NEW(mkclock_sbus, sizeof(struct mk48txx_softc), 106 mkclock_sbus_match, mkclock_sbus_attach, NULL, NULL); 107 108CFATTACH_DECL_NEW(mkclock_ebus, sizeof(struct mk48txx_softc), 109 mkclock_ebus_match, mkclock_ebus_attach, NULL, NULL); 110 111CFATTACH_DECL_NEW(mkclock_fhc, sizeof(struct mk48txx_softc), 112 mkclock_fhc_match, mkclock_fhc_attach, NULL, NULL); 113 114/* 115 * The OPENPROM calls the clock the "eeprom", so we have to have our 116 * own special match function to call it the "clock". 117 */ 118static int 119mkclock_sbus_match(device_t parent, cfdata_t cf, void *aux) 120{ 121 struct sbus_attach_args *sa = aux; 122 123 return (strcmp("eeprom", sa->sa_name) == 0); 124} 125 126static int 127mkclock_ebus_match(device_t parent, cfdata_t cf, void *aux) 128{ 129 struct ebus_attach_args *ea = aux; 130 131 return (strcmp("eeprom", ea->ea_name) == 0); 132} 133 134static int 135mkclock_fhc_match(device_t parent, cfdata_t cf, void *aux) 136{ 137 struct fhc_attach_args *fa = aux; 138 139 return (strcmp("eeprom", fa->fa_name) == 0); 140} 141 142/* 143 * Attach a clock (really `eeprom') to the sbus or ebus. 144 * 145 * We ignore any existing virtual address as we need to map 146 * this read-only and make it read-write only temporarily, 147 * whenever we read or write the clock chip. The clock also 148 * contains the ID ``PROM'', and I have already had the pleasure 149 * of reloading the CPU type, Ethernet address, etc, by hand from 150 * the console FORTH interpreter. I intend not to enjoy it again. 151 * 152 * the MK48T02 is 2K. the MK48T08 is 8K, and the MK48T59 is 153 * supposed to be identical to it. 154 * 155 * This is *UGLY*! We probably have multiple mappings. But I do 156 * know that this all fits inside an 8K page, so I'll just map in 157 * once. 158 * 159 * What we really need is some way to record the bus attach args 160 * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY 161 * or not to write enable/disable the device registers. This is 162 * a non-trivial operation. 163 */ 164 165/* ARGSUSED */ 166static void 167mkclock_sbus_attach(device_t parent, device_t self, void *aux) 168{ 169 struct mk48txx_softc *sc = device_private(self); 170 struct sbus_attach_args *sa = aux; 171 int sz; 172 173 sc->sc_dev = self; 174 sc->sc_bst = sa->sa_bustag; 175 176 /* use sa->sa_regs[0].size? */ 177 sz = 8192; 178 179 if (sbus_bus_map(sc->sc_bst, 180 sa->sa_slot, 181 trunc_page(sa->sa_offset), 182 sz, 183 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, 184 &sc->sc_bsh) != 0) { 185 aprint_error(": can't map register\n"); 186 return; 187 } 188 mkclock_attach(sc, sa->sa_node); 189} 190 191 192/* ARGSUSED */ 193static void 194mkclock_ebus_attach(device_t parent, device_t self, void *aux) 195{ 196 struct mk48txx_softc *sc = device_private(self); 197 struct ebus_attach_args *ea = aux; 198 int sz; 199 200 sc->sc_dev = self; 201 sc->sc_bst = ea->ea_bustag; 202 203 /* hard code to 8K? */ 204 sz = ea->ea_reg[0].size; 205 206 /* Use the PROM address if there. */ 207 if (ea->ea_nvaddr) 208 sparc_promaddr_to_handle(sc->sc_bst, ea->ea_vaddr[0], 209 &sc->sc_bsh); 210 else if (bus_space_map(sc->sc_bst, 211 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]), 212 sz, 213 BUS_SPACE_MAP_LINEAR, 214 &sc->sc_bsh) != 0) { 215 aprint_error(": can't map register\n"); 216 return; 217 } 218 mkclock_attach(sc, ea->ea_node); 219} 220 221/* ARGSUSED */ 222static void 223mkclock_fhc_attach(device_t parent, device_t self, void *aux) 224{ 225 struct mk48txx_softc *sc = device_private(self); 226 struct fhc_attach_args *fa = aux; 227 228 sc->sc_dev = self; 229 sc->sc_bst = fa->fa_bustag; 230 231 if (fhc_bus_map(sc->sc_bst, 232 fa->fa_reg[0].fbr_slot, 233 (fa->fa_reg[0].fbr_offset & ~NBPG), 234 fa->fa_reg[0].fbr_size, 235 BUS_SPACE_MAP_LINEAR, 236 &sc->sc_bsh) != 0) { 237 aprint_error(": can't map register\n"); 238 return; 239 } 240 mkclock_attach(sc, fa->fa_node); 241} 242 243 244static void 245mkclock_attach(struct mk48txx_softc *sc, int node) 246{ 247 248 sc->sc_model = prom_getpropstring(node, "model"); 249 250#ifdef DIAGNOSTIC 251 if (sc->sc_model == NULL) 252 panic("clockattach: no model property"); 253#endif 254 255 /* Our TOD clock year 0 is 1968 */ 256 sc->sc_year0 = 1968; 257 258 /* Save info for the clock wenable call. */ 259 sc->sc_handle.todr_setwen = mkclock_wenable; 260 261 mk48txx_attach(sc); 262 263 aprint_normal("\n"); 264} 265 266/* 267 * Write en/dis-able clock registers. We coordinate so that several 268 * writers can run simultaneously. 269 */ 270static int 271mkclock_wenable(struct todr_chip_handle *handle, int onoff) 272{ 273 struct mk48txx_softc *sc; 274 vm_prot_t prot; 275 vaddr_t va; 276 int s, err = 0; 277 static int writers; 278 279 /* XXXSMP */ 280 s = splhigh(); 281 if (onoff) 282 prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0; 283 else 284 prot = --writers == 0 ? VM_PROT_READ : 0; 285 splx(s); 286 if (prot == VM_PROT_NONE) { 287 return 0; 288 } 289 sc = handle->cookie; 290 va = (vaddr_t)bus_space_vaddr(sc->sc_bst, sc->sc_bsh); 291 if (va == 0UL) { 292 printf("clock_wenable: WARNING -- cannot get va\n"); 293 return EIO; 294 } 295 pmap_kprotect(va, prot); 296 return (err); 297} 298