realtek: use DT provided address for timers
[openwrt/openwrt.git] / target / linux / realtek / files-5.10 / arch / mips / kernel / cevt-rtl9300.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/clockchips.h>
4 #include <linux/init.h>
5 #include <asm/time.h>
6 #include <asm/idle.h>
7 #include <linux/interrupt.h>
8 #include <linux/of_address.h>
9 #include <linux/of_irq.h>
10 #include <linux/sched_clock.h>
11
12 #include <mach-rtl83xx.h>
13
14 /*
15 * Timer registers
16 * the RTL9300/9310 SoCs have 6 timers, each register block 0x10 apart
17 */
18 #define RTL9300_TC_DATA 0x0
19 #define RTL9300_TC_CNT 0x4
20 #define RTL9300_TC_CTRL 0x8
21 #define RTL9300_TC_CTRL_MODE BIT(24)
22 #define RTL9300_TC_CTRL_EN BIT(28)
23 #define RTL9300_TC_INT 0xc
24 #define RTL9300_TC_INT_IP BIT(16)
25 #define RTL9300_TC_INT_IE BIT(20)
26
27 // Timer modes
28 #define TIMER_MODE_REPEAT 1
29 #define TIMER_MODE_ONCE 0
30
31 // Minimum divider is 2
32 #define DIVISOR_RTL9300 2
33
34 #define N_BITS 28
35
36 #define RTL9300_CLOCK_RATE 87500000
37
38 struct rtl9300_clk_dev {
39 struct clock_event_device clkdev;
40 void __iomem *base;
41 };
42
43 static void __iomem *rtl9300_tc_base(struct clock_event_device *clk)
44 {
45 struct rtl9300_clk_dev *rtl_clk = container_of(clk, struct rtl9300_clk_dev, clkdev);
46
47 return rtl_clk->base;
48 }
49
50 static irqreturn_t rtl9300_timer_interrupt(int irq, void *dev_id)
51 {
52 struct rtl9300_clk_dev *rtl_clk = dev_id;
53 struct clock_event_device *clk = &rtl_clk->clkdev;
54 // int cpu = smp_processor_id();
55 static atomic_t count = ATOMIC_INIT(0);
56 unsigned int c;
57 u32 v = readl(rtl_clk->base + RTL9300_TC_INT);
58
59 c = (unsigned int)atomic_inc_return(&count);
60
61 // Acknowledge the IRQ
62 v |= RTL9300_TC_INT_IP;
63 writel(v, rtl_clk->base + RTL9300_TC_INT);
64 if (readl(rtl_clk->base + RTL9300_TC_INT) & RTL9300_TC_INT_IP)
65 dump_stack();
66
67 clk->event_handler(clk);
68 return IRQ_HANDLED;
69 }
70
71 static void rtl9300_clock_stop(void __iomem *base)
72 {
73 u32 v;
74
75 writel(0, base + RTL9300_TC_CTRL);
76
77 // Acknowledge possibly pending IRQ
78 v = readl(base + RTL9300_TC_INT);
79 // if (v & RTL9300_TC_INT_IP)
80 writel(v | RTL9300_TC_INT_IP, base + RTL9300_TC_INT);
81 if (readl(base + RTL9300_TC_INT) & RTL9300_TC_INT_IP)
82 dump_stack();
83 }
84
85 static void rtl9300_timer_start(void __iomem *base, bool periodic)
86 {
87 u32 v = (periodic ? RTL9300_TC_CTRL_MODE : 0) | RTL9300_TC_CTRL_EN | DIVISOR_RTL9300;
88
89 writel(0, base + RTL9300_TC_CNT);
90 pr_debug("------------- starting timer base %08x\n", (u32)base);
91 writel(v, base + RTL9300_TC_CTRL);
92 }
93
94 static int rtl9300_next_event(unsigned long delta, struct clock_event_device *clk)
95 {
96 void __iomem *base = rtl9300_tc_base(clk);
97
98 rtl9300_clock_stop(base);
99 writel(delta, base + RTL9300_TC_DATA);
100 rtl9300_timer_start(base, TIMER_MODE_ONCE);
101
102 return 0;
103 }
104
105 static int rtl9300_state_periodic(struct clock_event_device *clk)
106 {
107 void __iomem *base = rtl9300_tc_base(clk);
108
109 pr_debug("------------- rtl9300_state_periodic %08x\n", (u32)base);
110 rtl9300_clock_stop(base);
111 writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
112 rtl9300_timer_start(base, TIMER_MODE_REPEAT);
113 return 0;
114 }
115
116 static int rtl9300_state_oneshot(struct clock_event_device *clk)
117 {
118 void __iomem *base = rtl9300_tc_base(clk);
119
120 pr_debug("------------- rtl9300_state_oneshot %08x\n", (u32)base);
121 rtl9300_clock_stop(base);
122 writel(RTL9300_CLOCK_RATE / HZ, base + RTL9300_TC_DATA);
123 rtl9300_timer_start(base, TIMER_MODE_ONCE);
124 return 0;
125 }
126
127 static int rtl9300_shutdown(struct clock_event_device *clk)
128 {
129 void __iomem *base = rtl9300_tc_base(clk);
130
131 pr_debug("------------- rtl9300_shutdown %08x\n", (u32)base);
132 rtl9300_clock_stop(base);
133 return 0;
134 }
135
136 static void rtl9300_clock_setup(void __iomem *base)
137 {
138 u32 v;
139
140 // Disable timer
141 writel(0, base + RTL9300_TC_CTRL);
142
143 // Acknowledge possibly pending IRQ
144 v = readl(base + RTL9300_TC_INT);
145 // if (v & RTL9300_TC_INT_IP)
146 writel(v | RTL9300_TC_INT_IP, base + RTL9300_TC_INT);
147 if (readl(base + RTL9300_TC_INT) & RTL9300_TC_INT_IP)
148 dump_stack();
149
150 // Setup maximum period (for use as clock-source)
151 writel(0x0fffffff, base + RTL9300_TC_DATA);
152 }
153
154 static DEFINE_PER_CPU(struct rtl9300_clk_dev, rtl9300_clockevent);
155 static DEFINE_PER_CPU(char [18], rtl9300_clock_name);
156
157 void rtl9300_clockevent_init(void)
158 {
159 int cpu = smp_processor_id();
160 int irq;
161 struct rtl9300_clk_dev *rtl_clk = &per_cpu(rtl9300_clockevent, cpu);
162 struct clock_event_device *cd = &rtl_clk->clkdev;
163 unsigned char *name = per_cpu(rtl9300_clock_name, cpu);
164 unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
165 struct device_node *node;
166
167 pr_info("%s called for cpu%d\n", __func__, cpu);
168 BUG_ON(cpu > 3); /* Only have 4 general purpose timers */
169
170 node = of_find_compatible_node(NULL, NULL, "realtek,rtl9300clock");
171 if (!node) {
172 pr_err("No DT entry found for realtek,rtl9300clock\n");
173 return;
174 }
175
176 irq = irq_of_parse_and_map(node, cpu);
177 pr_info("%s using IRQ %d\n", __func__, irq);
178
179 rtl_clk->base = of_iomap(node, cpu);
180 if (!rtl_clk->base) {
181 pr_err("cannot map timer for cpu %d", cpu);
182 return;
183 }
184
185 rtl9300_clock_setup(rtl_clk->base);
186
187 sprintf(name, "rtl9300-counter-%d", cpu);
188 cd->name = name;
189 cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
190
191 clockevent_set_clock(cd, RTL9300_CLOCK_RATE);
192
193 cd->max_delta_ns = clockevent_delta2ns(0x0fffffff, cd);
194 cd->max_delta_ticks = 0x0fffffff;
195 cd->min_delta_ns = clockevent_delta2ns(0x20, cd);
196 cd->min_delta_ticks = 0x20;
197 cd->rating = 300;
198 cd->irq = irq;
199 cd->cpumask = cpumask_of(cpu);
200 cd->set_next_event = rtl9300_next_event;
201 cd->set_state_shutdown = rtl9300_shutdown;
202 cd->set_state_periodic = rtl9300_state_periodic;
203 cd->set_state_oneshot = rtl9300_state_oneshot;
204 clockevents_register_device(cd);
205
206 irq_set_affinity(irq, cd->cpumask);
207
208 if (request_irq(irq, rtl9300_timer_interrupt, flags, name, rtl_clk))
209 pr_err("Failed to request irq %d (%s)\n", irq, name);
210
211 writel(RTL9300_TC_INT_IE, rtl_clk->base + RTL9300_TC_INT);
212 }