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