diff mbox

Undocumented silicon bug

Message ID 50C8ED4B.4010307@corelatus.se (mailing list archive)
State Not Applicable
Headers show

Commit Message

Thomas Lange Dec. 12, 2012, 8:47 p.m. UTC
The time drift problem I have been chasing for a while, see
http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2012-December/025821.html
, seems to be due to an undocumented silicon bug.

The attached patch to master ( c22cf7755db6500df037cecdd6b290394d82392e
  Origin: git://gitorious.org/linux-davinci/linux-davinci.git )
exercises the problem. Example console output from my EVM6446 card:

----------------
Before  T0:0x5ed55a T1:0x5ed55d Diff:-3
After  T0:0x5ed817 T1:0x5ed824 Diff:-13
Before  T0:0x62a7e5 T1:0x62a7f3 Diff:-14
After  T0:0x62adff T1:0x62ae17 Diff:-24
Before  T0:0x66cbfb T1:0x66cc14 Diff:-25
After  T0:0x66d1f6 T1:0x66d219 Diff:-35
Before  T0:0x6aeab0 T1:0x6aead4 Diff:-36
After  T0:0x6af0ec T1:0x6af11a Diff:-46
Before  T0:0x6f09ef T1:0x6f0a1e Diff:-47
After  T0:0x6f1018 T1:0x6f1051 Diff:-57
Before  T0:0x732821 T1:0x73285b Diff:-58
After  T0:0x732e1a T1:0x732e5e Diff:-68
---------------

This shows that TIM34_0 misses 11 ticks every time a new event is setup
(10 ticks from my test loop + the original code 1).

If someone from TI can verify that the problem exists in all Davinci
versions, a workaround should be pretty straightforward, assuming this
is the only symptom of the bug.

Regards,
/Thomas

Comments

Sekhar Nori Dec. 13, 2012, 1:28 p.m. UTC | #1
On 12/13/2012 2:17 AM, Thomas Lange wrote:
> The time drift problem I have been chasing for a while, see
> http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2012-December/025821.html
> , seems to be due to an undocumented silicon bug.
> 
> The attached patch to master ( c22cf7755db6500df037cecdd6b290394d82392e
>   Origin: git://gitorious.org/linux-davinci/linux-davinci.git )
> exercises the problem. Example console output from my EVM6446 card:
> 
> ----------------
> Before  T0:0x5ed55a T1:0x5ed55d Diff:-3
> After  T0:0x5ed817 T1:0x5ed824 Diff:-13
> Before  T0:0x62a7e5 T1:0x62a7f3 Diff:-14
> After  T0:0x62adff T1:0x62ae17 Diff:-24
> Before  T0:0x66cbfb T1:0x66cc14 Diff:-25
> After  T0:0x66d1f6 T1:0x66d219 Diff:-35
> Before  T0:0x6aeab0 T1:0x6aead4 Diff:-36
> After  T0:0x6af0ec T1:0x6af11a Diff:-46
> Before  T0:0x6f09ef T1:0x6f0a1e Diff:-47
> After  T0:0x6f1018 T1:0x6f1051 Diff:-57
> Before  T0:0x732821 T1:0x73285b Diff:-58
> After  T0:0x732e1a T1:0x732e5e Diff:-68
> ---------------
> 
> This shows that TIM34_0 misses 11 ticks every time a new event is setup
> (10 ticks from my test loop + the original code 1).
> 
> If someone from TI can verify that the problem exists in all Davinci
> versions, a workaround should be pretty straightforward, assuming this
> is the only symptom of the bug.

I was not able to spend too much time on this today, but I did try your
patch on my DM644x EVM and have observations similar to what you
describe above. Further, I see that reading TIM12 instead of writing it
does not cause the same drift on TIM34. I still need to try on a
different DaVinci device.

One thing to try would be to temporarily stop both TIM12_0 and TIM34_0
using ENAMODE bits in TCR before resetting TIM12_0. There is a cryptic
note about writes to timer register being disallowed when timer is
running in section 2.4.2 of http://www.ti.com/lit/ug/sprue26/sprue26.pdf

Thanks,
Sekhar
Thomas Lange Dec. 13, 2012, 3:52 p.m. UTC | #2
On 2012-12-13 14:28, Sekhar Nori wrote:
> On 12/13/2012 2:17 AM, Thomas Lange wrote:
>> The time drift problem I have been chasing for a while, see
>> http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2012-December/025821.html
>> , seems to be due to an undocumented silicon bug.
>>
>> The attached patch to master ( c22cf7755db6500df037cecdd6b290394d82392e
>>   Origin: git://gitorious.org/linux-davinci/linux-davinci.git )
>> exercises the problem. Example console output from my EVM6446 card:
>>
>> ----------------
>> Before  T0:0x5ed55a T1:0x5ed55d Diff:-3
>> After  T0:0x5ed817 T1:0x5ed824 Diff:-13
>> Before  T0:0x62a7e5 T1:0x62a7f3 Diff:-14
>> After  T0:0x62adff T1:0x62ae17 Diff:-24
>> Before  T0:0x66cbfb T1:0x66cc14 Diff:-25
>> After  T0:0x66d1f6 T1:0x66d219 Diff:-35
>> Before  T0:0x6aeab0 T1:0x6aead4 Diff:-36
>> After  T0:0x6af0ec T1:0x6af11a Diff:-46
>> Before  T0:0x6f09ef T1:0x6f0a1e Diff:-47
>> After  T0:0x6f1018 T1:0x6f1051 Diff:-57
>> Before  T0:0x732821 T1:0x73285b Diff:-58
>> After  T0:0x732e1a T1:0x732e5e Diff:-68
>> ---------------
>>
>> This shows that TIM34_0 misses 11 ticks every time a new event is setup
>> (10 ticks from my test loop + the original code 1).
>>
>> If someone from TI can verify that the problem exists in all Davinci
>> versions, a workaround should be pretty straightforward, assuming this
>> is the only symptom of the bug.
> 
> I was not able to spend too much time on this today, but I did try your
> patch on my DM644x EVM and have observations similar to what you
> describe above. Further, I see that reading TIM12 instead of writing it
> does not cause the same drift on TIM34. I still need to try on a
> different DaVinci device.

Like I wrote in patch, my DM6443 based card behaves the same.

> One thing to try would be to temporarily stop both TIM12_0 and TIM34_0
> using ENAMODE bits in TCR before resetting TIM12_0. There is a cryptic
> note about writes to timer register being disallowed when timer is
> running in section 2.4.2 of http://www.ti.com/lit/ug/sprue26/sprue26.pdf

It says that timer registers are protected by hardware when the timer is active.
I guess writes are ignored if timer is active.

Regards,
/Thomas
Sekhar Nori Dec. 14, 2012, 1:20 p.m. UTC | #3
On 12/13/2012 9:22 PM, Thomas Lange wrote:
> On 2012-12-13 14:28, Sekhar Nori wrote:
>> On 12/13/2012 2:17 AM, Thomas Lange wrote:
>>> The time drift problem I have been chasing for a while, see
>>> http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2012-December/025821.html
>>> , seems to be due to an undocumented silicon bug.
>>>
>>> The attached patch to master ( c22cf7755db6500df037cecdd6b290394d82392e
>>>   Origin: git://gitorious.org/linux-davinci/linux-davinci.git )
>>> exercises the problem. Example console output from my EVM6446 card:
>>>
>>> ----------------
>>> Before  T0:0x5ed55a T1:0x5ed55d Diff:-3
>>> After  T0:0x5ed817 T1:0x5ed824 Diff:-13
>>> Before  T0:0x62a7e5 T1:0x62a7f3 Diff:-14
>>> After  T0:0x62adff T1:0x62ae17 Diff:-24
>>> Before  T0:0x66cbfb T1:0x66cc14 Diff:-25
>>> After  T0:0x66d1f6 T1:0x66d219 Diff:-35
>>> Before  T0:0x6aeab0 T1:0x6aead4 Diff:-36
>>> After  T0:0x6af0ec T1:0x6af11a Diff:-46
>>> Before  T0:0x6f09ef T1:0x6f0a1e Diff:-47
>>> After  T0:0x6f1018 T1:0x6f1051 Diff:-57
>>> Before  T0:0x732821 T1:0x73285b Diff:-58
>>> After  T0:0x732e1a T1:0x732e5e Diff:-68
>>> ---------------
>>>
>>> This shows that TIM34_0 misses 11 ticks every time a new event is setup
>>> (10 ticks from my test loop + the original code 1).
>>>
>>> If someone from TI can verify that the problem exists in all Davinci
>>> versions, a workaround should be pretty straightforward, assuming this
>>> is the only symptom of the bug.
>>
>> I was not able to spend too much time on this today, but I did try your
>> patch on my DM644x EVM and have observations similar to what you
>> describe above. Further, I see that reading TIM12 instead of writing it
>> does not cause the same drift on TIM34. I still need to try on a
>> different DaVinci device.
> 
> Like I wrote in patch, my DM6443 based card behaves the same.

I verified that similar behavior exists on DaVinci DA850.

> 
>> One thing to try would be to temporarily stop both TIM12_0 and TIM34_0
>> using ENAMODE bits in TCR before resetting TIM12_0. There is a cryptic
>> note about writes to timer register being disallowed when timer is
>> running in section 2.4.2 of http://www.ti.com/lit/ug/sprue26/sprue26.pdf
> 
> It says that timer registers are protected by hardware when the timer is active.
> I guess writes are ignored if timer is active.

I will check internally with the hardware team to see if this is a known
issue.

Thanks,
Sekhar
diff mbox

Patch

diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 9847938..95be656 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -117,6 +117,61 @@  static char *id_to_name[] = {
 	[T1_TOP]	= "timer1_1",
 };
 
+/*******************************************************************
+  Test code by thomas@corelatus.se 121212
+  Exercises a timer problem with Davinci, likely a silicon bug.
+  For each write to TIM12, the TIM34 counter misses a tick.
+  With current kernel, this causes time to drift 37 ns every time
+  a new event is set. This can accumulate to 1000 ppms
+  (1 ms per second) if lots of context switches.
+
+  Verified to exist in:
+    DM6443 rev 2.1
+    DM6446 rev 1.3
+*********************************************************************/
+
+static inline void show_timer_diff(const char *str){
+	u32 tim34_0, tim34_1;
+
+	tim34_1 = __raw_readl(IO_ADDRESS(DAVINCI_TIMER1_BASE + TIM34));
+	tim34_0 = __raw_readl(IO_ADDRESS(DAVINCI_TIMER0_BASE + TIM34));
+
+	printk("%s  T0:0x%x T1:0x%x Diff:%d\n",
+	       str,
+	       tim34_0,
+	       tim34_1,
+	       tim34_0 - tim34_1);
+}
+
+/* When setting up Timer 0-34, setup Timer 1-34 with the same settings.
+   This way, they should always have about the same counter value. */
+static void mirror(struct timer_s *t){
+	/* Timer 1 is +0x400 */
+	volatile void *base = t->base + 0x400;
+	u32 tcr;
+
+	tcr = __raw_readl(base + TCR);
+
+	/* disable timer */
+	tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
+	__raw_writel(tcr, base + TCR);
+
+	/* reset counter to zero, set new period */
+	__raw_writel(0, base + t->tim_off);
+	__raw_writel(t->period, base + t->prd_off);
+
+	/* Set enable mode */
+	if (t->opts & TIMER_OPTS_ONESHOT)
+		tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
+	else if (t->opts & TIMER_OPTS_PERIODIC)
+		tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
+
+	__raw_writel(tcr, base + TCR);
+}
+
+#define CHECK_LAPS 20
+static u32 chk = ~0;
+
 static int timer32_config(struct timer_s *t)
 {
 	u32 tcr;
@@ -142,6 +197,19 @@  static int timer32_config(struct timer_s *t)
 		tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
 		__raw_writel(tcr, t->base + TCR);
 
+		if( chk < CHECK_LAPS && t->id == 0 ){
+			int i;
+			show_timer_diff("Before");
+			/* TIM34_0 seems to miss 1 tick every time we write
+			   to TIM12_0!
+			   So, this loop makes us miss 10 ticks: */
+			for(i=0;i<10;i++){
+				__raw_writel(0, t->base + t->tim_off);
+			}
+			show_timer_diff("After");
+			chk++;
+		}
+
 		/* reset counter to zero, set new period */
 		__raw_writel(0, t->base + t->tim_off);
 		__raw_writel(t->period, t->base + t->prd_off);
@@ -152,6 +220,15 @@  static int timer32_config(struct timer_s *t)
 		else if (t->opts & TIMER_OPTS_PERIODIC)
 			tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
 
+		if(t->id == 1){
+			/* Timer 0-34 setup
+			   Setup 1-34 as a mirror to 0-34 */
+			mirror(t);
+
+			/* Start checking TIM counters */
+			chk = 0;
+		}
+
 		__raw_writel(tcr, t->base + TCR);
 	}
 	return 0;
@@ -381,6 +458,10 @@  static void __init davinci_timer_init(void)
 	BUG_ON(IS_ERR(timer_clk));
 	clk_prepare_enable(timer_clk);
 
+	timer_clk = clk_get(NULL, "timer1");
+	BUG_ON(IS_ERR(timer_clk));
+	clk_enable(timer_clk);
+
 	/* init timer hw */
 	timer_init();