Marc Jones (marc.jones@se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8596
-gerrit
commit 22d038e1b004d60d0600733b87475c899f159288 Author: Deepa Dinamani deepad@codeaurora.org Date: Mon Jul 14 16:26:11 2014 -0700
soc/ipq806x: Replace GPT with fine grained DGT timer.
Support 1MHz libpayload restriction on timer implementation by using DGT (debug) timer instead of GPT (general purpose) timer.
BUG=chrome-os-partner:28880 TEST=manual verified DGT timer functions in coreboot and depthcharge.
Original-Change-Id: Iab322d7e863e3959c027e9ce876223a64eb7e257 Original-Signed-off-by: Deepa Dinamani deepad@codeaurora.org Original-Reviewed-on: https://chromium-review.googlesource.com/201574 Original-Reviewed-by: Vadim Bendebury vbendeb@chromium.org Original-Commit-Queue: Vadim Bendebury vbendeb@chromium.org Original-Tested-by: Vadim Bendebury vbendeb@chromium.org (cherry picked from commit ddf11eee5ec2d86a62095e932dbec9313b8fb9e1) Signed-off-by: Marc Jones marc.jones@se-eng.com
Change-Id: Id73e805801fd8d135b607df9f4f8caf567ec5b83 --- src/soc/qualcomm/ipq806x/timer.c | 125 ++++++++++++++------------------------- 1 file changed, 43 insertions(+), 82 deletions(-)
diff --git a/src/soc/qualcomm/ipq806x/timer.c b/src/soc/qualcomm/ipq806x/timer.c index 3cb9531..ce11126 100644 --- a/src/soc/qualcomm/ipq806x/timer.c +++ b/src/soc/qualcomm/ipq806x/timer.c @@ -1,8 +1,5 @@ /* - * Copyright (c) 2012 - 2013 The Linux Foundation. All rights reserved. - * Source : APQ8064 LK boot - * - * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011 - 2014 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,103 +33,67 @@ #include <ipq_timer.h> #include <timer.h>
-#define GPT_FREQ_KHZ 32 -#define GPT_FREQ (GPT_FREQ_KHZ * 1000) /* 32 KHz */ +/* + * DGT runs at 25 MHz / 4, or 6.25 ticks per microsecond + */ +#define DGT_MHZ_NUM 25 +#define DGT_MHZ_DEN 4 + +#define TIMER_TICKS(us) ((DGT_MHZ_NUM*(us)+(DGT_MHZ_DEN-1))/DGT_MHZ_DEN) +#define TIMER_USECS(ticks) (DGT_MHZ_DEN*(ticks)/DGT_MHZ_NUM) + +/* Clock divider values for the timer. */ +#define DGT_CLK_DIV_1 0 +#define DGT_CLK_DIV_2 1 +#define DGT_CLK_DIV_3 2 +#define DGT_CLK_DIV_4 3
/** * init_timer - initialize timer */ void init_timer(void) { - writel(0, GPT_ENABLE); - writel(GPT_ENABLE_EN, GPT_ENABLE); + /* disable timer */ + writel_i(0, DGT_ENABLE); + + /* DGT uses TCXO source which is 25MHz. + * The timer should run at 1/4th the frequency of TCXO + * according to clock plan. + * Set clock divider to 4. + */ + writel_i(DGT_CLK_DIV_4, DGT_CLK_CTL); + + /* Enable timer */ + writel_i(0, DGT_CLEAR); + writel_i(DGT_ENABLE_EN, DGT_ENABLE); }
/** * udelay - generates micro second delay. * @param usec: delay duration in microseconds - * - * With 32KHz clock, minimum possible delay is 31.25 Micro seconds and - * its multiples. In Rumi GPT clock is 32 KHz */ void udelay(unsigned usec) { - unsigned val; - unsigned now, last; - unsigned runcount; + uint32_t now; + uint32_t last; + uint32_t ticks; + uint32_t curr_ticks = 0;
- usec = (usec + GPT_FREQ_KHZ - 1) / GPT_FREQ_KHZ; - last = readl(GPT_COUNT_VAL); - runcount = last; - val = usec + last; + /* Calculate number of ticks required. */ + ticks = TIMER_TICKS(usec);
- do { - now = readl(GPT_COUNT_VAL); - if (last > now) - runcount += ((GPT_FREQ - last) + now); - else - runcount += (now - last); - last = now; - } while (runcount < val); -} - -void timer_monotonic_get(struct mono_time *mt) -{ - mono_time_set_usecs(mt, (readl(GPT_COUNT_VAL) * 1000) / GPT_FREQ_KHZ); -} - -#if 0 - -/* - * TODO(vbendeb) clean it up later. - * Compile out the below code but leave it for now in case it will become - * necessary later in order to make the platform fully functional. - */ -static unsigned long timestamp; -static unsigned long lastinc; + /* Obtain the current timer value. */ + last = readl_i(DGT_COUNT_VAL);
-inline ulong gpt_to_sys_freq(unsigned int gpt) -{ - /* - * get_timer() expects the timer increments to be in terms - * of CONFIG_SYS_HZ. Convert GPT timer values to CONFIG_SYS_HZ - * units. - */ - return (((ulong)gpt) / (GPT_FREQ / CONFIG_SYS_HZ)); -} - -/** - * get_timer_masked - returns current ticks - * - * Returns the current timer ticks, since boot. - */ -ulong get_timer_masked(void) -{ - ulong now = gpt_to_sys_freq(readl(GPT_COUNT_VAL)); - - if (lastinc <= now) { /* normal mode (non roll) */ - /* normal mode */ - timestamp += now - lastinc; - /* move stamp forward with absolute diff ticks */ - } else { /* we have overflow of the count down timer */ - timestamp += now + (TIMER_LOAD_VAL - lastinc); + /* Loop until the right number of ticks. */ + while (curr_ticks < ticks) { + now = readl_i(DGT_COUNT_VAL); + curr_ticks += now - last; + last = now; } - - lastinc = now; - - return timestamp; }
-unsigned long long get_ticks(void) -{ - return readl(GPT_COUNT_VAL); -} - -/* - * Return the number of timer ticks per second. - */ -ulong get_tbclk(void) +void timer_monotonic_get(struct mono_time *mt) { - return GPT_FREQ; + mono_time_set_usecs(mt, TIMER_USECS(readl_i(DGT_COUNT_VAL))); } -#endif