]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
347cb2ed | 2 | /* |
fb48bc44 | 3 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved |
0f8106f8 | 4 | * Author(s): Patrice Chotard, <patrice.chotard@foss.st.com> for STMicroelectronics. |
35751c7f WZ |
5 | * |
6 | * ARM Cortext A9 global timer driver | |
347cb2ed PC |
7 | */ |
8 | ||
d678a59d | 9 | #include <common.h> |
347cb2ed | 10 | #include <dm.h> |
5b5699cd | 11 | #include <clk.h> |
347cb2ed | 12 | #include <timer.h> |
5b5699cd | 13 | #include <linux/err.h> |
347cb2ed PC |
14 | |
15 | #include <asm/io.h> | |
16 | #include <asm/arch-armv7/globaltimer.h> | |
17 | ||
35751c7f | 18 | struct arm_global_timer_priv { |
347cb2ed PC |
19 | struct globaltimer *global_timer; |
20 | }; | |
21 | ||
35751c7f | 22 | static u64 arm_global_timer_get_count(struct udevice *dev) |
347cb2ed | 23 | { |
35751c7f | 24 | struct arm_global_timer_priv *priv = dev_get_priv(dev); |
347cb2ed PC |
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; | |
8af7bb91 | 39 | return (u64)((timer << 32) | low); |
347cb2ed PC |
40 | } |
41 | ||
35751c7f | 42 | static int arm_global_timer_probe(struct udevice *dev) |
347cb2ed PC |
43 | { |
44 | struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
35751c7f | 45 | struct arm_global_timer_priv *priv = dev_get_priv(dev); |
5b5699cd NH |
46 | struct clk clk; |
47 | int err; | |
48 | ulong ret; | |
347cb2ed PC |
49 | |
50 | /* get arm global timer base address */ | |
123123d6 NH |
51 | priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev); |
52 | if (!priv->global_timer) | |
53 | return -ENOENT; | |
347cb2ed | 54 | |
5b5699cd NH |
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 { | |
65cc0e2a | 62 | uc_priv->clock_rate = CFG_SYS_HZ_CLOCK; |
5b5699cd NH |
63 | } |
64 | ||
347cb2ed PC |
65 | /* init timer */ |
66 | writel(0x01, &priv->global_timer->ctl); | |
67 | ||
68 | return 0; | |
69 | } | |
70 | ||
35751c7f WZ |
71 | static const struct timer_ops arm_global_timer_ops = { |
72 | .get_count = arm_global_timer_get_count, | |
347cb2ed PC |
73 | }; |
74 | ||
35751c7f | 75 | static const struct udevice_id arm_global_timer_ids[] = { |
347cb2ed PC |
76 | { .compatible = "arm,cortex-a9-global-timer" }, |
77 | {} | |
78 | }; | |
79 | ||
35751c7f WZ |
80 | U_BOOT_DRIVER(arm_global_timer) = { |
81 | .name = "arm_global_timer", | |
347cb2ed | 82 | .id = UCLASS_TIMER, |
35751c7f WZ |
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, | |
347cb2ed | 87 | }; |