libplatsupport,imx: Account for 32bit overflow

When constructing the 64bit clock value, handle the situation where the
low 32-bits could overflow between reading it and testing the hardware
overflow bit.

Signed-off-by: Kent McLeod <kent@kry10.com>
diff --git a/libplatsupport/src/mach/imx/gpt.c b/libplatsupport/src/mach/imx/gpt.c
index dceca7d..e64f04b 100644
--- a/libplatsupport/src/mach/imx/gpt.c
+++ b/libplatsupport/src/mach/imx/gpt.c
@@ -217,9 +217,30 @@
 
 uint64_t gpt_get_time(gpt_t *gpt)
 {
+    // Rollover of 32-bit counter can happen while we are reading it,
+    // We need to read in the following order (volatile modifier on gpt_map should ensure this):
+    // - GPT_SR[ROV]
+    // - GPT_CNT
+    // - GPT_SR[ROV]
+    // If GPT_SR[ROV] bit is unchanged, then the GPT_CNT read is valid and can be used.
+    // If GPT_SR[ROV] bit has changed, then the rollover happened sometime between the first
+    // read and the third read.  In this case GPT_CNT would have had a value of 0 at some point
+    // during our reads and so use 0.
+    uint32_t rollover_st = gpt->gpt_map->gptsr & BIT(ROV);
     uint32_t low_bits = gpt->gpt_map->gptcnt;
+    uint32_t rollover_st2 = gpt->gpt_map->gptsr & BIT(ROV);
+    if (rollover_st != rollover_st2) {
+        low_bits = 0;
+    }
+
+    // gpt->high_bits is the number of times the timer has overflowed and is managed by this driver.
+    // If GPT_SR[ROV] is set then gpt_handle_irq hasn't had a chance to run yet and gpt->high_bits
+    // is still recording the old number of overflows. We increment our own local copy and leave
+    // the driver copy to be updated by gpt_handle_irq.
+    // This driver requires that the IRQ handler function won't be called while other driver functions
+    // are executing.
     uint32_t high_bits = gpt->high_bits;
-    if (gpt->gpt_map->gptsr) {
+    if (rollover_st2) {
         /* irq has come in */
         high_bits++;
     }