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