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
26178840Smarius#include <sys/cdefs.h>
27178840Smarius__FBSDID("$FreeBSD$");
28178840Smarius
2990619Stmm#include <sys/param.h>
3090619Stmm#include <sys/bus.h>
3190619Stmm#include <sys/malloc.h>
3290619Stmm#include <sys/systm.h>
3390619Stmm#include <sys/time.h>
3490619Stmm#include <sys/timetc.h>
3590619Stmm
3690619Stmm#include <machine/bus.h>
3790619Stmm#include <machine/bus_common.h>
3890619Stmm
3990619Stmm#define	COUNTER_MASK	((1 << 29) - 1)
4090619Stmm#define	COUNTER_FREQ	1000000
41135971Skensmith#define	COUNTER_QUALITY	100
4290619Stmm
4390619Stmm/* Bits in the limit register. */
4490619Stmm#define	CTLR_INTEN	(1U << 31)	/* Enable timer interrupts */
4590619Stmm#define	CTLR_RELOAD	(1U << 30)	/* Zero counter on write to limit reg */
4690619Stmm#define	CTLR_PERIODIC	(1U << 29)	/* Wrap to 0 if limit is reached */
4790619Stmm
4890619Stmm/* Offsets of the registers for the two counters. */
4990619Stmm#define	CTR_CT0		0x00
5090619Stmm#define	CTR_CT1		0x10
5190619Stmm
5290619Stmm/* Register offsets from the base address. */
5390619Stmm#define	CTR_COUNT	0x00
5490619Stmm#define	CTR_LIMIT	0x08
5590619Stmm
5690619Stmm
57178840Smariusstatic timecounter_get_t counter_get_timecount;
5890619Stmm
5990619Stmmstruct ct_softc {
6090619Stmm	bus_space_tag_t		sc_tag;
6190619Stmm	bus_space_handle_t	sc_handle;
6290619Stmm	bus_addr_t		sc_offset;
6390619Stmm};
6490619Stmm
6590619Stmm
6690619Stmm/*
67178840Smarius * This is called from the psycho and sbus drivers.  It does not directly
68178840Smarius * attach to the nexus because it shares register space with the bridge in
69178840Smarius * question.
7090619Stmm */
7190619Stmmvoid
72178840Smariussparc64_counter_init(const char *name, bus_space_tag_t tag,
73178840Smarius    bus_space_handle_t handle, bus_addr_t offset)
7490619Stmm{
7590619Stmm	struct timecounter *tc;
7690619Stmm	struct ct_softc *sc;
7790619Stmm
78129083Smux	printf("initializing counter-timer\n");
7990619Stmm	/*
80178840Smarius	 * Turn off interrupts from both counters.  Set the limit to the
81178840Smarius	 * maximum value (although that should not change anything with
82178840Smarius	 * CTLR_INTEN and CTLR_PERIODIC off).
8390619Stmm	 */
84129083Smux	bus_space_write_8(tag, handle, offset + CTR_CT0 + CTR_LIMIT,
85129083Smux	    COUNTER_MASK);
8690619Stmm	bus_space_write_8(tag, handle, offset + CTR_CT1 + CTR_LIMIT,
8790619Stmm	    COUNTER_MASK);
8890619Stmm	/* Register as a time counter. */
89223961Smarius	tc = malloc(sizeof(*tc), M_DEVBUF, M_WAITOK | M_ZERO);
90111119Simp	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
9190619Stmm	sc->sc_tag = tag;
9290619Stmm	sc->sc_handle = handle;
9390619Stmm	sc->sc_offset = offset + CTR_CT0;
9490619Stmm	tc->tc_get_timecount = counter_get_timecount;
9590619Stmm	tc->tc_counter_mask = COUNTER_MASK;
9690619Stmm	tc->tc_frequency = COUNTER_FREQ;
97178840Smarius	tc->tc_name = strdup(name, M_DEVBUF);
9890619Stmm	tc->tc_priv = sc;
99135971Skensmith	tc->tc_quality = COUNTER_QUALITY;
10090619Stmm	tc_init(tc);
10190619Stmm}
10290619Stmm
103129083Smuxstatic unsigned int
10490619Stmmcounter_get_timecount(struct timecounter *tc)
10590619Stmm{
10690619Stmm	struct ct_softc *sc;
10790619Stmm
10890619Stmm	sc = tc->tc_priv;
109223961Smarius	return (bus_space_read_8(sc->sc_tag, sc->sc_handle, sc->sc_offset));
11090619Stmm}
111