SPRZ457I January 2021 – December 2024 AM2431 , AM2432 , AM2434 , AM6411 , AM6412 , AM6421 , AM6422 , AM6441 , AM6442
ICSS: Reading the 64-bit IEP timer does not have a lock MSW logic when LSW is read
IEPx 64-bit timestamp can be incorrect when lower 32-bit data is 0xFFFFFFFC or above (at 250MHz). In this case the upper 32-bit value is updated but lower value is the old number. The issue is seen when IEP counter (IEP_COUNT_REG1 : IEP_COUNT_REG0) is read back-to-back from ICSS PRU cores.
Example 1:
1st read : 0x000000D0(Upper):0xFFFFFFFC(lower)
2nd read : 0x000000D0(Upper):0x00000028(lower)
Example 2:
1st read : 0x000000D7(Upper):0xFFFFFFFC(lower)
2nd read : 0x000000D7(Upper):0x0000002C(lower)
Example 3:
1st read : 0x000000D6(Upper):0xFFFFFFF0(lower)
2nd read : 0x000000D7(Upper):0xFFFFFFFC((lower)
As shown above, this leads to timer increment behavior that is non-monotonic or timer differences to be unusually large as in Example 3 . This is due to 1 cycle race condition when loading 64-bit value from IEPx counter.
Note: these workarounds exist in SDK9.2 and later
Workaround in C for PRU:
uint64_t timestamp = (uint64_t) (0x2E0010);
/* Workaround starts here */
if ((timestamp & 0xFFFFFFFF) >= 0xFFFFFFFC)
{ timestamp = *(uint64_t*) (0x2E0010); }
/* Workaround ends here */
Workaround in assembly for PRU:
ldi32 r4, 0xFFFFFFFC ; 0-4 for 250MHz clock
;load 64-bit timestamp to r2:r3
lbco &r2, c26, 0x10, 8
qbgt skip_iep_read_errata. r2, r4
;re-read IEP if IEP_COUNTER_LOW >= 0xFFFF_FFFC
lbco &r2, c26, 0x10, 8
skip_iep_read_errata:
Workaround in C for R5F, A53:
uint64_t getIepTimeStamp64 (void)
{
uint64_t u64Timestamp1 = (volatile uint64_t)(0x300AE010);
uint64_t u64Timestamp2 = (volatile uint64_t)(0x300AE010);
if (u64Timestamp2 > u64Timestamp1)
{
#ifdef __DEBUG
if (((u64Timestamp2 >> 32)-(u64Timestamp1 >> 32)) == 1)
{
/* HW errata fixed due to picking u64Timestamp1*/
if ((u64Timestamp2 & 0xFFFFFFFF) >= (u64Timestamp1 & 0xFFFFFFFF))
{ DebugP_log ("Errata fixed (1): %llx : %llx\r\n",
u64Timestamp1, u64Timestamp2); }
}
#endif
return u64Timestamp1;
}
else
{
#ifdef __DEBUG
if ((u64Timestamp2 & 0xFFFFFFFF) < (u64Timestamp1 & 0xFFFFFFFF))
{ /* Adjust the IEP MSW in the case running into HW errata */
DebugP_log ("Errata fixed (2): %llx : %llx\r\n", u64Timestamp1,
u64Timestamp2); }
#endif
/* HW errata fixed due to picking u64Timestamp2*/
return u64Timestamp2;
}
}