blob: 11c098434a8fae3575c368cf8dd23f8d278512eb [file] [log] [blame]
Greg Malysa39e47192024-04-24 20:04:03 -04001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (C) Copyright 2022 - Analog Devices, Inc.
4 *
5 * Written and/or maintained by Timesys Corporation
6 *
7 * Converted to driver model by Nathan Barrett-Morrison
8 *
9 * Author: Greg Malysa <greg.malysa@timesys.com>
10 * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
11 *
12 * dm timer implementation for ADI ADSP-SC5xx SoCs
13 *
14 */
15
16#include <clk.h>
17#include <dm.h>
18#include <timer.h>
19#include <asm/io.h>
20#include <dm/device_compat.h>
21#include <linux/compiler_types.h>
22
23/*
24 * Timer Configuration Register Bits
25 */
26#define TIMER_OUT_DIS 0x0800
27#define TIMER_PULSE_HI 0x0080
28#define TIMER_MODE_PWM_CONT 0x000c
29
30#define __BFP(m) u16 m; u16 __pad_##m
31
32struct gptimer3 {
33 __BFP(config);
34 u32 counter;
35 u32 period;
36 u32 width;
37 u32 delay;
38};
39
40struct gptimer3_group_regs {
41 __BFP(run);
42 __BFP(enable);
43 __BFP(disable);
44 __BFP(stop_cfg);
45 __BFP(stop_cfg_set);
46 __BFP(stop_cfg_clr);
47 __BFP(data_imsk);
48 __BFP(stat_imsk);
49 __BFP(tr_msk);
50 __BFP(tr_ie);
51 __BFP(data_ilat);
52 __BFP(stat_ilat);
53 __BFP(err_status);
54 __BFP(bcast_per);
55 __BFP(bcast_wid);
56 __BFP(bcast_dly);
57};
58
59#define MAX_TIM_LOAD 0xFFFFFFFF
60
61struct adi_gptimer_priv {
62 struct gptimer3_group_regs __iomem *timer_group;
63 struct gptimer3 __iomem *timer_base;
64 u32 prev;
65 u64 upper;
66};
67
68static u64 adi_gptimer_get_count(struct udevice *udev)
69{
70 struct adi_gptimer_priv *priv = dev_get_priv(udev);
71
72 u32 now = readl(&priv->timer_base->counter);
73
74 if (now < priv->prev)
75 priv->upper += (1ull << 32);
76
77 priv->prev = now;
78
79 return (priv->upper + (u64)now);
80}
81
82static const struct timer_ops adi_gptimer_ops = {
83 .get_count = adi_gptimer_get_count,
84};
85
86static int adi_gptimer_probe(struct udevice *udev)
87{
88 struct timer_dev_priv *uc_priv = dev_get_uclass_priv(udev);
89 struct adi_gptimer_priv *priv = dev_get_priv(udev);
90 struct clk clk;
91 u16 imask;
92 int ret;
93
94 priv->timer_group = dev_remap_addr_index(udev, 0);
95 priv->timer_base = dev_remap_addr_index(udev, 1);
96 priv->upper = 0;
97 priv->prev = 0;
98
99 if (!priv->timer_group || !priv->timer_base) {
100 dev_err(udev, "Missing timer_group or timer_base reg entries\n");
101 return -ENODEV;
102 }
103
104 ret = clk_get_by_index(udev, 0, &clk);
105 if (ret < 0) {
106 dev_err(udev, "Missing clock reference for timer\n");
107 return ret;
108 }
109
110 ret = clk_enable(&clk);
111 if (ret) {
112 dev_err(udev, "Failed to enable clock\n");
113 return ret;
114 }
115
116 uc_priv->clock_rate = clk_get_rate(&clk);
117
118 /* Enable timer */
119 writew(TIMER_OUT_DIS | TIMER_MODE_PWM_CONT | TIMER_PULSE_HI,
120 &priv->timer_base->config);
121 writel(MAX_TIM_LOAD, &priv->timer_base->period);
122 writel(MAX_TIM_LOAD - 1, &priv->timer_base->width);
123
124 /* We only use timer 0 in uboot */
125 imask = readw(&priv->timer_group->data_imsk);
126 imask &= ~(1 << 0);
127 writew(imask, &priv->timer_group->data_imsk);
128 writew((1 << 0), &priv->timer_group->enable);
129
130 return 0;
131}
132
133static const struct udevice_id adi_gptimer_ids[] = {
134 { .compatible = "adi,sc5xx-gptimer" },
135 { },
136};
137
138U_BOOT_DRIVER(adi_gptimer) = {
139 .name = "adi_gptimer",
140 .id = UCLASS_TIMER,
141 .of_match = adi_gptimer_ids,
142 .priv_auto = sizeof(struct adi_gptimer_priv),
143 .probe = adi_gptimer_probe,
144 .ops = &adi_gptimer_ops,
145};