aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorJisheng Zhang <jszhang@marvell.com>2015-11-04 21:32:06 -0500
committerDaniel Lezcano <daniel.lezcano@linaro.org>2015-12-15 03:42:00 -0500
commit9115df89d12c2cf6db080a7ee57cd076f8416e4a (patch)
treecfd86473d7034ace8133978e0f747d201b7125eb /drivers/clocksource
parent0901f18432db704b7622c969a09fba9846e4cfcd (diff)
clocksource/drivers/dw_apb_timer_of: Implement ARM delay timer
Implement an ARM delay timer to be used for udelay(). This allows us to skip the delay loop calibration at boot on Marvell BG2, BG2Q, BG2CD platforms. And after this patch, udelay() will be unaffected by CPU frequency changes. Note: Although in case there are several possible delay timers, we may not select the "best" delay timer. Take one Marvell Berlin platform for example: we have arch timer and dw-apb timer. The arch timer freq is 25MHZ while the dw-apb timer freq is 100MHZ, current selection would choose the dw-apb timer. But the dw apb timer is on the APB bus while arch timer sits in CPU, the cost of accessing the apb timer is higher than the arch timer. We could introduce "rating" concept to delay timer, but this approach "brings a lot of complexity and workarounds in the code for a small benefit" as pointed out by Daniel. Later, Arnd pointed out "However, we could argue that this actually doesn't matter at all, because the entire point of the ndelay()/ udelay()/mdelay() functions is to waste CPU cycles doing not much at all, so we can just as well waste them reading the timer register than spinning on the CPU reading the arch timer more often.", so we just simply register the dw apb base delay timer. Signed-off-by: Jisheng Zhang <jszhang@marvell.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index a19a3f619cc7..860843cef572 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -16,6 +16,7 @@
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */ 18 */
19#include <linux/delay.h>
19#include <linux/dw_apb_timer.h> 20#include <linux/dw_apb_timer.h>
20#include <linux/of.h> 21#include <linux/of.h>
21#include <linux/of_address.h> 22#include <linux/of_address.h>
@@ -130,6 +131,17 @@ static void __init init_sched_clock(void)
130 sched_clock_register(read_sched_clock, 32, sched_rate); 131 sched_clock_register(read_sched_clock, 32, sched_rate);
131} 132}
132 133
134#ifdef CONFIG_ARM
135static unsigned long dw_apb_delay_timer_read(void)
136{
137 return ~readl_relaxed(sched_io_base);
138}
139
140static struct delay_timer dw_apb_delay_timer = {
141 .read_current_timer = dw_apb_delay_timer_read,
142};
143#endif
144
133static int num_called; 145static int num_called;
134static void __init dw_apb_timer_init(struct device_node *timer) 146static void __init dw_apb_timer_init(struct device_node *timer)
135{ 147{
@@ -142,6 +154,10 @@ static void __init dw_apb_timer_init(struct device_node *timer)
142 pr_debug("%s: found clocksource timer\n", __func__); 154 pr_debug("%s: found clocksource timer\n", __func__);
143 add_clocksource(timer); 155 add_clocksource(timer);
144 init_sched_clock(); 156 init_sched_clock();
157#ifdef CONFIG_ARM
158 dw_apb_delay_timer.freq = sched_rate;
159 register_current_timer_delay(&dw_apb_delay_timer);
160#endif
145 break; 161 break;
146 default: 162 default:
147 break; 163 break;