1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
4  * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics.
5  *
6  * ARM Cortext A9 global timer driver
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <clk.h>
12 #include <timer.h>
13 #include <linux/err.h>
14 
15 #include <asm/io.h>
16 #include <asm/arch-armv7/globaltimer.h>
17 
18 struct arm_global_timer_priv {
19 	struct globaltimer *global_timer;
20 };
21 
arm_global_timer_get_count(struct udevice * dev)22 static u64 arm_global_timer_get_count(struct udevice *dev)
23 {
24 	struct arm_global_timer_priv *priv = dev_get_priv(dev);
25 	struct globaltimer *global_timer = priv->global_timer;
26 	u32 low, high;
27 	u64 timer;
28 	u32 old = readl(&global_timer->cnt_h);
29 
30 	while (1) {
31 		low = readl(&global_timer->cnt_l);
32 		high = readl(&global_timer->cnt_h);
33 		if (old == high)
34 			break;
35 		else
36 			old = high;
37 	}
38 	timer = high;
39 	return (u64)((timer << 32) | low);
40 }
41 
arm_global_timer_probe(struct udevice * dev)42 static int arm_global_timer_probe(struct udevice *dev)
43 {
44 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
45 	struct arm_global_timer_priv *priv = dev_get_priv(dev);
46 	struct clk clk;
47 	int err;
48 	ulong ret;
49 
50 	/* get arm global timer base address */
51 	priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev);
52 	if (!priv->global_timer)
53 		return -ENOENT;
54 
55 	err = clk_get_by_index(dev, 0, &clk);
56 	if (!err) {
57 		ret = clk_get_rate(&clk);
58 		if (IS_ERR_VALUE(ret))
59 			return ret;
60 		uc_priv->clock_rate = ret;
61 	} else {
62 		uc_priv->clock_rate = CFG_SYS_HZ_CLOCK;
63 	}
64 
65 	/* init timer */
66 	writel(0x01, &priv->global_timer->ctl);
67 
68 	return 0;
69 }
70 
71 static const struct timer_ops arm_global_timer_ops = {
72 	.get_count = arm_global_timer_get_count,
73 };
74 
75 static const struct udevice_id arm_global_timer_ids[] = {
76 	{ .compatible = "arm,cortex-a9-global-timer" },
77 	{}
78 };
79 
80 U_BOOT_DRIVER(arm_global_timer) = {
81 	.name = "arm_global_timer",
82 	.id = UCLASS_TIMER,
83 	.of_match = arm_global_timer_ids,
84 	.priv_auto	= sizeof(struct arm_global_timer_priv),
85 	.probe = arm_global_timer_probe,
86 	.ops = &arm_global_timer_ops,
87 };
88