blob: 6ac7d7f1d0ee1caab45303b762afbdad7e9450a4 [file] [log] [blame]
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 StarFive, Inc. All rights reserved.
Kuan Lim Lee55a35872023-12-11 10:22:10 +08004 * Author: Kuan Lim Lee <kuanlim.lee@starfivetech.com>
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +08005 */
6
7#include <common.h>
8#include <clk.h>
9#include <dm.h>
10#include <time.h>
11#include <timer.h>
12#include <asm/io.h>
13#include <dm/device-internal.h>
14#include <linux/err.h>
15
16#define STF_TIMER_INT_STATUS 0x00
17#define STF_TIMER_CTL 0x04
18#define STF_TIMER_LOAD 0x08
19#define STF_TIMER_ENABLE 0x10
20#define STF_TIMER_RELOAD 0x14
21#define STF_TIMER_VALUE 0x18
22#define STF_TIMER_INT_CLR 0x20
23#define STF_TIMER_INT_MASK 0x24
24
25struct starfive_timer_priv {
26 void __iomem *base;
27 u32 timer_size;
28};
29
30static u64 notrace starfive_get_count(struct udevice *dev)
31{
32 struct starfive_timer_priv *priv = dev_get_priv(dev);
33
34 /* Read decrement timer value and convert to increment value */
35 return priv->timer_size - readl(priv->base + STF_TIMER_VALUE);
36}
37
38static const struct timer_ops starfive_ops = {
39 .get_count = starfive_get_count,
40};
41
42static int starfive_probe(struct udevice *dev)
43{
44 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
45 struct starfive_timer_priv *priv = dev_get_priv(dev);
46 int timer_channel;
47 struct clk clk;
48 int ret;
49
50 priv->base = dev_read_addr_ptr(dev);
Kuan Lim Lee55a35872023-12-11 10:22:10 +080051 if (!priv->base)
52 return -EINVAL;
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +080053
54 timer_channel = dev_read_u32_default(dev, "channel", 0);
55 priv->base = priv->base + (0x40 * timer_channel);
56
57 /* Get clock rate from channel selectecd*/
58 ret = clk_get_by_index(dev, timer_channel, &clk);
59 if (ret)
60 return ret;
61
62 ret = clk_enable(&clk);
63 if (ret)
64 return ret;
65 uc_priv->clock_rate = clk_get_rate(&clk);
66
Kuan Lim Lee55a35872023-12-11 10:22:10 +080067 /*
68 * Initiate timer, channel 0
69 * Unmask Interrupt Mask
70 */
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +080071 writel(0, priv->base + STF_TIMER_INT_MASK);
72 /* Single run mode Setting */
73 if (dev_read_bool(dev, "single-run"))
74 writel(1, priv->base + STF_TIMER_CTL);
75 /* Set Reload value */
Kuan Lim Lee55a35872023-12-11 10:22:10 +080076 priv->timer_size = dev_read_u32_default(dev, "timer-size", -1U);
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +080077 writel(priv->timer_size, priv->base + STF_TIMER_LOAD);
78 /* Enable to start timer */
79 writel(1, priv->base + STF_TIMER_ENABLE);
80
81 return 0;
82}
83
84static const struct udevice_id starfive_ids[] = {
85 { .compatible = "starfive,jh8100-timers" },
86 { }
87};
88
89U_BOOT_DRIVER(jh8100_starfive_timer) = {
Kuan Lim Lee55a35872023-12-11 10:22:10 +080090 .name = "starfive_timer",
Kuan Lim Leeeb66fc32023-09-19 15:30:36 +080091 .id = UCLASS_TIMER,
92 .of_match = starfive_ids,
93 .probe = starfive_probe,
94 .ops = &starfive_ops,
95 .priv_auto = sizeof(struct starfive_timer_priv),
96};