mkclock.c revision 1.8
11.8Sdyoung/*	$NetBSD: mkclock.c,v 1.8 2011/07/01 18:48:36 dyoung 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.8Sdyoung__KERNEL_RCSID(0, "$NetBSD: mkclock.c,v 1.8 2011/07/01 18:48:36 dyoung 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.1Stsutsui/*
881.1Stsutsui * clock (eeprom) attaches at the sbus or the ebus (PCI)
891.1Stsutsui */
901.3Stsutsuistatic int	mkclock_sbus_match(device_t, cfdata_t, void *);
911.3Stsutsuistatic void	mkclock_sbus_attach(device_t, device_t, void *);
921.1Stsutsui
931.3Stsutsuistatic int	mkclock_ebus_match(device_t, cfdata_t, void *);
941.3Stsutsuistatic void	mkclock_ebus_attach(device_t, device_t, void *);
951.1Stsutsui
961.1Stsutsuistatic void	mkclock_attach(struct mk48txx_softc *, int);
971.1Stsutsui
981.1Stsutsuistatic int	mkclock_wenable(struct todr_chip_handle *, int);
991.1Stsutsui
1001.1Stsutsui
1011.3StsutsuiCFATTACH_DECL_NEW(mkclock_sbus, sizeof(struct mk48txx_softc),
1021.1Stsutsui    mkclock_sbus_match, mkclock_sbus_attach, NULL, NULL);
1031.1Stsutsui
1041.3StsutsuiCFATTACH_DECL_NEW(mkclock_ebus, sizeof(struct mk48txx_softc),
1051.1Stsutsui    mkclock_ebus_match, mkclock_ebus_attach, NULL, NULL);
1061.1Stsutsui
1071.1Stsutsui/*
1081.1Stsutsui * The OPENPROM calls the clock the "eeprom", so we have to have our
1091.1Stsutsui * own special match function to call it the "clock".
1101.1Stsutsui */
1111.1Stsutsuistatic int
1121.3Stsutsuimkclock_sbus_match(device_t parent, cfdata_t cf, void *aux)
1131.1Stsutsui{
1141.1Stsutsui	struct sbus_attach_args *sa = aux;
1151.1Stsutsui
1161.1Stsutsui	return (strcmp("eeprom", sa->sa_name) == 0);
1171.1Stsutsui}
1181.1Stsutsui
1191.1Stsutsuistatic int
1201.3Stsutsuimkclock_ebus_match(device_t parent, cfdata_t cf, void *aux)
1211.1Stsutsui{
1221.1Stsutsui	struct ebus_attach_args *ea = aux;
1231.1Stsutsui
1241.1Stsutsui	return (strcmp("eeprom", ea->ea_name) == 0);
1251.1Stsutsui}
1261.1Stsutsui
1271.1Stsutsui/*
1281.1Stsutsui * Attach a clock (really `eeprom') to the sbus or ebus.
1291.1Stsutsui *
1301.1Stsutsui * We ignore any existing virtual address as we need to map
1311.1Stsutsui * this read-only and make it read-write only temporarily,
1321.1Stsutsui * whenever we read or write the clock chip.  The clock also
1331.1Stsutsui * contains the ID ``PROM'', and I have already had the pleasure
1341.1Stsutsui * of reloading the CPU type, Ethernet address, etc, by hand from
1351.1Stsutsui * the console FORTH interpreter.  I intend not to enjoy it again.
1361.1Stsutsui *
1371.1Stsutsui * the MK48T02 is 2K.  the MK48T08 is 8K, and the MK48T59 is
1381.1Stsutsui * supposed to be identical to it.
1391.1Stsutsui *
1401.1Stsutsui * This is *UGLY*!  We probably have multiple mappings.  But I do
1411.1Stsutsui * know that this all fits inside an 8K page, so I'll just map in
1421.1Stsutsui * once.
1431.1Stsutsui *
1441.1Stsutsui * What we really need is some way to record the bus attach args
1451.1Stsutsui * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
1461.1Stsutsui * or not to write enable/disable the device registers.  This is
1471.1Stsutsui * a non-trivial operation.
1481.1Stsutsui */
1491.1Stsutsui
1501.1Stsutsui/* ARGSUSED */
1511.1Stsutsuistatic void
1521.3Stsutsuimkclock_sbus_attach(device_t parent, device_t self, void *aux)
1531.1Stsutsui{
1541.3Stsutsui	struct mk48txx_softc *sc = device_private(self);
1551.1Stsutsui	struct sbus_attach_args *sa = aux;
1561.1Stsutsui	int sz;
1571.1Stsutsui
1581.5Stsutsui	sc->sc_dev = self;
1591.1Stsutsui	sc->sc_bst = sa->sa_bustag;
1601.1Stsutsui
1611.1Stsutsui	/* use sa->sa_regs[0].size? */
1621.1Stsutsui	sz = 8192;
1631.1Stsutsui
1641.1Stsutsui	if (sbus_bus_map(sc->sc_bst,
1651.1Stsutsui			 sa->sa_slot,
1661.6Snakayama			 trunc_page(sa->sa_offset),
1671.1Stsutsui			 sz,
1681.1Stsutsui			 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
1691.1Stsutsui			 &sc->sc_bsh) != 0) {
1701.3Stsutsui		aprint_error(": can't map register\n");
1711.1Stsutsui		return;
1721.1Stsutsui	}
1731.1Stsutsui	mkclock_attach(sc, sa->sa_node);
1741.1Stsutsui}
1751.1Stsutsui
1761.1Stsutsui
1771.1Stsutsui/* ARGSUSED */
1781.1Stsutsuistatic void
1791.1Stsutsuimkclock_ebus_attach(struct device *parent, struct device *self, void *aux)
1801.1Stsutsui{
1811.4Stsutsui	struct mk48txx_softc *sc = device_private(self);
1821.1Stsutsui	struct ebus_attach_args *ea = aux;
1831.1Stsutsui	int sz;
1841.1Stsutsui
1851.5Stsutsui	sc->sc_dev = self;
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.3Stsutsui		aprint_error(": can't map register\n");
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.3Stsutsui	aprint_normal("\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