counter.c revision 90619
190619Stmm/*-
290619Stmm * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
390619Stmm * All rights reserved.
490619Stmm *
590619Stmm * Redistribution and use in source and binary forms, with or without
690619Stmm * modification, are permitted provided that the following conditions
790619Stmm * are met:
890619Stmm * 1. Redistributions of source code must retain the above copyright
990619Stmm *    notice, this list of conditions and the following disclaimer.
1090619Stmm * 2. Redistributions in binary form must reproduce the above copyright
1190619Stmm *    notice, this list of conditions and the following disclaimer in the
1290619Stmm *    documentation and/or other materials provided with the distribution.
1390619Stmm *
1490619Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1590619Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1690619Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1790619Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
1890619Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1990619Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2090619Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2190619Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2290619Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2390619Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2490619Stmm *
2590619Stmm * $FreeBSD: head/sys/sparc64/sparc64/counter.c 90619 2002-02-13 16:16:36Z tmm $
2690619Stmm */
2790619Stmm
2890619Stmm#include <sys/param.h>
2990619Stmm#include <sys/bus.h>
3090619Stmm#include <sys/malloc.h>
3190619Stmm#include <sys/systm.h>
3290619Stmm#include <sys/time.h>
3390619Stmm#include <sys/timetc.h>
3490619Stmm
3590619Stmm#include <machine/bus.h>
3690619Stmm#include <machine/bus_common.h>
3790619Stmm
3890619Stmm#define	COUNTER_MASK	((1 << 29) - 1)
3990619Stmm#define	COUNTER_FREQ	1000000
4090619Stmm
4190619Stmm/* Bits in the limit register. */
4290619Stmm#define	CTLR_INTEN	(1U << 31)	/* Enable timer interrupts */
4390619Stmm#define	CTLR_RELOAD	(1U << 30)	/* Zero counter on write to limit reg */
4490619Stmm#define	CTLR_PERIODIC	(1U << 29)	/* Wrap to 0 if limit is reached */
4590619Stmm
4690619Stmm/* Offsets of the registers for the two counters. */
4790619Stmm#define	CTR_CT0		0x00
4890619Stmm#define	CTR_CT1		0x10
4990619Stmm
5090619Stmm/* Register offsets from the base address. */
5190619Stmm#define	CTR_COUNT	0x00
5290619Stmm#define	CTR_LIMIT	0x08
5390619Stmm
5490619Stmm
5590619Stmmstatic unsigned counter_get_timecount(struct timecounter *tc);
5690619Stmm
5790619Stmmstruct ct_softc {
5890619Stmm	bus_space_tag_t		sc_tag;
5990619Stmm	bus_space_handle_t	sc_handle;
6090619Stmm	bus_addr_t		sc_offset;
6190619Stmm};
6290619Stmm
6390619Stmm
6490619Stmm/*
6590619Stmm * This is called from the psycho and sbus drivers. It does not directly attach
6690619Stmm * to the nexus because it shares register space with the bridge in question.
6790619Stmm */
6890619Stmmvoid
6990619Stmmsparc64_counter_init(bus_space_tag_t tag, bus_space_handle_t handle,
7090619Stmm    bus_addr_t offset)
7190619Stmm{
7290619Stmm	struct timecounter *tc;
7390619Stmm	struct ct_softc *sc;
7490619Stmm
7590619Stmm	printf("initialializing counter-timer\n");
7690619Stmm	/*
7790619Stmm	 * Turn off interrupts from both counters. Set the limit to the maximum
7890619Stmm	 * value (although that should not change anything with CTLR_INTEN and
7990619Stmm	 * CTLR_PERIODIC off).
8090619Stmm	 */
8190619Stmm	bus_space_write_8(tag, handle, offset + CTR_CT0 + CTR_LIMIT
8290619Stmm	    , COUNTER_MASK);
8390619Stmm	bus_space_write_8(tag, handle, offset + CTR_CT1 + CTR_LIMIT,
8490619Stmm	    COUNTER_MASK);
8590619Stmm	/* Register as a time counter. */
8690619Stmm	tc = malloc(sizeof(*tc), M_DEVBUF, M_WAITOK);
8790619Stmm	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
8890619Stmm	sc->sc_tag = tag;
8990619Stmm	sc->sc_handle = handle;
9090619Stmm	sc->sc_offset = offset + CTR_CT0;
9190619Stmm	tc->tc_get_timecount = counter_get_timecount;
9290619Stmm	tc->tc_poll_pps = NULL;
9390619Stmm	tc->tc_counter_mask = COUNTER_MASK;
9490619Stmm	tc->tc_frequency = COUNTER_FREQ;
9590619Stmm	tc->tc_name = "counter-timer";
9690619Stmm	tc->tc_priv = sc;
9790619Stmm	tc_init(tc);
9890619Stmm}
9990619Stmm
10090619Stmmstatic unsigned
10190619Stmmcounter_get_timecount(struct timecounter *tc)
10290619Stmm{
10390619Stmm	struct ct_softc *sc;
10490619Stmm
10590619Stmm	sc = tc->tc_priv;
10690619Stmm	return (bus_space_read_8(sc->sc_tag, sc->sc_handle, sc->sc_offset) &
10790619Stmm	    COUNTER_MASK);
10890619Stmm}
10990619Stmm
110