xref: /openbmc/u-boot/drivers/timer/dw-apb-timer.c (revision 1fdeacd3)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Designware APB Timer driver
4  *
5  * Copyright (C) 2018 Marek Vasut <marex@denx.de>
6  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <clk.h>
11 #include <timer.h>
12 
13 #include <asm/io.h>
14 #include <asm/arch/timer.h>
15 
16 #define DW_APB_LOAD_VAL		0x0
17 #define DW_APB_CURR_VAL		0x4
18 #define DW_APB_CTRL		0x8
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 struct dw_apb_timer_priv {
23 	fdt_addr_t	regs;
24 };
25 
26 static int dw_apb_timer_get_count(struct udevice *dev, u64 *count)
27 {
28 	struct dw_apb_timer_priv *priv = dev_get_priv(dev);
29 
30 	/*
31 	 * The DW APB counter counts down, but this function
32 	 * requires the count to be incrementing. Invert the
33 	 * result.
34 	 */
35 	*count = ~readl(priv->regs + DW_APB_CURR_VAL);
36 
37 	return 0;
38 }
39 
40 static int dw_apb_timer_probe(struct udevice *dev)
41 {
42 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
43 	struct dw_apb_timer_priv *priv = dev_get_priv(dev);
44 	struct clk clk;
45 	int ret;
46 
47 	ret = clk_get_by_index(dev, 0, &clk);
48 	if (ret)
49 		return ret;
50 
51 	uc_priv->clock_rate = clk_get_rate(&clk);
52 
53 	clk_free(&clk);
54 
55 	/* init timer */
56 	writel(0xffffffff, priv->regs + DW_APB_LOAD_VAL);
57 	writel(0xffffffff, priv->regs + DW_APB_CURR_VAL);
58 	setbits_le32(priv->regs + DW_APB_CTRL, 0x3);
59 
60 	return 0;
61 }
62 
63 static int dw_apb_timer_ofdata_to_platdata(struct udevice *dev)
64 {
65 	struct dw_apb_timer_priv *priv = dev_get_priv(dev);
66 
67 	priv->regs = dev_read_addr(dev);
68 
69 	return 0;
70 }
71 
72 static const struct timer_ops dw_apb_timer_ops = {
73 	.get_count	= dw_apb_timer_get_count,
74 };
75 
76 static const struct udevice_id dw_apb_timer_ids[] = {
77 	{ .compatible = "snps,dw-apb-timer" },
78 	{}
79 };
80 
81 U_BOOT_DRIVER(dw_apb_timer) = {
82 	.name		= "dw_apb_timer",
83 	.id		= UCLASS_TIMER,
84 	.ops		= &dw_apb_timer_ops,
85 	.probe		= dw_apb_timer_probe,
86 	.flags		= DM_FLAG_PRE_RELOC,
87 	.of_match	= dw_apb_timer_ids,
88 	.ofdata_to_platdata = dw_apb_timer_ofdata_to_platdata,
89 	.priv_auto_alloc_size = sizeof(struct dw_apb_timer_priv),
90 };
91