ARM: Davinci: Fix DM644x timer overflow handling and cleanup
Fix ARM based DaVinci DM644x timer overflow handling and cleanup timer code. Changes: - Remove *_masked() functions as noted by Wolfgang - Adapt register naming to recent TI spec (sprue26, March 2007) - Fix reset_timer() handling - As reported by Pieter [1] the overflow fix introduced a delay of factor 16 (e.g 2 seconds became 32). While the overflow fix is basically okay, it missed to divide udelay by 16, too. Fix this. [1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/38179 - Remove software division of timer count value (DIV(x) macro) and do it in hardware (TIM_CLK_DIV). Many thanks to Troy Kisky <troy.kisky@boundarydevices.com> and Pieter Voorthuijsen <pieter.voorthuijsen@Prodrive.nl> for the hints & testing! Patch is compile tested with davinci_dvevm & sonata & schmoogie configuration and tested by Pieter on DaVinci EVM hardware. Signed-off-by: Dirk Behme <dirk.behme@gmail.com> Acked-by: Pieter Voorthuijsen <pieter.voorthuijsen@Prodrive.nl>
This commit is contained in:
		
							parent
							
								
									58c5376ba6
								
							
						
					
					
						commit
						80c40b765b
					
				| 
						 | 
					@ -42,9 +42,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef volatile struct {
 | 
					typedef volatile struct {
 | 
				
			||||||
	u_int32_t	pid12;
 | 
						u_int32_t	pid12;
 | 
				
			||||||
	u_int32_t	emumgt_clksped;
 | 
						u_int32_t	emumgt;
 | 
				
			||||||
	u_int32_t	gpint_en;
 | 
						u_int32_t	na1;
 | 
				
			||||||
	u_int32_t	gpdir_dat;
 | 
						u_int32_t	na2;
 | 
				
			||||||
	u_int32_t	tim12;
 | 
						u_int32_t	tim12;
 | 
				
			||||||
	u_int32_t	tim34;
 | 
						u_int32_t	tim34;
 | 
				
			||||||
	u_int32_t	prd12;
 | 
						u_int32_t	prd12;
 | 
				
			||||||
| 
						 | 
					@ -52,21 +52,12 @@ typedef volatile struct {
 | 
				
			||||||
	u_int32_t	tcr;
 | 
						u_int32_t	tcr;
 | 
				
			||||||
	u_int32_t	tgcr;
 | 
						u_int32_t	tgcr;
 | 
				
			||||||
	u_int32_t	wdtcr;
 | 
						u_int32_t	wdtcr;
 | 
				
			||||||
	u_int32_t	tlgc;
 | 
					 | 
				
			||||||
	u_int32_t	tlmr;
 | 
					 | 
				
			||||||
} davinci_timer;
 | 
					} davinci_timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
davinci_timer		*timer = (davinci_timer *)CFG_TIMERBASE;
 | 
					davinci_timer		*timer = (davinci_timer *)CFG_TIMERBASE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TIMER_LOAD_VAL	(CFG_HZ_CLOCK / CFG_HZ)
 | 
					#define TIMER_LOAD_VAL	(CFG_HZ_CLOCK / CFG_HZ)
 | 
				
			||||||
#define READ_TIMER	timer->tim34
 | 
					#define TIM_CLK_DIV	16
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Timer runs with CFG_HZ_CLOCK, currently 27MHz. To avoid wrap
 | 
					 | 
				
			||||||
 * around of timestamp already after min ~159s, divide it, e.g. by 16.
 | 
					 | 
				
			||||||
 * timestamp will then wrap around all min ~42min
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define DIV(x)		((x) >> 4)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ulong timestamp;
 | 
					static ulong timestamp;
 | 
				
			||||||
static ulong lastinc;
 | 
					static ulong lastinc;
 | 
				
			||||||
| 
						 | 
					@ -76,24 +67,43 @@ int timer_init(void)
 | 
				
			||||||
	/* We are using timer34 in unchained 32-bit mode, full speed */
 | 
						/* We are using timer34 in unchained 32-bit mode, full speed */
 | 
				
			||||||
	timer->tcr = 0x0;
 | 
						timer->tcr = 0x0;
 | 
				
			||||||
	timer->tgcr = 0x0;
 | 
						timer->tgcr = 0x0;
 | 
				
			||||||
	timer->tgcr = 0x06;
 | 
						timer->tgcr = 0x06 | ((TIM_CLK_DIV - 1) << 8);
 | 
				
			||||||
	timer->tim34 = 0x0;
 | 
						timer->tim34 = 0x0;
 | 
				
			||||||
	timer->prd34 = TIMER_LOAD_VAL;
 | 
						timer->prd34 = TIMER_LOAD_VAL;
 | 
				
			||||||
	lastinc = 0;
 | 
						lastinc = 0;
 | 
				
			||||||
	timer->tcr = 0x80 << 16;
 | 
					 | 
				
			||||||
	timestamp = 0;
 | 
						timestamp = 0;
 | 
				
			||||||
 | 
						timer->tcr = 2 << 22;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return(0);
 | 
						return(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void reset_timer(void)
 | 
					void reset_timer(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	reset_timer_masked();
 | 
						timer->tcr = 0x0;
 | 
				
			||||||
 | 
						timer->tim34 = 0;
 | 
				
			||||||
 | 
						lastinc = 0;
 | 
				
			||||||
 | 
						timestamp = 0;
 | 
				
			||||||
 | 
						timer->tcr = 2 << 22;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ulong get_timer_raw(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ulong now = timer->tim34;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (now >= lastinc) {
 | 
				
			||||||
 | 
							/* normal mode */
 | 
				
			||||||
 | 
							timestamp += now - lastinc;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* overflow ... */
 | 
				
			||||||
 | 
							timestamp += now + TIMER_LOAD_VAL - lastinc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						lastinc = now;
 | 
				
			||||||
 | 
						return timestamp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ulong get_timer(ulong base)
 | 
					ulong get_timer(ulong base)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return(get_timer_masked() - base);
 | 
						return((get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void set_timer(ulong t)
 | 
					void set_timer(ulong t)
 | 
				
			||||||
| 
						 | 
					@ -102,37 +112,6 @@ void set_timer(ulong t)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void udelay(unsigned long usec)
 | 
					void udelay(unsigned long usec)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	udelay_masked(usec);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void reset_timer_masked(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	lastinc = DIV(READ_TIMER);
 | 
					 | 
				
			||||||
	timestamp = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ulong get_timer_raw(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ulong now = DIV(READ_TIMER);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (now >= lastinc) {
 | 
					 | 
				
			||||||
		/* normal mode */
 | 
					 | 
				
			||||||
		timestamp += now - lastinc;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* overflow ... */
 | 
					 | 
				
			||||||
		timestamp += now + DIV(TIMER_LOAD_VAL) - lastinc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	lastinc = now;
 | 
					 | 
				
			||||||
	return timestamp;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ulong get_timer_masked(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return(get_timer_raw() / DIV(TIMER_LOAD_VAL));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void udelay_masked(unsigned long usec)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ulong tmo;
 | 
						ulong tmo;
 | 
				
			||||||
	ulong endtime;
 | 
						ulong endtime;
 | 
				
			||||||
| 
						 | 
					@ -140,7 +119,7 @@ void udelay_masked(unsigned long usec)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tmo = CFG_HZ_CLOCK / 1000;
 | 
						tmo = CFG_HZ_CLOCK / 1000;
 | 
				
			||||||
	tmo *= usec;
 | 
						tmo *= usec;
 | 
				
			||||||
	tmo /= 1000;
 | 
						tmo /= (1000 * TIM_CLK_DIV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endtime = get_timer_raw() + tmo;
 | 
						endtime = get_timer_raw() + tmo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,8 +144,5 @@ unsigned long long get_ticks(void)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ulong get_tbclk(void)
 | 
					ulong get_tbclk(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ulong tbclk;
 | 
						return CFG_HZ;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	tbclk = CFG_HZ;
 | 
					 | 
				
			||||||
	return(tbclk);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue