xref: /linux/drivers/clocksource/timer-tegra186.c (revision 6376c0770656f3bdf7f411faf068371b6932aeca)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2019-2025 NVIDIA Corporation. All rights reserved.
4  */
5 
6 #include <linux/bitfield.h>
7 #include <linux/clocksource.h>
8 #include <linux/module.h>
9 #include <linux/interrupt.h>
10 #include <linux/io.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/pm.h>
14 #include <linux/watchdog.h>
15 
16 /* shared registers */
17 #define TKETSC0 0x000
18 #define TKETSC1 0x004
19 #define TKEUSEC 0x008
20 #define TKEOSC  0x00c
21 
22 #define TKEIE(x) (0x100 + ((x) * 4))
23 #define  TKEIE_WDT_MASK(x, y) ((y) << (16 + 4 * (x)))
24 
25 /* timer registers */
26 #define TMRCR 0x000
27 #define  TMRCR_ENABLE BIT(31)
28 #define  TMRCR_PERIODIC BIT(30)
29 #define  TMRCR_PTV(x) ((x) & 0x0fffffff)
30 
31 #define TMRSR 0x004
32 #define  TMRSR_INTR_CLR BIT(30)
33 #define  TMRSR_PCV GENMASK(28, 0)
34 
35 #define TMRCSSR 0x008
36 #define  TMRCSSR_SRC_USEC (0 << 0)
37 
38 /* watchdog registers */
39 #define WDTCR 0x000
40 #define  WDTCR_SYSTEM_POR_RESET_ENABLE BIT(16)
41 #define  WDTCR_SYSTEM_DEBUG_RESET_ENABLE BIT(15)
42 #define  WDTCR_REMOTE_INT_ENABLE BIT(14)
43 #define  WDTCR_LOCAL_FIQ_ENABLE BIT(13)
44 #define  WDTCR_LOCAL_INT_ENABLE BIT(12)
45 #define  WDTCR_PERIOD_MASK (0xff << 4)
46 #define  WDTCR_PERIOD(x) (((x) & 0xff) << 4)
47 #define  WDTCR_TIMER_SOURCE_MASK 0xf
48 #define  WDTCR_TIMER_SOURCE(x) ((x) & 0xf)
49 
50 #define WDTSR 0x004
51 #define  WDTSR_CURRENT_EXPIRATION_COUNT GENMASK(14, 12)
52 
53 #define WDTCMDR 0x008
54 #define  WDTCMDR_DISABLE_COUNTER BIT(1)
55 #define  WDTCMDR_START_COUNTER BIT(0)
56 
57 #define WDTUR 0x00c
58 #define  WDTUR_UNLOCK_PATTERN 0x0000c45a
59 
60 struct tegra186_timer_soc {
61 	unsigned int num_timers;
62 	unsigned int num_wdts;
63 };
64 
65 struct tegra186_tmr {
66 	struct tegra186_timer *parent;
67 	void __iomem *regs;
68 	unsigned int index;
69 	unsigned int hwirq;
70 };
71 
72 struct tegra186_wdt {
73 	struct watchdog_device base;
74 
75 	void __iomem *regs;
76 	unsigned int index;
77 	bool locked;
78 
79 	struct tegra186_tmr *tmr;
80 };
81 
to_tegra186_wdt(struct watchdog_device * wdd)82 static inline struct tegra186_wdt *to_tegra186_wdt(struct watchdog_device *wdd)
83 {
84 	return container_of(wdd, struct tegra186_wdt, base);
85 }
86 
87 struct tegra186_timer {
88 	const struct tegra186_timer_soc *soc;
89 	struct device *dev;
90 	void __iomem *regs;
91 
92 	struct tegra186_wdt *wdt;
93 	struct clocksource usec;
94 	struct clocksource tsc;
95 	struct clocksource osc;
96 };
97 
tmr_writel(struct tegra186_tmr * tmr,u32 value,unsigned int offset)98 static void tmr_writel(struct tegra186_tmr *tmr, u32 value, unsigned int offset)
99 {
100 	writel_relaxed(value, tmr->regs + offset);
101 }
102 
wdt_writel(struct tegra186_wdt * wdt,u32 value,unsigned int offset)103 static void wdt_writel(struct tegra186_wdt *wdt, u32 value, unsigned int offset)
104 {
105 	writel_relaxed(value, wdt->regs + offset);
106 }
107 
wdt_readl(struct tegra186_wdt * wdt,unsigned int offset)108 static u32 wdt_readl(struct tegra186_wdt *wdt, unsigned int offset)
109 {
110 	return readl_relaxed(wdt->regs + offset);
111 }
112 
tegra186_tmr_create(struct tegra186_timer * tegra,unsigned int index)113 static struct tegra186_tmr *tegra186_tmr_create(struct tegra186_timer *tegra,
114 						unsigned int index)
115 {
116 	unsigned int offset = 0x10000 + index * 0x10000;
117 	struct tegra186_tmr *tmr;
118 
119 	tmr = devm_kzalloc(tegra->dev, sizeof(*tmr), GFP_KERNEL);
120 	if (!tmr)
121 		return ERR_PTR(-ENOMEM);
122 
123 	tmr->parent = tegra;
124 	tmr->regs = tegra->regs + offset;
125 	tmr->index = index;
126 	tmr->hwirq = 0;
127 
128 	return tmr;
129 }
130 
131 static const struct watchdog_info tegra186_wdt_info = {
132 	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
133 	.identity = "NVIDIA Tegra186 WDT",
134 };
135 
tegra186_wdt_disable(struct tegra186_wdt * wdt)136 static void tegra186_wdt_disable(struct tegra186_wdt *wdt)
137 {
138 	/* unlock and disable the watchdog */
139 	wdt_writel(wdt, WDTUR_UNLOCK_PATTERN, WDTUR);
140 	wdt_writel(wdt, WDTCMDR_DISABLE_COUNTER, WDTCMDR);
141 
142 	/* disable timer */
143 	tmr_writel(wdt->tmr, 0, TMRCR);
144 }
145 
tegra186_wdt_enable(struct tegra186_wdt * wdt)146 static void tegra186_wdt_enable(struct tegra186_wdt *wdt)
147 {
148 	struct tegra186_timer *tegra = wdt->tmr->parent;
149 	u32 value;
150 
151 	/* unmask hardware IRQ, this may have been lost across powergate */
152 	value = TKEIE_WDT_MASK(wdt->index, 1);
153 	writel(value, tegra->regs + TKEIE(wdt->tmr->hwirq));
154 
155 	/* clear interrupt */
156 	tmr_writel(wdt->tmr, TMRSR_INTR_CLR, TMRSR);
157 
158 	/* select microsecond source */
159 	tmr_writel(wdt->tmr, TMRCSSR_SRC_USEC, TMRCSSR);
160 
161 	/* configure timer (system reset happens on the fifth expiration) */
162 	value = TMRCR_PTV(wdt->base.timeout * USEC_PER_SEC / 5) |
163 		TMRCR_PERIODIC | TMRCR_ENABLE;
164 	tmr_writel(wdt->tmr, value, TMRCR);
165 
166 	if (!wdt->locked) {
167 		value = wdt_readl(wdt, WDTCR);
168 
169 		/* select the proper timer source */
170 		value &= ~WDTCR_TIMER_SOURCE_MASK;
171 		value |= WDTCR_TIMER_SOURCE(wdt->tmr->index);
172 
173 		/* single timer period since that's already configured */
174 		value &= ~WDTCR_PERIOD_MASK;
175 		value |= WDTCR_PERIOD(1);
176 
177 		/* enable system POR reset */
178 		value |= WDTCR_SYSTEM_POR_RESET_ENABLE;
179 
180 		wdt_writel(wdt, value, WDTCR);
181 	}
182 
183 	wdt_writel(wdt, WDTCMDR_START_COUNTER, WDTCMDR);
184 }
185 
tegra186_wdt_start(struct watchdog_device * wdd)186 static int tegra186_wdt_start(struct watchdog_device *wdd)
187 {
188 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
189 
190 	tegra186_wdt_enable(wdt);
191 
192 	return 0;
193 }
194 
tegra186_wdt_stop(struct watchdog_device * wdd)195 static int tegra186_wdt_stop(struct watchdog_device *wdd)
196 {
197 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
198 
199 	tegra186_wdt_disable(wdt);
200 
201 	return 0;
202 }
203 
tegra186_wdt_ping(struct watchdog_device * wdd)204 static int tegra186_wdt_ping(struct watchdog_device *wdd)
205 {
206 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
207 
208 	tegra186_wdt_disable(wdt);
209 	tegra186_wdt_enable(wdt);
210 
211 	return 0;
212 }
213 
tegra186_wdt_set_timeout(struct watchdog_device * wdd,unsigned int timeout)214 static int tegra186_wdt_set_timeout(struct watchdog_device *wdd,
215 				    unsigned int timeout)
216 {
217 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
218 
219 	if (watchdog_active(&wdt->base))
220 		tegra186_wdt_disable(wdt);
221 
222 	wdt->base.timeout = timeout;
223 
224 	if (watchdog_active(&wdt->base))
225 		tegra186_wdt_enable(wdt);
226 
227 	return 0;
228 }
229 
tegra186_wdt_get_timeleft(struct watchdog_device * wdd)230 static unsigned int tegra186_wdt_get_timeleft(struct watchdog_device *wdd)
231 {
232 	struct tegra186_wdt *wdt = to_tegra186_wdt(wdd);
233 	u32 expiration, val;
234 	u64 timeleft;
235 
236 	if (!watchdog_active(&wdt->base)) {
237 		/* return zero if the watchdog timer is not activated. */
238 		return 0;
239 	}
240 
241 	/*
242 	 * Reset occurs on the fifth expiration of the
243 	 * watchdog timer and so when the watchdog timer is configured,
244 	 * the actual value programmed into the counter is 1/5 of the
245 	 * timeout value. Once the counter reaches 0, expiration count
246 	 * will be increased by 1 and the down counter restarts.
247 	 * Hence to get the time left before system reset we must
248 	 * combine 2 parts:
249 	 * 1. value of the current down counter
250 	 * 2. (number of counter expirations remaining) * (timeout/5)
251 	 */
252 
253 	/* Get the current number of counter expirations. Should be a
254 	 * value between 0 and 4
255 	 */
256 	val = readl_relaxed(wdt->regs + WDTSR);
257 	expiration = FIELD_GET(WDTSR_CURRENT_EXPIRATION_COUNT, val);
258 	if (WARN_ON_ONCE(expiration > 4))
259 		return 0;
260 
261 	/* Get the current counter value in microsecond. */
262 	val = readl_relaxed(wdt->tmr->regs + TMRSR);
263 	timeleft = FIELD_GET(TMRSR_PCV, val);
264 
265 	/*
266 	 * Calculate the time remaining by adding the time for the
267 	 * counter value to the time of the counter expirations that
268 	 * remain.
269 	 */
270 	timeleft += (((u64)wdt->base.timeout * USEC_PER_SEC) / 5) * (4 - expiration);
271 
272 	/*
273 	 * Convert the current counter value to seconds,
274 	 * rounding up to the nearest second. Cast u64 to
275 	 * u32 under the assumption that no overflow happens
276 	 * when coverting to seconds.
277 	 */
278 	timeleft = DIV_ROUND_CLOSEST_ULL(timeleft, USEC_PER_SEC);
279 
280 	if (WARN_ON_ONCE(timeleft > U32_MAX))
281 		return U32_MAX;
282 
283 	return lower_32_bits(timeleft);
284 }
285 
286 static const struct watchdog_ops tegra186_wdt_ops = {
287 	.owner = THIS_MODULE,
288 	.start = tegra186_wdt_start,
289 	.stop = tegra186_wdt_stop,
290 	.ping = tegra186_wdt_ping,
291 	.set_timeout = tegra186_wdt_set_timeout,
292 	.get_timeleft = tegra186_wdt_get_timeleft,
293 };
294 
tegra186_wdt_create(struct tegra186_timer * tegra,unsigned int index)295 static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
296 						unsigned int index)
297 {
298 	unsigned int offset = 0x10000, source;
299 	struct tegra186_wdt *wdt;
300 	u32 value;
301 	int err;
302 
303 	offset += tegra->soc->num_timers * 0x10000 + index * 0x10000;
304 
305 	wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL);
306 	if (!wdt)
307 		return ERR_PTR(-ENOMEM);
308 
309 	wdt->regs = tegra->regs + offset;
310 	wdt->index = index;
311 
312 	/* read the watchdog configuration since it might be locked down */
313 	value = wdt_readl(wdt, WDTCR);
314 
315 	if (value & WDTCR_LOCAL_INT_ENABLE)
316 		wdt->locked = true;
317 
318 	source = value & WDTCR_TIMER_SOURCE_MASK;
319 
320 	wdt->tmr = tegra186_tmr_create(tegra, source);
321 	if (IS_ERR(wdt->tmr))
322 		return ERR_CAST(wdt->tmr);
323 
324 	wdt->base.info = &tegra186_wdt_info;
325 	wdt->base.ops = &tegra186_wdt_ops;
326 	wdt->base.min_timeout = 1;
327 	wdt->base.max_timeout = 255;
328 	wdt->base.parent = tegra->dev;
329 
330 	err = watchdog_init_timeout(&wdt->base, 5, tegra->dev);
331 	if (err < 0) {
332 		dev_err(tegra->dev, "failed to initialize timeout: %d\n", err);
333 		return ERR_PTR(err);
334 	}
335 
336 	err = devm_watchdog_register_device(tegra->dev, &wdt->base);
337 	if (err < 0) {
338 		dev_err(tegra->dev, "failed to register WDT: %d\n", err);
339 		return ERR_PTR(err);
340 	}
341 
342 	return wdt;
343 }
344 
tegra186_timer_tsc_read(struct clocksource * cs)345 static u64 tegra186_timer_tsc_read(struct clocksource *cs)
346 {
347 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
348 						    tsc);
349 	u32 hi, lo, ss;
350 
351 	hi = readl_relaxed(tegra->regs + TKETSC1);
352 
353 	/*
354 	 * The 56-bit value of the TSC is spread across two registers that are
355 	 * not synchronized. In order to read them atomically, ensure that the
356 	 * high 24 bits match before and after reading the low 32 bits.
357 	 */
358 	do {
359 		/* snapshot the high 24 bits */
360 		ss = hi;
361 
362 		lo = readl_relaxed(tegra->regs + TKETSC0);
363 		hi = readl_relaxed(tegra->regs + TKETSC1);
364 	} while (hi != ss);
365 
366 	return (u64)hi << 32 | lo;
367 }
368 
tegra186_timer_tsc_init(struct tegra186_timer * tegra)369 static int tegra186_timer_tsc_init(struct tegra186_timer *tegra)
370 {
371 	tegra->tsc.name = "tsc";
372 	tegra->tsc.rating = 300;
373 	tegra->tsc.read = tegra186_timer_tsc_read;
374 	tegra->tsc.mask = CLOCKSOURCE_MASK(56);
375 	tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
376 
377 	return clocksource_register_hz(&tegra->tsc, 31250000);
378 }
379 
tegra186_timer_osc_read(struct clocksource * cs)380 static u64 tegra186_timer_osc_read(struct clocksource *cs)
381 {
382 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
383 						    osc);
384 
385 	return readl_relaxed(tegra->regs + TKEOSC);
386 }
387 
tegra186_timer_osc_init(struct tegra186_timer * tegra)388 static int tegra186_timer_osc_init(struct tegra186_timer *tegra)
389 {
390 	tegra->osc.name = "osc";
391 	tegra->osc.rating = 300;
392 	tegra->osc.read = tegra186_timer_osc_read;
393 	tegra->osc.mask = CLOCKSOURCE_MASK(32);
394 	tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
395 
396 	return clocksource_register_hz(&tegra->osc, 38400000);
397 }
398 
tegra186_timer_usec_read(struct clocksource * cs)399 static u64 tegra186_timer_usec_read(struct clocksource *cs)
400 {
401 	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
402 						    usec);
403 
404 	return readl_relaxed(tegra->regs + TKEUSEC);
405 }
406 
tegra186_timer_usec_init(struct tegra186_timer * tegra)407 static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
408 {
409 	tegra->usec.name = "usec";
410 	tegra->usec.rating = 300;
411 	tegra->usec.read = tegra186_timer_usec_read;
412 	tegra->usec.mask = CLOCKSOURCE_MASK(32);
413 	tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS;
414 
415 	return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
416 }
417 
tegra186_timer_probe(struct platform_device * pdev)418 static int tegra186_timer_probe(struct platform_device *pdev)
419 {
420 	struct device *dev = &pdev->dev;
421 	struct tegra186_timer *tegra;
422 	int err;
423 
424 	tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL);
425 	if (!tegra)
426 		return -ENOMEM;
427 
428 	tegra->soc = of_device_get_match_data(dev);
429 	dev_set_drvdata(dev, tegra);
430 	tegra->dev = dev;
431 
432 	tegra->regs = devm_platform_ioremap_resource(pdev, 0);
433 	if (IS_ERR(tegra->regs))
434 		return PTR_ERR(tegra->regs);
435 
436 	err = platform_get_irq(pdev, 0);
437 	if (err < 0)
438 		return err;
439 
440 	/* create a watchdog using a preconfigured timer */
441 	tegra->wdt = tegra186_wdt_create(tegra, 0);
442 	if (IS_ERR(tegra->wdt)) {
443 		err = PTR_ERR(tegra->wdt);
444 		dev_err(dev, "failed to create WDT: %d\n", err);
445 		return err;
446 	}
447 
448 	err = tegra186_timer_tsc_init(tegra);
449 	if (err < 0) {
450 		dev_err(dev, "failed to register TSC counter: %d\n", err);
451 		return err;
452 	}
453 
454 	err = tegra186_timer_osc_init(tegra);
455 	if (err < 0) {
456 		dev_err(dev, "failed to register OSC counter: %d\n", err);
457 		goto unregister_tsc;
458 	}
459 
460 	err = tegra186_timer_usec_init(tegra);
461 	if (err < 0) {
462 		dev_err(dev, "failed to register USEC counter: %d\n", err);
463 		goto unregister_osc;
464 	}
465 
466 	return 0;
467 
468 unregister_osc:
469 	clocksource_unregister(&tegra->osc);
470 unregister_tsc:
471 	clocksource_unregister(&tegra->tsc);
472 	return err;
473 }
474 
tegra186_timer_remove(struct platform_device * pdev)475 static void tegra186_timer_remove(struct platform_device *pdev)
476 {
477 	struct tegra186_timer *tegra = platform_get_drvdata(pdev);
478 
479 	clocksource_unregister(&tegra->usec);
480 	clocksource_unregister(&tegra->osc);
481 	clocksource_unregister(&tegra->tsc);
482 }
483 
tegra186_timer_suspend(struct device * dev)484 static int __maybe_unused tegra186_timer_suspend(struct device *dev)
485 {
486 	struct tegra186_timer *tegra = dev_get_drvdata(dev);
487 
488 	if (watchdog_active(&tegra->wdt->base))
489 		tegra186_wdt_disable(tegra->wdt);
490 
491 	return 0;
492 }
493 
tegra186_timer_resume(struct device * dev)494 static int __maybe_unused tegra186_timer_resume(struct device *dev)
495 {
496 	struct tegra186_timer *tegra = dev_get_drvdata(dev);
497 
498 	if (watchdog_active(&tegra->wdt->base))
499 		tegra186_wdt_enable(tegra->wdt);
500 
501 	return 0;
502 }
503 
504 static SIMPLE_DEV_PM_OPS(tegra186_timer_pm_ops, tegra186_timer_suspend,
505 			 tegra186_timer_resume);
506 
507 static const struct tegra186_timer_soc tegra186_timer = {
508 	.num_timers = 10,
509 	.num_wdts = 3,
510 };
511 
512 static const struct tegra186_timer_soc tegra234_timer = {
513 	.num_timers = 16,
514 	.num_wdts = 3,
515 };
516 
517 static const struct of_device_id tegra186_timer_of_match[] = {
518 	{ .compatible = "nvidia,tegra186-timer", .data = &tegra186_timer },
519 	{ .compatible = "nvidia,tegra234-timer", .data = &tegra234_timer },
520 	{ }
521 };
522 MODULE_DEVICE_TABLE(of, tegra186_timer_of_match);
523 
524 static struct platform_driver tegra186_wdt_driver = {
525 	.driver = {
526 		.name = "tegra186-timer",
527 		.pm = &tegra186_timer_pm_ops,
528 		.of_match_table = tegra186_timer_of_match,
529 	},
530 	.probe = tegra186_timer_probe,
531 	.remove = tegra186_timer_remove,
532 };
533 module_platform_driver(tegra186_wdt_driver);
534 
535 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
536 MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver");
537