1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * 64-bit Periodic Interval Timer driver
4  *
5  * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6  *
7  * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
8  */
9 
10 #include <clk.h>
11 #include <dm.h>
12 #include <timer.h>
13 #include <asm/io.h>
14 
15 #define MCHP_PIT64B_CR			0x00	/* Control Register */
16 #define		MCHP_PIT64B_CR_START	BIT(0)
17 #define		MCHP_PIT64B_CR_SWRST	BIT(8)
18 #define MCHP_PIT64B_MR			0x04	/* Mode Register */
19 #define		MCHP_PIT64B_MR_CONT	BIT(0)
20 #define MCHP_PIT64B_LSB_PR		0x08	/* LSB Period Register */
21 #define MCHP_PIT64B_MSB_PR		0x0C	/* MSB Period Register */
22 #define MCHP_PIT64B_TLSBR		0x20	/* Timer LSB Register */
23 #define MCHP_PIT64B_TMSBR		0x24	/* Timer MSB Register */
24 
25 struct mchp_pit64b_priv {
26 	void __iomem *base;
27 };
28 
mchp_pit64b_get_count(struct udevice * dev)29 static u64 mchp_pit64b_get_count(struct udevice *dev)
30 {
31 	struct mchp_pit64b_priv *priv = dev_get_priv(dev);
32 
33 	u32 lsb = readl(priv->base + MCHP_PIT64B_TLSBR);
34 	u32 msb = readl(priv->base + MCHP_PIT64B_TMSBR);
35 
36 	return ((u64)msb << 32) | lsb;
37 }
38 
mchp_pit64b_probe(struct udevice * dev)39 static int mchp_pit64b_probe(struct udevice *dev)
40 {
41 	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
42 	struct mchp_pit64b_priv *priv = dev_get_priv(dev);
43 	struct clk clk;
44 	ulong rate;
45 	int ret;
46 
47 	priv->base = dev_read_addr_ptr(dev);
48 	if (IS_ERR(priv->base))
49 		return PTR_ERR(priv->base);
50 
51 	ret = clk_get_by_index(dev, 0, &clk);
52 	if (ret)
53 		return ret;
54 
55 	ret = clk_enable(&clk);
56 	if (ret)
57 		return ret;
58 
59 	rate = clk_get_rate(&clk);
60 	if (!rate) {
61 		clk_disable(&clk);
62 		return -ENOTSUPP;
63 	}
64 
65 	/* Reset the timer in case it was used by previous bootloaders. */
66 	writel(MCHP_PIT64B_CR_SWRST, priv->base + MCHP_PIT64B_CR);
67 
68 	/*
69 	 * Use highest prescaller (for a peripheral clock running at 200MHz
70 	 * this will lead to the timer running at 12.5MHz) and continuous mode.
71 	 */
72 	writel((15 << 8) | MCHP_PIT64B_MR_CONT, priv->base + MCHP_PIT64B_MR);
73 	uc_priv->clock_rate = rate / 16;
74 
75 	/*
76 	 * Simulate free running counter by setting max values to period
77 	 * registers.
78 	 */
79 	writel(~0UL, priv->base + MCHP_PIT64B_MSB_PR);
80 	writel(~0UL, priv->base + MCHP_PIT64B_LSB_PR);
81 
82 	/* Start the timer. */
83 	writel(MCHP_PIT64B_CR_START, priv->base + MCHP_PIT64B_CR);
84 
85 	return 0;
86 }
87 
88 static const struct timer_ops mchp_pit64b_ops = {
89 	.get_count = mchp_pit64b_get_count,
90 };
91 
92 static const struct udevice_id mchp_pit64b_ids[] = {
93 	{ .compatible = "microchip,sam9x60-pit64b", },
94 	{ .compatible = "microchip,sama7g5-pit64b", },
95 	{ }
96 };
97 
98 U_BOOT_DRIVER(mchp_pit64b) = {
99 	.name	= "mchp-pit64b",
100 	.id	= UCLASS_TIMER,
101 	.of_match = mchp_pit64b_ids,
102 	.priv_auto	= sizeof(struct mchp_pit64b_priv),
103 	.probe	= mchp_pit64b_probe,
104 	.ops	= &mchp_pit64b_ops,
105 	.flags	= DM_FLAG_PRE_RELOC,
106 };
107