11592Srgrimes// SPDX-License-Identifier: GPL-2.0+
21592Srgrimes/*
31592Srgrimes * (C) Copyright 2003 Josef Baumgartner <josef.baumgartner@telex.de>
41592Srgrimes *
51592Srgrimes * (C) Copyright 2000
61592Srgrimes * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
71592Srgrimes */
81592Srgrimes
91592Srgrimes#include <init.h>
101592Srgrimes#include <irq_func.h>
111592Srgrimes#include <time.h>
121592Srgrimes#include <asm/global_data.h>
13262435Sbrueffer#include <linux/delay.h>
141592Srgrimes
151592Srgrimes#include <asm/timer.h>
161592Srgrimes#include <asm/immap.h>
171592Srgrimes#include <watchdog.h>
181592Srgrimes
191592SrgrimesDECLARE_GLOBAL_DATA_PTR;
201592Srgrimes
211592Srgrimesstatic volatile ulong timestamp = 0;
221592Srgrimes
231592Srgrimes#ifndef CFG_SYS_WATCHDOG_FREQ
241592Srgrimes#define CFG_SYS_WATCHDOG_FREQ (CONFIG_SYS_HZ / 2)
251592Srgrimes#endif
261592Srgrimes
271592Srgrimes#if CONFIG_IS_ENABLED(MCFTMR)
281592Srgrimes#ifndef CFG_SYS_UDELAY_BASE
291592Srgrimes#	error	"uDelay base not defined!"
3050476Speter#endif
311592Srgrimes
321592Srgrimes#if !defined(CFG_SYS_TMR_BASE) || !defined(CFG_SYS_INTR_BASE) || !defined(CFG_SYS_TMRINTR_NO) || !defined(CFG_SYS_TMRINTR_MASK)
331592Srgrimes#	error	"TMR_BASE, INTR_BASE, TMRINTR_NO or TMRINTR_MASk not defined!"
341592Srgrimes#endif
3517435Spstextern void dtimer_intr_setup(void);
361592Srgrimes
373936Spstvoid __udelay(unsigned long usec)
3825283Sdavidn{
3925283Sdavidn	volatile dtmr_t *timerp = (dtmr_t *) (CFG_SYS_UDELAY_BASE);
4025283Sdavidn	uint start, now, tmp;
41
42	while (usec > 0) {
43		if (usec > 65000)
44			tmp = 65000;
45		else
46			tmp = usec;
47		usec = usec - tmp;
48
49		/* Set up TIMER 3 as timebase clock */
50		timerp->tmr = DTIM_DTMR_RST_RST;
51		timerp->tcn = 0;
52		/* set period to 1 us */
53		timerp->tmr =
54		    CFG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 | DTIM_DTMR_FRR |
55		    DTIM_DTMR_RST_EN;
56
57		start = now = timerp->tcn;
58		while (now < start + tmp)
59			now = timerp->tcn;
60	}
61}
62
63void dtimer_interrupt(void *not_used)
64{
65	volatile dtmr_t *timerp = (dtmr_t *) (CFG_SYS_TMR_BASE);
66
67	/* check for timer interrupt asserted */
68	if ((CFG_SYS_TMRPND_REG & CFG_SYS_TMRINTR_MASK) == CFG_SYS_TMRINTR_PEND) {
69		timerp->ter = (DTIM_DTER_CAP | DTIM_DTER_REF);
70		timestamp++;
71
72		#if defined(CONFIG_WATCHDOG) || defined (CONFIG_HW_WATCHDOG)
73		if (CFG_SYS_WATCHDOG_FREQ && (timestamp % (CFG_SYS_WATCHDOG_FREQ)) == 0) {
74			schedule();
75		}
76		#endif    /* CONFIG_WATCHDOG || CONFIG_HW_WATCHDOG */
77		return;
78	}
79}
80
81int timer_init(void)
82{
83	volatile dtmr_t *timerp = (dtmr_t *) (CFG_SYS_TMR_BASE);
84
85	timestamp = 0;
86
87	timerp->tcn = 0;
88	timerp->trr = 0;
89
90	/* Set up TIMER 4 as clock */
91	timerp->tmr = DTIM_DTMR_RST_RST;
92
93	/* initialize and enable timer interrupt */
94	irq_install_handler(CFG_SYS_TMRINTR_NO, dtimer_interrupt, 0);
95
96	timerp->tcn = 0;
97	timerp->trr = 1000;	/* Interrupt every ms */
98
99	dtimer_intr_setup();
100
101	/* set a period of 1us, set timer mode to restart and enable timer and interrupt */
102	timerp->tmr = CFG_SYS_TIMER_PRESCALER | DTIM_DTMR_CLK_DIV1 |
103	    DTIM_DTMR_FRR | DTIM_DTMR_ORRI | DTIM_DTMR_RST_EN;
104
105	return 0;
106}
107
108ulong get_timer(ulong base)
109{
110	return (timestamp - base);
111}
112
113/*
114 * This function is derived from PowerPC code (read timebase as long long).
115 * On M68K it just returns the timer value.
116 */
117unsigned long long get_ticks(void)
118{
119	return get_timer(0);
120}
121#else
122static u64 timer64 __section(".data");
123static u16 timer16 __section(".data");
124
125uint64_t __weak get_ticks(void)
126{
127	volatile pit_t *timerp = (pit_t *) (CFG_SYS_UDELAY_BASE);
128	u16 val = ~timerp->pcntr;
129
130	if (timer16 > val)
131		timer64 += 0xffff - timer16 + val;
132	else
133		timer64 += val - timer16;
134
135	timer16 = val;
136
137	return timer64;
138}
139
140/* PIT timer */
141int timer_init(void)
142{
143	volatile pit_t *timerp = (pit_t *) (CFG_SYS_UDELAY_BASE);
144
145	timer16 = 0;
146	timer64 = 0;
147
148	/* Set up PIT as timebase clock */
149	timerp->pmr = 0xffff;
150	timerp->pcsr = PIT_PCSR_EN | PIT_PCSR_OVW;
151
152	return 0;
153}
154#endif				/* CONFIG_MCFTMR */
155
156unsigned long usec2ticks(unsigned long usec)
157{
158	return get_timer(usec);
159}
160
161/*
162 * This function is derived from PowerPC code (timebase clock frequency).
163 * On M68K it returns the number of timer ticks per second.
164 */
165ulong get_tbclk(void)
166{
167	return CONFIG_SYS_HZ;
168}
169