mkclock.c revision 1.9
11.9Smrg/*	$NetBSD: mkclock.c,v 1.9 2011/07/29 08:37:36 mrg 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.9Smrg__KERNEL_RCSID(0, "$NetBSD: mkclock.c,v 1.9 2011/07/29 08:37:36 mrg 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/malloc.h>
701.1Stsutsui#include <sys/systm.h>
711.1Stsutsui
721.1Stsutsui#include <uvm/uvm_extern.h>
731.1Stsutsui
741.8Sdyoung#include <sys/bus.h>
751.1Stsutsui#include <machine/autoconf.h>
761.1Stsutsui#include <machine/eeprom.h>
771.1Stsutsui#include <machine/cpu.h>
781.1Stsutsui
791.1Stsutsui#include <dev/clock_subr.h>
801.1Stsutsui#include <dev/ic/mk48txxreg.h>
811.1Stsutsui#include <dev/ic/mk48txxvar.h>
821.1Stsutsui
831.1Stsutsui#include <dev/sbus/sbusvar.h>
841.1Stsutsui#include <dev/ebus/ebusreg.h>
851.1Stsutsui#include <dev/ebus/ebusvar.h>
861.1Stsutsui
871.9Smrg#include <sparc64/dev/fhcvar.h>
881.9Smrg
891.1Stsutsui/*
901.1Stsutsui * clock (eeprom) attaches at the sbus or the ebus (PCI)
911.1Stsutsui */
921.3Stsutsuistatic int	mkclock_sbus_match(device_t, cfdata_t, void *);
931.3Stsutsuistatic void	mkclock_sbus_attach(device_t, device_t, void *);
941.1Stsutsui
951.3Stsutsuistatic int	mkclock_ebus_match(device_t, cfdata_t, void *);
961.3Stsutsuistatic void	mkclock_ebus_attach(device_t, device_t, void *);
971.1Stsutsui
981.9Smrgstatic int	mkclock_fhc_match(device_t, cfdata_t, void *);
991.9Smrgstatic void	mkclock_fhc_attach(device_t, device_t, void *);
1001.9Smrg
1011.1Stsutsuistatic void	mkclock_attach(struct mk48txx_softc *, int);
1021.1Stsutsui
1031.1Stsutsuistatic int	mkclock_wenable(struct todr_chip_handle *, int);
1041.1Stsutsui
1051.1Stsutsui
1061.3StsutsuiCFATTACH_DECL_NEW(mkclock_sbus, sizeof(struct mk48txx_softc),
1071.1Stsutsui    mkclock_sbus_match, mkclock_sbus_attach, NULL, NULL);
1081.1Stsutsui
1091.3StsutsuiCFATTACH_DECL_NEW(mkclock_ebus, sizeof(struct mk48txx_softc),
1101.1Stsutsui    mkclock_ebus_match, mkclock_ebus_attach, NULL, NULL);
1111.1Stsutsui
1121.9SmrgCFATTACH_DECL_NEW(mkclock_fhc, sizeof(struct mk48txx_softc),
1131.9Smrg    mkclock_fhc_match, mkclock_fhc_attach, NULL, NULL);
1141.9Smrg
1151.1Stsutsui/*
1161.1Stsutsui * The OPENPROM calls the clock the "eeprom", so we have to have our
1171.1Stsutsui * own special match function to call it the "clock".
1181.1Stsutsui */
1191.1Stsutsuistatic int
1201.3Stsutsuimkclock_sbus_match(device_t parent, cfdata_t cf, void *aux)
1211.1Stsutsui{
1221.1Stsutsui	struct sbus_attach_args *sa = aux;
1231.1Stsutsui
1241.1Stsutsui	return (strcmp("eeprom", sa->sa_name) == 0);
1251.1Stsutsui}
1261.1Stsutsui
1271.1Stsutsuistatic int
1281.3Stsutsuimkclock_ebus_match(device_t parent, cfdata_t cf, void *aux)
1291.1Stsutsui{
1301.1Stsutsui	struct ebus_attach_args *ea = aux;
1311.1Stsutsui
1321.1Stsutsui	return (strcmp("eeprom", ea->ea_name) == 0);
1331.1Stsutsui}
1341.1Stsutsui
1351.9Smrgstatic int
1361.9Smrgmkclock_fhc_match(device_t parent, cfdata_t cf, void *aux)
1371.9Smrg{
1381.9Smrg	struct fhc_attach_args *fa = aux;
1391.9Smrg
1401.9Smrg	return (strcmp("eeprom", fa->fa_name) == 0);
1411.9Smrg}
1421.9Smrg
1431.1Stsutsui/*
1441.1Stsutsui * Attach a clock (really `eeprom') to the sbus or ebus.
1451.1Stsutsui *
1461.1Stsutsui * We ignore any existing virtual address as we need to map
1471.1Stsutsui * this read-only and make it read-write only temporarily,
1481.1Stsutsui * whenever we read or write the clock chip.  The clock also
1491.1Stsutsui * contains the ID ``PROM'', and I have already had the pleasure
1501.1Stsutsui * of reloading the CPU type, Ethernet address, etc, by hand from
1511.1Stsutsui * the console FORTH interpreter.  I intend not to enjoy it again.
1521.1Stsutsui *
1531.1Stsutsui * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
1541.1Stsutsui * supposed to be identical to it.
1551.1Stsutsui *
1561.1Stsutsui * This is *UGLY*!  We probably have multiple mappings.  But I do
1571.1Stsutsui * know that this all fits inside an 8K page, so I'll just map in
1581.1Stsutsui * once.
1591.1Stsutsui *
1601.1Stsutsui * What we really need is some way to record the bus attach args
1611.1Stsutsui * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
1621.1Stsutsui * or not to write enable/disable the device registers.  This is
1631.1Stsutsui * a non-trivial operation.
1641.1Stsutsui */
1651.1Stsutsui
1661.1Stsutsui/* ARGSUSED */
1671.1Stsutsuistatic void
1681.3Stsutsuimkclock_sbus_attach(device_t parent, device_t self, void *aux)
1691.1Stsutsui{
1701.3Stsutsui	struct mk48txx_softc *sc = device_private(self);
1711.1Stsutsui	struct sbus_attach_args *sa = aux;
1721.1Stsutsui	int sz;
1731.1Stsutsui
1741.5Stsutsui	sc->sc_dev = self;
1751.1Stsutsui	sc->sc_bst = sa->sa_bustag;
1761.1Stsutsui
1771.1Stsutsui	/* use sa->sa_regs[0].size? */
1781.1Stsutsui	sz = 8192;
1791.1Stsutsui
1801.1Stsutsui	if (sbus_bus_map(sc->sc_bst,
1811.1Stsutsui			 sa->sa_slot,
1821.6Snakayama			 trunc_page(sa->sa_offset),
1831.1Stsutsui			 sz,
1841.1Stsutsui			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
1851.1Stsutsui			 &sc->sc_bsh) != 0) {
1861.3Stsutsui		aprint_error(": can't map register\n");
1871.1Stsutsui		return;
1881.1Stsutsui	}
1891.1Stsutsui	mkclock_attach(sc, sa->sa_node);
1901.1Stsutsui}
1911.1Stsutsui
1921.1Stsutsui
1931.1Stsutsui/* ARGSUSED */
1941.1Stsutsuistatic void
1951.1Stsutsuimkclock_ebus_attach(struct device *parent, struct device *self, void *aux)
1961.1Stsutsui{
1971.4Stsutsui	struct mk48txx_softc *sc = device_private(self);
1981.1Stsutsui	struct ebus_attach_args *ea = aux;
1991.1Stsutsui	int sz;
2001.1Stsutsui
2011.5Stsutsui	sc->sc_dev = self;
2021.1Stsutsui	sc->sc_bst = ea->ea_bustag;
2031.1Stsutsui
2041.1Stsutsui	/* hard code to 8K? */
2051.1Stsutsui	sz = ea->ea_reg[0].size;
2061.1Stsutsui
2071.1Stsutsui	if (bus_space_map(sc->sc_bst,
2081.1Stsutsui			 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
2091.1Stsutsui			 sz,
2101.1Stsutsui			 BUS_SPACE_MAP_LINEAR,
2111.1Stsutsui			 &sc->sc_bsh) != 0) {
2121.3Stsutsui		aprint_error(": can't map register\n");
2131.1Stsutsui		return;
2141.1Stsutsui	}
2151.1Stsutsui	mkclock_attach(sc, ea->ea_node);
2161.1Stsutsui}
2171.1Stsutsui
2181.9Smrg/* ARGSUSED */
2191.9Smrgstatic void
2201.9Smrgmkclock_fhc_attach(struct device *parent, struct device *self, void *aux)
2211.9Smrg{
2221.9Smrg	struct mk48txx_softc *sc = device_private(self);
2231.9Smrg	struct fhc_attach_args *fa = aux;
2241.9Smrg
2251.9Smrg	sc->sc_dev = self;
2261.9Smrg	sc->sc_bst = fa->fa_bustag;
2271.9Smrg
2281.9Smrg	if (fhc_bus_map(sc->sc_bst,
2291.9Smrg			fa->fa_reg[0].fbr_slot,
2301.9Smrg			(fa->fa_reg[0].fbr_offset & ~NBPG),
2311.9Smrg			fa->fa_reg[0].fbr_size,
2321.9Smrg			BUS_SPACE_MAP_LINEAR,
2331.9Smrg			&sc->sc_bsh) != 0) {
2341.9Smrg		aprint_error(": can't map register\n");
2351.9Smrg		return;
2361.9Smrg	}
2371.9Smrg	mkclock_attach(sc, fa->fa_node);
2381.9Smrg}
2391.9Smrg
2401.1Stsutsui
2411.1Stsutsuistatic void
2421.1Stsutsuimkclock_attach(struct mk48txx_softc *sc, int node)
2431.1Stsutsui{
2441.1Stsutsui
2451.1Stsutsui	sc->sc_model = prom_getpropstring(node, "model");
2461.1Stsutsui
2471.1Stsutsui#ifdef DIAGNOSTIC
2481.1Stsutsui	if (sc->sc_model == NULL)
2491.1Stsutsui		panic("clockattach: no model property");
2501.1Stsutsui#endif
2511.1Stsutsui
2521.1Stsutsui	/* Our TOD clock year 0 is 1968 */
2531.1Stsutsui	sc->sc_year0 = 1968;
2541.1Stsutsui
2551.1Stsutsui	/* Save info for the clock wenable call. */
2561.1Stsutsui	sc->sc_handle.todr_setwen = mkclock_wenable;
2571.1Stsutsui
2581.2Stsutsui	mk48txx_attach(sc);
2591.2Stsutsui
2601.3Stsutsui	aprint_normal("\n");
2611.1Stsutsui}
2621.1Stsutsui
2631.1Stsutsui/*
2641.1Stsutsui * Write en/dis-able clock registers.  We coordinate so that several
2651.1Stsutsui * writers can run simultaneously.
2661.1Stsutsui */
2671.1Stsutsuistatic int
2681.1Stsutsuimkclock_wenable(struct todr_chip_handle *handle, int onoff)
2691.1Stsutsui{
2701.1Stsutsui	struct mk48txx_softc *sc;
2711.1Stsutsui	vm_prot_t prot;
2721.1Stsutsui	vaddr_t va;
2731.1Stsutsui	int s, err = 0;
2741.1Stsutsui	static int writers;
2751.1Stsutsui
2761.1Stsutsui	s = splhigh();
2771.1Stsutsui	if (onoff)
2781.1Stsutsui		prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
2791.1Stsutsui	else
2801.1Stsutsui		prot = --writers == 0 ? VM_PROT_READ : 0;
2811.1Stsutsui	splx(s);
2821.1Stsutsui	if (prot == VM_PROT_NONE) {
2831.1Stsutsui		return 0;
2841.1Stsutsui	}
2851.1Stsutsui	sc = handle->cookie;
2861.1Stsutsui	va = (vaddr_t)bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
2871.1Stsutsui	if (va == 0UL) {
2881.1Stsutsui		printf("clock_wenable: WARNING -- cannot get va\n");
2891.1Stsutsui		return EIO;
2901.1Stsutsui	}
2911.1Stsutsui	pmap_kprotect(va, prot);
2921.1Stsutsui	return (err);
2931.1Stsutsui}
294