From 74aa7770f6ec4184faff83fce3d2e843e65cf347 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Mon, 14 Jul 2014 16:26:11 -0700 Subject: 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 Original-Reviewed-on: https://chromium-review.googlesource.com/201574 Original-Reviewed-by: Vadim Bendebury Original-Commit-Queue: Vadim Bendebury Original-Tested-by: Vadim Bendebury (cherry picked from commit ddf11eee5ec2d86a62095e932dbec9313b8fb9e1) Signed-off-by: Marc Jones Change-Id: Id73e805801fd8d135b607df9f4f8caf567ec5b83 Reviewed-on: http://review.coreboot.org/8596 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/soc/qualcomm/ipq806x/timer.c | 125 ++++++++++++++------------------------- 1 file changed, 43 insertions(+), 82 deletions(-) (limited to 'src') diff --git a/src/soc/qualcomm/ipq806x/timer.c b/src/soc/qualcomm/ipq806x/timer.c index 3cb9531d33..55386e949b 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 #include -#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 -- cgit v1.2.3