1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MediaTek timer driver
4  *
5  * Copyright (C) 2018 MediaTek Inc.
6  * Author: Ryder Lee <ryder.lee@mediatek.com>
7  */
8 
9 #include <clk.h>
10 #include <common.h>
11 #include <dm.h>
12 #include <timer.h>
13 #include <asm/io.h>
14 #include <linux/bitops.h>
15 
16 #define MTK_GPT4_OFFSET_V1	0x40
17 #define MTK_GPT4_OFFSET_V2	0x80
18 
19 #define MTK_GPT_CON		0x0
20 #define MTK_GPT_V1_CLK		0x4
21 #define MTK_GPT_CNT		0x8
22 
23 #define GPT_ENABLE		BIT(0)
24 #define GPT_CLEAR		BIT(1)
25 #define GPT_V1_FREERUN		GENMASK(5, 4)
26 #define GPT_V2_FREERUN		GENMASK(6, 5)
27 
28 enum mtk_gpt_ver {
29 	MTK_GPT_V1,
30 	MTK_GPT_V2
31 };
32 
33 struct mtk_timer_priv {
34 	void __iomem *base;
35 	unsigned int gpt4_offset;
36 };
37 
mtk_timer_get_count(struct udevice * dev)38 static u64 mtk_timer_get_count(struct udevice *dev)
39 {
40 	struct mtk_timer_priv *priv = dev_get_priv(dev);
41 	u32 val = readl(priv->base + priv->gpt4_offset + MTK_GPT_CNT);
42 
43 	return timer_conv_64(val);
44 }
45 
mtk_timer_probe(struct udevice * dev)46 static int mtk_timer_probe(struct udevice *dev)
47 {
48 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
49 	struct mtk_timer_priv *priv = dev_get_priv(dev);
50 	struct clk clk, parent;
51 	int ret, gpt_ver;
52 
53 	priv->base = dev_read_addr_ptr(dev);
54 	gpt_ver = dev_get_driver_data(dev);
55 
56 	if (!priv->base)
57 		return -ENOENT;
58 
59 	if (gpt_ver == MTK_GPT_V2) {
60 		priv->gpt4_offset = MTK_GPT4_OFFSET_V2;
61 
62 		writel(GPT_V2_FREERUN | GPT_CLEAR | GPT_ENABLE,
63 		       priv->base + priv->gpt4_offset + MTK_GPT_CON);
64 	} else {
65 		priv->gpt4_offset = MTK_GPT4_OFFSET_V1;
66 
67 		writel(GPT_V1_FREERUN | GPT_CLEAR | GPT_ENABLE,
68 		       priv->base + priv->gpt4_offset + MTK_GPT_CON);
69 		writel(0, priv->base + priv->gpt4_offset + MTK_GPT_V1_CLK);
70 	}
71 
72 	ret = clk_get_by_index(dev, 0, &clk);
73 	if (ret)
74 		return ret;
75 
76 	ret = clk_get_by_index(dev, 1, &parent);
77 	if (!ret) {
78 		ret = clk_set_parent(&clk, &parent);
79 		if (ret)
80 			return ret;
81 	}
82 
83 	uc_priv->clock_rate = clk_get_rate(&clk);
84 	if (!uc_priv->clock_rate)
85 		return -EINVAL;
86 
87 	return 0;
88 }
89 
90 static const struct timer_ops mtk_timer_ops = {
91 	.get_count = mtk_timer_get_count,
92 };
93 
94 static const struct udevice_id mtk_timer_ids[] = {
95 	{ .compatible = "mediatek,timer", .data = MTK_GPT_V1 },
96 	{ .compatible = "mediatek,mt6577-timer", .data = MTK_GPT_V1 },
97 	{ .compatible = "mediatek,mt7981-timer", .data = MTK_GPT_V2 },
98 	{ .compatible = "mediatek,mt7986-timer", .data = MTK_GPT_V2 },
99 	{ }
100 };
101 
102 U_BOOT_DRIVER(mtk_timer) = {
103 	.name = "mtk_timer",
104 	.id = UCLASS_TIMER,
105 	.of_match = mtk_timer_ids,
106 	.priv_auto	= sizeof(struct mtk_timer_priv),
107 	.probe = mtk_timer_probe,
108 	.ops = &mtk_timer_ops,
109 	.flags = DM_FLAG_PRE_RELOC,
110 };
111