11.14Sthorpej/*	$NetBSD: mkclock.c,v 1.14 2025/09/07 21:45:15 thorpej Exp $ */
21.1Stsutsui
31.1Stsutsui/*
41.1Stsutsui * Copyright (c) 1992, 1993
51.1Stsutsui *	The Regents of the University of California.  All rights reserved.
61.1Stsutsui * Copyright (c) 1994 Gordon W. Ross
71.1Stsutsui * Copyright (c) 1993 Adam Glass
81.1Stsutsui * Copyright (c) 1996 Paul Kranenburg
91.1Stsutsui * Copyright (c) 1996
101.1Stsutsui * 	The President and Fellows of Harvard College. All rights reserved.
111.1Stsutsui *
121.1Stsutsui * This software was developed by the Computer Systems Engineering group
131.1Stsutsui * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
141.1Stsutsui * contributed to Berkeley.
151.1Stsutsui *
161.1Stsutsui * All advertising materials mentioning features or use of this software
171.1Stsutsui * must display the following acknowledgement:
181.1Stsutsui *	This product includes software developed by Harvard University.
191.1Stsutsui *	This product includes software developed by the University of
201.1Stsutsui *	California, Lawrence Berkeley Laboratory.
211.1Stsutsui *
221.1Stsutsui * Redistribution and use in source and binary forms, with or without
231.1Stsutsui * modification, are permitted provided that the following conditions
241.1Stsutsui * are met:
251.1Stsutsui *
261.1Stsutsui * 1. Redistributions of source code must retain the above copyright
271.1Stsutsui *    notice, this list of conditions and the following disclaimer.
281.1Stsutsui * 2. Redistributions in binary form must reproduce the above copyright
291.1Stsutsui *    notice, this list of conditions and the following disclaimer in the
301.1Stsutsui *    documentation and/or other materials provided with the distribution.
311.1Stsutsui * 3. All advertising materials mentioning features or use of this software
321.1Stsutsui *    must display the following acknowledgement:
331.1Stsutsui *	This product includes software developed by the University of
341.1Stsutsui *	California, Berkeley and its contributors.
351.1Stsutsui *	This product includes software developed by Paul Kranenburg.
361.1Stsutsui *	This product includes software developed by Harvard University.
371.1Stsutsui * 4. Neither the name of the University nor the names of its contributors
381.1Stsutsui *    may be used to endorse or promote products derived from this software
391.1Stsutsui *    without specific prior written permission.
401.1Stsutsui *
411.1Stsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
421.1Stsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431.1Stsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
441.1Stsutsui * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
451.1Stsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
461.1Stsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
471.1Stsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
481.1Stsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
491.1Stsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
501.1Stsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
511.1Stsutsui * SUCH DAMAGE.
521.1Stsutsui *
531.1Stsutsui *	@(#)clock.c	8.1 (Berkeley) 6/11/93
541.1Stsutsui *
551.1Stsutsui */
561.1Stsutsui
571.1Stsutsui#include <sys/cdefs.h>
581.14Sthorpej__KERNEL_RCSID(0, "$NetBSD: mkclock.c,v 1.14 2025/09/07 21:45:15 thorpej Exp $");
591.1Stsutsui
601.1Stsutsui/*
611.1Stsutsui * Clock driver for 'mkclock' - Mostek MK48Txx TOD clock.
621.1Stsutsui */
631.1Stsutsui
641.1Stsutsui#include <sys/param.h>
651.1Stsutsui#include <sys/kernel.h>
661.1Stsutsui#include <sys/device.h>
671.1Stsutsui#include <sys/proc.h>
681.1Stsutsui#include <sys/resourcevar.h>
691.1Stsutsui#include <sys/systm.h>
701.1Stsutsui
711.1Stsutsui#include <uvm/uvm_extern.h>
721.1Stsutsui
731.8Sdyoung#include <sys/bus.h>
741.1Stsutsui#include <machine/autoconf.h>
751.1Stsutsui#include <machine/eeprom.h>
761.1Stsutsui#include <machine/cpu.h>
771.1Stsutsui
781.1Stsutsui#include <dev/clock_subr.h>
791.1Stsutsui#include <dev/ic/mk48txxreg.h>
801.1Stsutsui#include <dev/ic/mk48txxvar.h>
811.1Stsutsui
821.1Stsutsui#include <dev/sbus/sbusvar.h>
831.1Stsutsui#include <dev/ebus/ebusreg.h>
841.1Stsutsui#include <dev/ebus/ebusvar.h>
851.1Stsutsui
861.9Smrg#include <sparc64/dev/fhcvar.h>
871.9Smrg
881.1Stsutsui/*
891.1Stsutsui * clock (eeprom) attaches at the sbus or the ebus (PCI)
901.1Stsutsui */
911.3Stsutsuistatic int	mkclock_sbus_match(device_t, cfdata_t, void *);
921.3Stsutsuistatic void	mkclock_sbus_attach(device_t, device_t, void *);
931.1Stsutsui
941.3Stsutsuistatic int	mkclock_ebus_match(device_t, cfdata_t, void *);
951.3Stsutsuistatic void	mkclock_ebus_attach(device_t, device_t, void *);
961.1Stsutsui
971.9Smrgstatic int	mkclock_fhc_match(device_t, cfdata_t, void *);
981.9Smrgstatic void	mkclock_fhc_attach(device_t, device_t, void *);
991.9Smrg
1001.1Stsutsuistatic void	mkclock_attach(struct mk48txx_softc *, int);
1011.1Stsutsui
1021.1Stsutsuistatic int	mkclock_wenable(struct todr_chip_handle *, int);
1031.1Stsutsui
1041.1Stsutsui
1051.3StsutsuiCFATTACH_DECL_NEW(mkclock_sbus, sizeof(struct mk48txx_softc),
1061.1Stsutsui    mkclock_sbus_match, mkclock_sbus_attach, NULL, NULL);
1071.1Stsutsui
1081.3StsutsuiCFATTACH_DECL_NEW(mkclock_ebus, sizeof(struct mk48txx_softc),
1091.1Stsutsui    mkclock_ebus_match, mkclock_ebus_attach, NULL, NULL);
1101.1Stsutsui
1111.9SmrgCFATTACH_DECL_NEW(mkclock_fhc, sizeof(struct mk48txx_softc),
1121.9Smrg    mkclock_fhc_match, mkclock_fhc_attach, NULL, NULL);
1131.9Smrg
1141.1Stsutsui/*
1151.1Stsutsui * The OPENPROM calls the clock the "eeprom", so we have to have our
1161.1Stsutsui * own special match function to call it the "clock".
1171.1Stsutsui */
1181.1Stsutsuistatic int
1191.3Stsutsuimkclock_sbus_match(device_t parent, cfdata_t cf, void *aux)
1201.1Stsutsui{
1211.1Stsutsui	struct sbus_attach_args *sa = aux;
1221.1Stsutsui
1231.1Stsutsui	return (strcmp("eeprom", sa->sa_name) == 0);
1241.1Stsutsui}
1251.1Stsutsui
1261.1Stsutsuistatic int
1271.3Stsutsuimkclock_ebus_match(device_t parent, cfdata_t cf, void *aux)
1281.1Stsutsui{
1291.1Stsutsui	struct ebus_attach_args *ea = aux;
1301.1Stsutsui
1311.1Stsutsui	return (strcmp("eeprom", ea->ea_name) == 0);
1321.1Stsutsui}
1331.1Stsutsui
1341.9Smrgstatic int
1351.9Smrgmkclock_fhc_match(device_t parent, cfdata_t cf, void *aux)
1361.9Smrg{
1371.9Smrg	struct fhc_attach_args *fa = aux;
1381.9Smrg
1391.9Smrg	return (strcmp("eeprom", fa->fa_name) == 0);
1401.9Smrg}
1411.9Smrg
1421.1Stsutsui/*
1431.1Stsutsui * Attach a clock (really `eeprom') to the sbus or ebus.
1441.1Stsutsui *
1451.1Stsutsui * We ignore any existing virtual address as we need to map
1461.1Stsutsui * this read-only and make it read-write only temporarily,
1471.1Stsutsui * whenever we read or write the clock chip.  The clock also
1481.1Stsutsui * contains the ID ``PROM'', and I have already had the pleasure
1491.1Stsutsui * of reloading the CPU type, Ethernet address, etc, by hand from
1501.1Stsutsui * the console FORTH interpreter.  I intend not to enjoy it again.
1511.1Stsutsui *
1521.1Stsutsui * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
1531.1Stsutsui * supposed to be identical to it.
1541.1Stsutsui *
1551.1Stsutsui * This is *UGLY*!  We probably have multiple mappings.  But I do
1561.1Stsutsui * know that this all fits inside an 8K page, so I'll just map in
1571.1Stsutsui * once.
1581.1Stsutsui *
1591.1Stsutsui * What we really need is some way to record the bus attach args
1601.1Stsutsui * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
1611.1Stsutsui * or not to write enable/disable the device registers.  This is
1621.1Stsutsui * a non-trivial operation.
1631.1Stsutsui */
1641.1Stsutsui
1651.1Stsutsui/* ARGSUSED */
1661.1Stsutsuistatic void
1671.3Stsutsuimkclock_sbus_attach(device_t parent, device_t self, void *aux)
1681.1Stsutsui{
1691.3Stsutsui	struct mk48txx_softc *sc = device_private(self);
1701.1Stsutsui	struct sbus_attach_args *sa = aux;
1711.1Stsutsui	int sz;
1721.1Stsutsui
1731.5Stsutsui	sc->sc_dev = self;
1741.1Stsutsui	sc->sc_bst = sa->sa_bustag;
1751.1Stsutsui
1761.1Stsutsui	/* use sa->sa_regs[0].size? */
1771.1Stsutsui	sz = 8192;
1781.1Stsutsui
1791.1Stsutsui	if (sbus_bus_map(sc->sc_bst,
1801.1Stsutsui			 sa->sa_slot,
1811.6Snakayama			 trunc_page(sa->sa_offset),
1821.1Stsutsui			 sz,
1831.1Stsutsui			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
1841.1Stsutsui			 &sc->sc_bsh) != 0) {
1851.3Stsutsui		aprint_error(": can't map register\n");
1861.1Stsutsui		return;
1871.1Stsutsui	}
1881.1Stsutsui	mkclock_attach(sc, sa->sa_node);
1891.1Stsutsui}
1901.1Stsutsui
1911.1Stsutsui
1921.1Stsutsui/* ARGSUSED */
1931.1Stsutsuistatic void
1941.12Schsmkclock_ebus_attach(device_t parent, device_t self, void *aux)
1951.1Stsutsui{
1961.4Stsutsui	struct mk48txx_softc *sc = device_private(self);
1971.1Stsutsui	struct ebus_attach_args *ea = aux;
1981.1Stsutsui	int sz;
1991.1Stsutsui
2001.5Stsutsui	sc->sc_dev = self;
2011.1Stsutsui	sc->sc_bst = ea->ea_bustag;
2021.1Stsutsui
2031.1Stsutsui	/* hard code to 8K? */
2041.1Stsutsui	sz = ea->ea_reg[0].size;
2051.1Stsutsui
2061.11Sjdc	/* Use the PROM address if there. */
2071.11Sjdc	if (ea->ea_nvaddr)
2081.11Sjdc		sparc_promaddr_to_handle(sc->sc_bst, ea->ea_vaddr[0],
2091.11Sjdc			&sc->sc_bsh);
2101.11Sjdc	else if (bus_space_map(sc->sc_bst,
2111.1Stsutsui			 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
2121.1Stsutsui			 sz,
2131.1Stsutsui			 BUS_SPACE_MAP_LINEAR,
2141.1Stsutsui			 &sc->sc_bsh) != 0) {
2151.3Stsutsui		aprint_error(": can't map register\n");
2161.1Stsutsui		return;
2171.1Stsutsui	}
2181.1Stsutsui	mkclock_attach(sc, ea->ea_node);
2191.1Stsutsui}
2201.1Stsutsui
2211.9Smrg/* ARGSUSED */
2221.9Smrgstatic void
2231.12Schsmkclock_fhc_attach(device_t parent, device_t self, void *aux)
2241.9Smrg{
2251.9Smrg	struct mk48txx_softc *sc = device_private(self);
2261.9Smrg	struct fhc_attach_args *fa = aux;
2271.9Smrg
2281.9Smrg	sc->sc_dev = self;
2291.9Smrg	sc->sc_bst = fa->fa_bustag;
2301.9Smrg
2311.9Smrg	if (fhc_bus_map(sc->sc_bst,
2321.9Smrg			fa->fa_reg[0].fbr_slot,
2331.9Smrg			(fa->fa_reg[0].fbr_offset & ~NBPG),
2341.9Smrg			fa->fa_reg[0].fbr_size,
2351.9Smrg			BUS_SPACE_MAP_LINEAR,
2361.9Smrg			&sc->sc_bsh) != 0) {
2371.9Smrg		aprint_error(": can't map register\n");
2381.9Smrg		return;
2391.9Smrg	}
2401.9Smrg	mkclock_attach(sc, fa->fa_node);
2411.9Smrg}
2421.9Smrg
2431.1Stsutsui
2441.1Stsutsuistatic void
2451.1Stsutsuimkclock_attach(struct mk48txx_softc *sc, int node)
2461.1Stsutsui{
2471.1Stsutsui
2481.1Stsutsui	sc->sc_model = prom_getpropstring(node, "model");
2491.1Stsutsui
2501.1Stsutsui#ifdef DIAGNOSTIC
2511.1Stsutsui	if (sc->sc_model == NULL)
2521.1Stsutsui		panic("clockattach: no model property");
2531.1Stsutsui#endif
2541.1Stsutsui
2551.1Stsutsui	/* Our TOD clock year 0 is 1968 */
2561.1Stsutsui	sc->sc_year0 = 1968;
2571.1Stsutsui
2581.1Stsutsui	/* Save info for the clock wenable call. */
2591.1Stsutsui	sc->sc_handle.todr_setwen = mkclock_wenable;
2601.1Stsutsui
2611.2Stsutsui	mk48txx_attach(sc);
2621.2Stsutsui
2631.3Stsutsui	aprint_normal("\n");
2641.1Stsutsui}
2651.1Stsutsui
2661.1Stsutsui/*
2671.1Stsutsui * Write en/dis-able clock registers.  We coordinate so that several
2681.1Stsutsui * writers can run simultaneously.
2691.1Stsutsui */
2701.1Stsutsuistatic int
2711.1Stsutsuimkclock_wenable(struct todr_chip_handle *handle, int onoff)
2721.1Stsutsui{
2731.14Sthorpej	struct mk48txx_softc *sc = device_private(handle->todr_dev);
2741.1Stsutsui	vm_prot_t prot;
2751.1Stsutsui	vaddr_t va;
2761.1Stsutsui	int s, err = 0;
2771.1Stsutsui	static int writers;
2781.1Stsutsui
2791.10Smrg	/* XXXSMP */
2801.1Stsutsui	s = splhigh();
2811.1Stsutsui	if (onoff)
2821.1Stsutsui		prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
2831.1Stsutsui	else
2841.1Stsutsui		prot = --writers == 0 ? VM_PROT_READ : 0;
2851.1Stsutsui	splx(s);
2861.1Stsutsui	if (prot == VM_PROT_NONE) {
2871.1Stsutsui		return 0;
2881.1Stsutsui	}
2891.1Stsutsui	va = (vaddr_t)bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
2901.1Stsutsui	if (va == 0UL) {
2911.1Stsutsui		printf("clock_wenable: WARNING -- cannot get va\n");
2921.1Stsutsui		return EIO;
2931.1Stsutsui	}
2941.1Stsutsui	pmap_kprotect(va, prot);
2951.1Stsutsui	return (err);
2961.1Stsutsui}
297