xref: /netbsd-src/sys/arch/arm/xscale/ixp425_timer.c (revision 482eef70502290f7cbd2cb9a24a4f41e6bacd98d)
1*482eef70Srin /*	$NetBSD: ixp425_timer.c,v 1.20 2020/05/29 12:30:39 rin Exp $ */
200eb02e3Sichiro 
300eb02e3Sichiro /*
400eb02e3Sichiro  * Copyright (c) 2003
500eb02e3Sichiro  *	Ichiro FUKUHARA <ichiro@ichiro.org>.
600eb02e3Sichiro  * All rights reserved.
700eb02e3Sichiro  *
800eb02e3Sichiro  * Redistribution and use in source and binary forms, with or without
900eb02e3Sichiro  * modification, are permitted provided that the following conditions
1000eb02e3Sichiro  * are met:
1100eb02e3Sichiro  * 1. Redistributions of source code must retain the above copyright
1200eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer.
1300eb02e3Sichiro  * 2. Redistributions in binary form must reproduce the above copyright
1400eb02e3Sichiro  *    notice, this list of conditions and the following disclaimer in the
1500eb02e3Sichiro  *    documentation and/or other materials provided with the distribution.
1600eb02e3Sichiro  *
1700eb02e3Sichiro  * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``AS IS'' AND ANY EXPRESS OR
1800eb02e3Sichiro  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1900eb02e3Sichiro  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2000eb02e3Sichiro  * IN NO EVENT SHALL ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
2100eb02e3Sichiro  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2200eb02e3Sichiro  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2300eb02e3Sichiro  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2400eb02e3Sichiro  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2500eb02e3Sichiro  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2600eb02e3Sichiro  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2700eb02e3Sichiro  * SUCH DAMAGE.
2800eb02e3Sichiro  */
2900eb02e3Sichiro 
3000eb02e3Sichiro #include <sys/cdefs.h>
31*482eef70Srin __KERNEL_RCSID(0, "$NetBSD: ixp425_timer.c,v 1.20 2020/05/29 12:30:39 rin Exp $");
3200eb02e3Sichiro 
33c95cd915Sscw #include "opt_ixp425.h"
3400eb02e3Sichiro 
3500eb02e3Sichiro #include <sys/types.h>
3600eb02e3Sichiro #include <sys/param.h>
3700eb02e3Sichiro #include <sys/systm.h>
3800eb02e3Sichiro #include <sys/kernel.h>
394e56cdd2Sjoerg #include <sys/atomic.h>
4000eb02e3Sichiro #include <sys/time.h>
414e56cdd2Sjoerg #include <sys/timetc.h>
4200eb02e3Sichiro #include <sys/device.h>
4300eb02e3Sichiro 
44ca601a77Sthorpej #include <dev/clock_subr.h>
45ca601a77Sthorpej 
46ed9977b1Sdyoung #include <sys/bus.h>
4700eb02e3Sichiro #include <machine/intr.h>
4800eb02e3Sichiro 
4900eb02e3Sichiro #include <arm/cpufunc.h>
5000eb02e3Sichiro 
5100eb02e3Sichiro #include <arm/xscale/ixp425reg.h>
5200eb02e3Sichiro #include <arm/xscale/ixp425var.h>
5300eb02e3Sichiro #include <arm/xscale/ixp425_sipvar.h>
5400eb02e3Sichiro 
55a2b8c7fbSmsaitoh static int	ixpclk_match(device_t, cfdata_t, void *);
56a2b8c7fbSmsaitoh static void	ixpclk_attach(device_t, device_t, void *);
574e56cdd2Sjoerg static u_int	ixpclk_get_timecount(struct timecounter *);
5800eb02e3Sichiro 
5900eb02e3Sichiro static uint32_t counts_per_hz;
6000eb02e3Sichiro 
6100eb02e3Sichiro static void *clock_ih;
6200eb02e3Sichiro 
6300eb02e3Sichiro /* callback functions for intr_functions */
6400eb02e3Sichiro int	ixpclk_intr(void *);
6500eb02e3Sichiro 
6600eb02e3Sichiro struct ixpclk_softc {
6700eb02e3Sichiro 	bus_addr_t		sc_baseaddr;
6800eb02e3Sichiro 	bus_space_tag_t		sc_iot;
6900eb02e3Sichiro 	bus_space_handle_t      sc_ioh;
7000eb02e3Sichiro };
7100eb02e3Sichiro 
72c95cd915Sscw #ifndef IXP425_CLOCK_FREQ
73fb2c5211Sscw #define	COUNTS_PER_SEC		66666600	/* 66MHz */
74c95cd915Sscw #else
75c95cd915Sscw #define	COUNTS_PER_SEC		IXP425_CLOCK_FREQ
76c95cd915Sscw #endif
77fb2c5211Sscw #define	COUNTS_PER_USEC		((COUNTS_PER_SEC / 1000000) + 1)
7800eb02e3Sichiro 
79fb2c5211Sscw static struct ixpclk_softc *ixpclk_sc;
8000eb02e3Sichiro 
814e56cdd2Sjoerg static struct timecounter ixpclk_timecounter = {
82*482eef70Srin 	.tc_get_timecount = ixpclk_get_timecount,
83*482eef70Srin 	.tc_counter_mask = 0xffffffff,
84*482eef70Srin 	.tc_frequency = COUNTS_PER_SEC,
85*482eef70Srin 	.tc_name = "ixpclk",
86*482eef70Srin 	.tc_quality = 100,
874e56cdd2Sjoerg };
884e56cdd2Sjoerg 
894e56cdd2Sjoerg static volatile uint32_t ixpclk_base;
904e56cdd2Sjoerg 
91a2b8c7fbSmsaitoh CFATTACH_DECL_NEW(ixpclk, sizeof(struct ixpclk_softc),
9200eb02e3Sichiro 		ixpclk_match, ixpclk_attach, NULL, NULL);
9300eb02e3Sichiro 
9400eb02e3Sichiro #define GET_TIMER_VALUE(sc)	(bus_space_read_4((sc)->sc_iot,		\
9500eb02e3Sichiro 						  (sc)->sc_ioh,		\
9600eb02e3Sichiro 						  IXP425_OST_TIM0))
9700eb02e3Sichiro 
9808a4aba7Sskrll #define GET_TS_VALUE(sc)	(*(volatile uint32_t *) \
995801c731Sscw 				  (IXP425_TIMER_VBASE + IXP425_OST_TS))
1005801c731Sscw 
10100eb02e3Sichiro static int
ixpclk_match(device_t parent,cfdata_t match,void * aux)102a2b8c7fbSmsaitoh ixpclk_match(device_t parent, cfdata_t match, void *aux)
10300eb02e3Sichiro {
10400eb02e3Sichiro 	return 2;
10500eb02e3Sichiro }
10600eb02e3Sichiro 
10700eb02e3Sichiro static void
ixpclk_attach(device_t parent,device_t self,void * aux)108a2b8c7fbSmsaitoh ixpclk_attach(device_t parent, device_t self, void *aux)
10900eb02e3Sichiro {
110a2b8c7fbSmsaitoh 	struct ixpclk_softc		*sc = device_private(self);
11100eb02e3Sichiro 	struct ixpsip_attach_args	*sa = aux;
11200eb02e3Sichiro 
11300eb02e3Sichiro 	printf("\n");
11400eb02e3Sichiro 
1155801c731Sscw 	ixpclk_sc = sc;
1165801c731Sscw 
11700eb02e3Sichiro 	sc->sc_iot = sa->sa_iot;
11800eb02e3Sichiro 	sc->sc_baseaddr = sa->sa_addr;
11900eb02e3Sichiro 
12000eb02e3Sichiro 	if (bus_space_map(sc->sc_iot, sa->sa_addr, sa->sa_size, 0,
12100eb02e3Sichiro 			  &sc->sc_ioh))
122a2b8c7fbSmsaitoh 		panic("%s: Cannot map registers", device_xname(self));
12300eb02e3Sichiro 
124a2b8c7fbSmsaitoh 	aprint_normal_dev(self, "IXP425 Interval Timer\n");
12500eb02e3Sichiro }
12600eb02e3Sichiro 
12700eb02e3Sichiro /*
12800eb02e3Sichiro  * cpu_initclocks:
12900eb02e3Sichiro  *
13000eb02e3Sichiro  *	Initialize the clock and get them going.
13100eb02e3Sichiro  */
13200eb02e3Sichiro void
cpu_initclocks(void)13300eb02e3Sichiro cpu_initclocks(void)
13400eb02e3Sichiro {
13500eb02e3Sichiro 	struct ixpclk_softc *sc = ixpclk_sc;
13600eb02e3Sichiro 	u_int oldirqstate;
13700eb02e3Sichiro 
13800eb02e3Sichiro 	if (hz < 50 || COUNTS_PER_SEC % hz) {
13900eb02e3Sichiro 		aprint_error("Cannot get %d Hz clock; using 100 Hz\n", hz);
14000eb02e3Sichiro 		hz = 100;
14100eb02e3Sichiro 	}
14200eb02e3Sichiro 
14300eb02e3Sichiro 	/*
14400eb02e3Sichiro 	 * We only have one timer available; stathz and profhz are
14500eb02e3Sichiro 	 * always left as 0 (the upper-layer clock code deals with
14600eb02e3Sichiro 	 * this situation).
14700eb02e3Sichiro 	 */
14800eb02e3Sichiro 	if (stathz != 0)
14900eb02e3Sichiro 		aprint_error("Cannot get %d Hz statclock\n", stathz);
15000eb02e3Sichiro 	stathz = 0;
15100eb02e3Sichiro 
15200eb02e3Sichiro 	if (profhz != 0)
15300eb02e3Sichiro 		aprint_error("Cannot get %d Hz profclock\n", profhz);
15400eb02e3Sichiro 	profhz = 0;
15500eb02e3Sichiro 
15600eb02e3Sichiro 	/* Report the clock frequency. */
15700eb02e3Sichiro 	aprint_normal("clock: hz=%d stathz=%d profhz=%d\n", hz, stathz, profhz);
15800eb02e3Sichiro 
15900eb02e3Sichiro 	oldirqstate = disable_interrupts(I32_bit);
16000eb02e3Sichiro 
16100eb02e3Sichiro 	/* Hook up the clock interrupt handler. */
16200eb02e3Sichiro 	clock_ih = ixp425_intr_establish(IXP425_INT_TMR0, IPL_CLOCK,
16300eb02e3Sichiro 					 ixpclk_intr, NULL);
16400eb02e3Sichiro 	if (clock_ih == NULL)
16500eb02e3Sichiro 		panic("cpu_initclocks: unable to register timer interrupt");
16600eb02e3Sichiro 
16700eb02e3Sichiro 	/* Set up the new clock parameters. */
16800eb02e3Sichiro 
16900eb02e3Sichiro 	/* clear interrupt */
17000eb02e3Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
17100eb02e3Sichiro 			  OST_WARM_RESET | OST_WDOG_INT | OST_TS_INT |
17200eb02e3Sichiro 			  OST_TIM1_INT | OST_TIM0_INT);
17300eb02e3Sichiro 
17400eb02e3Sichiro 	counts_per_hz = COUNTS_PER_SEC / hz;
17500eb02e3Sichiro 
17600eb02e3Sichiro 	/* reload value & Timer enable */
17700eb02e3Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_TIM0_RELOAD,
17800eb02e3Sichiro 			  (counts_per_hz & TIMERRELOAD_MASK) | OST_TIMER_EN);
17900eb02e3Sichiro 
18000eb02e3Sichiro 	restore_interrupts(oldirqstate);
1814e56cdd2Sjoerg 
1824e56cdd2Sjoerg 	tc_init(&ixpclk_timecounter);
18300eb02e3Sichiro }
18400eb02e3Sichiro 
18500eb02e3Sichiro /*
18600eb02e3Sichiro  * setstatclockrate:
18700eb02e3Sichiro  *
18800eb02e3Sichiro  *	Set the rate of the statistics clock.
18900eb02e3Sichiro  *
19000eb02e3Sichiro  *	We assume that hz is either stathz or profhz, and that neither
19100eb02e3Sichiro  *	will change after being set by cpu_initclocks().  We could
19200eb02e3Sichiro  *	recalculate the intervals here, but that would be a pain.
19300eb02e3Sichiro  */
19400eb02e3Sichiro void
setstatclockrate(int newhz)195a816cb98She setstatclockrate(int newhz)
19600eb02e3Sichiro {
19700eb02e3Sichiro 
19800eb02e3Sichiro 	/*
19900eb02e3Sichiro 	 * XXX Use TMR1?
20000eb02e3Sichiro 	 */
20100eb02e3Sichiro }
20200eb02e3Sichiro 
2034e56cdd2Sjoerg static u_int
ixpclk_get_timecount(struct timecounter * tc)2044e56cdd2Sjoerg ixpclk_get_timecount(struct timecounter *tc)
20500eb02e3Sichiro {
2064e56cdd2Sjoerg 	u_int	savedints, base, counter;
20700eb02e3Sichiro 
2084e56cdd2Sjoerg 	savedints = disable_interrupts(I32_bit);
2094e56cdd2Sjoerg 	base = ixpclk_base;
2104e56cdd2Sjoerg 	counter = GET_TIMER_VALUE(ixpclk_sc);
2114e56cdd2Sjoerg 	restore_interrupts(savedints);
21200eb02e3Sichiro 
2134e56cdd2Sjoerg 	return base - counter;
21400eb02e3Sichiro }
21500eb02e3Sichiro 
21600eb02e3Sichiro /*
21700eb02e3Sichiro  * delay:
21800eb02e3Sichiro  *
21900eb02e3Sichiro  *	Delay for at least N microseconds.
22000eb02e3Sichiro  */
22100eb02e3Sichiro void
delay(u_int n)22200eb02e3Sichiro delay(u_int n)
22300eb02e3Sichiro {
22408a4aba7Sskrll 	uint32_t first, last;
2255801c731Sscw 	int usecs;
2265801c731Sscw 
2275801c731Sscw 	if (n == 0)
2285801c731Sscw 		return;
22900eb02e3Sichiro 
23000eb02e3Sichiro 	/*
2315801c731Sscw 	 * Clamp the timeout at a maximum value (about 32 seconds with
2325801c731Sscw 	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
2335801c731Sscw 	 * near that length of time and if they are, they should be hung
2345801c731Sscw 	 * out to dry.
23500eb02e3Sichiro 	 */
2365801c731Sscw 	if (n >= (0x80000000U / COUNTS_PER_USEC))
2375801c731Sscw 		usecs = (0x80000000U / COUNTS_PER_USEC) - 1;
23800eb02e3Sichiro 	else
2395801c731Sscw 		usecs = n * COUNTS_PER_USEC;
24000eb02e3Sichiro 
2415801c731Sscw 	/* Note: Timestamp timer counts *up*, unlike the other timers */
2425801c731Sscw 	first = GET_TS_VALUE();
24300eb02e3Sichiro 
2445801c731Sscw 	while (usecs > 0) {
2455801c731Sscw 		last = GET_TS_VALUE();
2465801c731Sscw 		usecs -= (int)(last - first);
2475801c731Sscw 		first = last;
24800eb02e3Sichiro 	}
24900eb02e3Sichiro }
25000eb02e3Sichiro 
25100eb02e3Sichiro /*
25200eb02e3Sichiro  * ixpclk_intr:
25300eb02e3Sichiro  *
25400eb02e3Sichiro  *	Handle the hardclock interrupt.
25500eb02e3Sichiro  */
25600eb02e3Sichiro int
ixpclk_intr(void * arg)25700eb02e3Sichiro ixpclk_intr(void *arg)
25800eb02e3Sichiro {
25900eb02e3Sichiro 	struct ixpclk_softc *sc = ixpclk_sc;
26000eb02e3Sichiro 	struct clockframe *frame = arg;
26100eb02e3Sichiro 
26200eb02e3Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
26300eb02e3Sichiro 			  OST_TIM0_INT);
26400eb02e3Sichiro 
2654e56cdd2Sjoerg 	atomic_add_32(&ixpclk_base, counts_per_hz);
2664e56cdd2Sjoerg 
26700eb02e3Sichiro 	hardclock(frame);
26800eb02e3Sichiro 
26900eb02e3Sichiro 	return (1);
27000eb02e3Sichiro }
271