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 
7 #include <common.h>
8 #include <dm.h>
9 #include <clk.h>
10 #include <timer.h>
11 #include <linux/err.h>
12 
13 #include <asm/io.h>
14 #include <asm/arch-armv7/globaltimer.h>
15 
16 struct sti_timer_priv {
17 	struct globaltimer *global_timer;
18 };
19 
sti_timer_get_count(struct udevice * dev)20 static u64 sti_timer_get_count(struct udevice *dev)
21 {
22 	struct sti_timer_priv *priv = dev_get_priv(dev);
23 	struct globaltimer *global_timer = priv->global_timer;
24 	u32 low, high;
25 	u64 timer;
26 	u32 old = readl(&global_timer->cnt_h);
27 
28 	while (1) {
29 		low = readl(&global_timer->cnt_l);
30 		high = readl(&global_timer->cnt_h);
31 		if (old == high)
32 			break;
33 		else
34 			old = high;
35 	}
36 	timer = high;
37 	return (u64)((timer << 32) | low);
38 }
39 
sti_timer_probe(struct udevice * dev)40 static int sti_timer_probe(struct udevice *dev)
41 {
42 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
43 	struct sti_timer_priv *priv = dev_get_priv(dev);
44 	struct clk clk;
45 	int err;
46 	ulong ret;
47 
48 	/* get arm global timer base address */
49 	priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev);
50 	if (!priv->global_timer)
51 		return -ENOENT;
52 
53 	err = clk_get_by_index(dev, 0, &clk);
54 	if (!err) {
55 		ret = clk_get_rate(&clk);
56 		if (IS_ERR_VALUE(ret))
57 			return ret;
58 		uc_priv->clock_rate = ret;
59 	} else {
60 		uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
61 	}
62 
63 	/* init timer */
64 	writel(0x01, &priv->global_timer->ctl);
65 
66 	return 0;
67 }
68 
69 static const struct timer_ops sti_timer_ops = {
70 	.get_count = sti_timer_get_count,
71 };
72 
73 static const struct udevice_id sti_timer_ids[] = {
74 	{ .compatible = "arm,cortex-a9-global-timer" },
75 	{}
76 };
77 
78 U_BOOT_DRIVER(sti_timer) = {
79 	.name = "sti_timer",
80 	.id = UCLASS_TIMER,
81 	.of_match = sti_timer_ids,
82 	.priv_auto	= sizeof(struct sti_timer_priv),
83 	.probe = sti_timer_probe,
84 	.ops = &sti_timer_ops,
85 };
86