mkclock.c revision 1.2
11.2Stsutsui/*	$NetBSD: mkclock.c,v 1.2 2008/01/10 15:31:27 tsutsui 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.2Stsutsui__KERNEL_RCSID(0, "$NetBSD: mkclock.c,v 1.2 2008/01/10 15:31:27 tsutsui 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.1Stsutsui#include <machine/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 <sparc64/dev/iommureg.h>
841.1Stsutsui#include <sparc64/dev/sbusreg.h>
851.1Stsutsui#include <dev/sbus/sbusvar.h>
861.1Stsutsui#include <dev/ebus/ebusreg.h>
871.1Stsutsui#include <dev/ebus/ebusvar.h>
881.1Stsutsui
891.1Stsutsui/*
901.1Stsutsui * clock (eeprom) attaches at the sbus or the ebus (PCI)
911.1Stsutsui */
921.1Stsutsuistatic int	mkclock_sbus_match(struct device *, struct cfdata *, void *);
931.1Stsutsuistatic void	mkclock_sbus_attach(struct device *, struct device *, void *);
941.1Stsutsui
951.1Stsutsuistatic int	mkclock_ebus_match(struct device *, struct cfdata *, void *);
961.1Stsutsuistatic void	mkclock_ebus_attach(struct device *, struct device *, void *);
971.1Stsutsui
981.1Stsutsuistatic void	mkclock_attach(struct mk48txx_softc *, int);
991.1Stsutsui
1001.1Stsutsuistatic int	mkclock_wenable(struct todr_chip_handle *, int);
1011.1Stsutsui
1021.1Stsutsui
1031.1StsutsuiCFATTACH_DECL(mkclock_sbus, sizeof(struct mk48txx_softc),
1041.1Stsutsui    mkclock_sbus_match, mkclock_sbus_attach, NULL, NULL);
1051.1Stsutsui
1061.1StsutsuiCFATTACH_DECL(mkclock_ebus, sizeof(struct mk48txx_softc),
1071.1Stsutsui    mkclock_ebus_match, mkclock_ebus_attach, NULL, NULL);
1081.1Stsutsui
1091.1Stsutsui/*
1101.1Stsutsui * The OPENPROM calls the clock the "eeprom", so we have to have our
1111.1Stsutsui * own special match function to call it the "clock".
1121.1Stsutsui */
1131.1Stsutsuistatic int
1141.1Stsutsuimkclock_sbus_match(struct device *parent, struct cfdata *cf, void *aux)
1151.1Stsutsui{
1161.1Stsutsui	struct sbus_attach_args *sa = aux;
1171.1Stsutsui
1181.1Stsutsui	return (strcmp("eeprom", sa->sa_name) == 0);
1191.1Stsutsui}
1201.1Stsutsui
1211.1Stsutsuistatic int
1221.1Stsutsuimkclock_ebus_match(struct device *parent, struct cfdata *cf, void *aux)
1231.1Stsutsui{
1241.1Stsutsui	struct ebus_attach_args *ea = aux;
1251.1Stsutsui
1261.1Stsutsui	return (strcmp("eeprom", ea->ea_name) == 0);
1271.1Stsutsui}
1281.1Stsutsui
1291.1Stsutsui/*
1301.1Stsutsui * Attach a clock (really `eeprom') to the sbus or ebus.
1311.1Stsutsui *
1321.1Stsutsui * We ignore any existing virtual address as we need to map
1331.1Stsutsui * this read-only and make it read-write only temporarily,
1341.1Stsutsui * whenever we read or write the clock chip.  The clock also
1351.1Stsutsui * contains the ID ``PROM'', and I have already had the pleasure
1361.1Stsutsui * of reloading the CPU type, Ethernet address, etc, by hand from
1371.1Stsutsui * the console FORTH interpreter.  I intend not to enjoy it again.
1381.1Stsutsui *
1391.1Stsutsui * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
1401.1Stsutsui * supposed to be identical to it.
1411.1Stsutsui *
1421.1Stsutsui * This is *UGLY*!  We probably have multiple mappings.  But I do
1431.1Stsutsui * know that this all fits inside an 8K page, so I'll just map in
1441.1Stsutsui * once.
1451.1Stsutsui *
1461.1Stsutsui * What we really need is some way to record the bus attach args
1471.1Stsutsui * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
1481.1Stsutsui * or not to write enable/disable the device registers.  This is
1491.1Stsutsui * a non-trivial operation.
1501.1Stsutsui */
1511.1Stsutsui
1521.1Stsutsui/* ARGSUSED */
1531.1Stsutsuistatic void
1541.1Stsutsuimkclock_sbus_attach(struct device *parent, struct device *self, void *aux)
1551.1Stsutsui{
1561.1Stsutsui	struct mk48txx_softc *sc = (void *)self;
1571.1Stsutsui	struct sbus_attach_args *sa = aux;
1581.1Stsutsui	int sz;
1591.1Stsutsui
1601.1Stsutsui	sc->sc_bst = sa->sa_bustag;
1611.1Stsutsui
1621.1Stsutsui	/* use sa->sa_regs[0].size? */
1631.1Stsutsui	sz = 8192;
1641.1Stsutsui
1651.1Stsutsui	if (sbus_bus_map(sc->sc_bst,
1661.1Stsutsui			 sa->sa_slot,
1671.1Stsutsui			 (sa->sa_offset & ~(PAGE_SIZE - 1)),
1681.1Stsutsui			 sz,
1691.1Stsutsui			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
1701.1Stsutsui			 &sc->sc_bsh) != 0) {
1711.1Stsutsui		printf("%s: can't map register\n", self->dv_xname);
1721.1Stsutsui		return;
1731.1Stsutsui	}
1741.1Stsutsui	mkclock_attach(sc, sa->sa_node);
1751.1Stsutsui}
1761.1Stsutsui
1771.1Stsutsui
1781.1Stsutsui/* ARGSUSED */
1791.1Stsutsuistatic void
1801.1Stsutsuimkclock_ebus_attach(struct device *parent, struct device *self, void *aux)
1811.1Stsutsui{
1821.1Stsutsui	struct mk48txx_softc *sc = (void *)self;
1831.1Stsutsui	struct ebus_attach_args *ea = aux;
1841.1Stsutsui	int sz;
1851.1Stsutsui
1861.1Stsutsui	sc->sc_bst = ea->ea_bustag;
1871.1Stsutsui
1881.1Stsutsui	/* hard code to 8K? */
1891.1Stsutsui	sz = ea->ea_reg[0].size;
1901.1Stsutsui
1911.1Stsutsui	if (bus_space_map(sc->sc_bst,
1921.1Stsutsui			 EBUS_ADDR_FROM_REG(&ea->ea_reg[0]),
1931.1Stsutsui			 sz,
1941.1Stsutsui			 BUS_SPACE_MAP_LINEAR,
1951.1Stsutsui			 &sc->sc_bsh) != 0) {
1961.1Stsutsui		printf("%s: can't map register\n", self->dv_xname);
1971.1Stsutsui		return;
1981.1Stsutsui	}
1991.1Stsutsui	mkclock_attach(sc, ea->ea_node);
2001.1Stsutsui}
2011.1Stsutsui
2021.1Stsutsui
2031.1Stsutsuistatic void
2041.1Stsutsuimkclock_attach(struct mk48txx_softc *sc, int node)
2051.1Stsutsui{
2061.1Stsutsui
2071.1Stsutsui	sc->sc_model = prom_getpropstring(node, "model");
2081.1Stsutsui
2091.1Stsutsui#ifdef DIAGNOSTIC
2101.1Stsutsui	if (sc->sc_model == NULL)
2111.1Stsutsui		panic("clockattach: no model property");
2121.1Stsutsui#endif
2131.1Stsutsui
2141.1Stsutsui	/* Our TOD clock year 0 is 1968 */
2151.1Stsutsui	sc->sc_year0 = 1968;
2161.1Stsutsui
2171.1Stsutsui	/* Save info for the clock wenable call. */
2181.1Stsutsui	sc->sc_handle.todr_setwen = mkclock_wenable;
2191.1Stsutsui
2201.2Stsutsui	mk48txx_attach(sc);
2211.2Stsutsui
2221.2Stsutsui	printf("\n");
2231.1Stsutsui}
2241.1Stsutsui
2251.1Stsutsui/*
2261.1Stsutsui * Write en/dis-able clock registers.  We coordinate so that several
2271.1Stsutsui * writers can run simultaneously.
2281.1Stsutsui */
2291.1Stsutsuistatic int
2301.1Stsutsuimkclock_wenable(struct todr_chip_handle *handle, int onoff)
2311.1Stsutsui{
2321.1Stsutsui	struct mk48txx_softc *sc;
2331.1Stsutsui	vm_prot_t prot;
2341.1Stsutsui	vaddr_t va;
2351.1Stsutsui	int s, err = 0;
2361.1Stsutsui	static int writers;
2371.1Stsutsui
2381.1Stsutsui	s = splhigh();
2391.1Stsutsui	if (onoff)
2401.1Stsutsui		prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
2411.1Stsutsui	else
2421.1Stsutsui		prot = --writers == 0 ? VM_PROT_READ : 0;
2431.1Stsutsui	splx(s);
2441.1Stsutsui	if (prot == VM_PROT_NONE) {
2451.1Stsutsui		return 0;
2461.1Stsutsui	}
2471.1Stsutsui	sc = handle->cookie;
2481.1Stsutsui	va = (vaddr_t)bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
2491.1Stsutsui	if (va == 0UL) {
2501.1Stsutsui		printf("clock_wenable: WARNING -- cannot get va\n");
2511.1Stsutsui		return EIO;
2521.1Stsutsui	}
2531.1Stsutsui	pmap_kprotect(va, prot);
2541.1Stsutsui	return (err);
2551.1Stsutsui}
256