]>
Commit | Line | Data |
---|---|---|
1168d2dd PT |
1 | /* |
2 | * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <dm.h> | |
9 | #include <mapmem.h> | |
10 | #include <asm/arch/timer.h> | |
11 | #include <dt-structs.h> | |
12 | #include <timer.h> | |
13 | #include <asm/io.h> | |
14 | ||
15 | DECLARE_GLOBAL_DATA_PTR; | |
16 | ||
17 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
18 | struct rockchip_timer_plat { | |
19 | struct dtd_rockchip_rk3368_timer dtd; | |
20 | }; | |
21 | #endif | |
22 | ||
23 | /* Driver private data. Contains timer id. Could be either 0 or 1. */ | |
24 | struct rockchip_timer_priv { | |
25 | struct rk_timer *timer; | |
26 | }; | |
27 | ||
28 | static int rockchip_timer_get_count(struct udevice *dev, u64 *count) | |
29 | { | |
30 | struct rockchip_timer_priv *priv = dev_get_priv(dev); | |
31 | uint64_t timebase_h, timebase_l; | |
32 | uint64_t cntr; | |
33 | ||
34 | timebase_l = readl(&priv->timer->timer_curr_value0); | |
35 | timebase_h = readl(&priv->timer->timer_curr_value1); | |
36 | ||
37 | /* timers are down-counting */ | |
38 | cntr = timebase_h << 32 | timebase_l; | |
39 | *count = ~0ull - cntr; | |
40 | return 0; | |
41 | } | |
42 | ||
43 | static int rockchip_clk_ofdata_to_platdata(struct udevice *dev) | |
44 | { | |
45 | #if !CONFIG_IS_ENABLED(OF_PLATDATA) | |
46 | struct rockchip_timer_priv *priv = dev_get_priv(dev); | |
47 | ||
48 | priv->timer = (struct rk_timer *)devfdt_get_addr(dev); | |
49 | #endif | |
50 | ||
51 | return 0; | |
52 | } | |
53 | ||
54 | static int rockchip_timer_start(struct udevice *dev) | |
55 | { | |
56 | struct rockchip_timer_priv *priv = dev_get_priv(dev); | |
57 | const uint64_t reload_val = ~0uLL; | |
58 | const uint32_t reload_val_l = reload_val & 0xffffffff; | |
59 | const uint32_t reload_val_h = reload_val >> 32; | |
60 | ||
61 | /* disable timer and reset all control */ | |
62 | writel(0, &priv->timer->timer_ctrl_reg); | |
63 | /* write reload value */ | |
64 | writel(reload_val_l, &priv->timer->timer_load_count0); | |
65 | writel(reload_val_h, &priv->timer->timer_load_count1); | |
66 | /* enable timer */ | |
67 | writel(1, &priv->timer->timer_ctrl_reg); | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static int rockchip_timer_probe(struct udevice *dev) | |
73 | { | |
74 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
75 | struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); | |
76 | struct rockchip_timer_priv *priv = dev_get_priv(dev); | |
77 | struct rockchip_timer_plat *plat = dev_get_platdata(dev); | |
78 | ||
79 | priv->timer = map_sysmem(plat->dtd.reg[1], plat->dtd.reg[3]); | |
80 | uc_priv->clock_rate = plat->dtd.clock_frequency; | |
81 | #endif | |
82 | ||
83 | return rockchip_timer_start(dev); | |
84 | } | |
85 | ||
86 | static const struct timer_ops rockchip_timer_ops = { | |
87 | .get_count = rockchip_timer_get_count, | |
88 | }; | |
89 | ||
90 | static const struct udevice_id rockchip_timer_ids[] = { | |
91 | { .compatible = "rockchip,rk3368-timer" }, | |
92 | {} | |
93 | }; | |
94 | ||
95 | U_BOOT_DRIVER(arc_timer) = { | |
96 | .name = "rockchip_rk3368_timer", | |
97 | .id = UCLASS_TIMER, | |
98 | .of_match = rockchip_timer_ids, | |
99 | .probe = rockchip_timer_probe, | |
100 | .ops = &rockchip_timer_ops, | |
101 | .flags = DM_FLAG_PRE_RELOC, | |
102 | .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv), | |
103 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
104 | .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat), | |
105 | #endif | |
106 | .ofdata_to_platdata = rockchip_clk_ofdata_to_platdata, | |
107 | }; |