File Index
Files and directories
Sign in
FILE

timer-tegra186.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clocksource/timer-tegra186.c C
  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
 60struct tegra186_timer_soc {
 61	unsigned int num_timers;
 62	unsigned int num_wdts;
 63};
 64
 65struct tegra186_tmr {
 66	struct tegra186_timer *parent;
 67	void __iomem *regs;
 68	unsigned int index;
 69	unsigned int hwirq;
 70};
 71
 72struct 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
 82static inline struct tegra186_wdt *to_tegra186_wdt(struct watchdog_device *wdd)
 83{
 84	return container_of(wdd, struct tegra186_wdt, base);
 85}
 86
 87struct 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
 98static void tmr_writel(struct tegra186_tmr *tmr, u32 value, unsigned int offset)
 99{
100	writel_relaxed(value, tmr->regs + offset);
101}
102
103static void wdt_writel(struct tegra186_wdt *wdt, u32 value, unsigned int offset)
104{
105	writel_relaxed(value, wdt->regs + offset);
106}
107
108static u32 wdt_readl(struct tegra186_wdt *wdt, unsigned int offset)
109{
110	return readl_relaxed(wdt->regs + offset);
111}
112
113static 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
131static const struct watchdog_info tegra186_wdt_info = {
132	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
133	.identity = "NVIDIA Tegra186 WDT",
134};
135
136static 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
146static 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
186static 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
195static 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
204static 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
214static 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
230static 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	u32 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	 * Note: Since wdt->base.timeout is bound to 255, the maximum
270	 * value added to timeleft is
271	 *   255 * (1,000,000 / 5) * 4
272	 * = 255 * 200,000 * 4
273	 * = 204,000,000
274	 * TMRSR_PCV is a 29-bit field.
275	 * Its maximum value is 0x1fffffff = 536,870,911.
276	 * 204,000,000 + 536,870,911 = 740,870,911 = 0x2C28CAFF.
277	 * timeleft can therefore not overflow, and 64-bit calculations
278	 * are not necessary.
279	 */
280	timeleft += (wdt->base.timeout * (USEC_PER_SEC / 5)) * (4 - expiration);
281
282	/*
283	 * Convert the current counter value to seconds,
284	 * rounding to the nearest second.
285	 */
286	timeleft = DIV_ROUND_CLOSEST(timeleft, USEC_PER_SEC);
287
288	return timeleft;
289}
290
291static const struct watchdog_ops tegra186_wdt_ops = {
292	.owner = THIS_MODULE,
293	.start = tegra186_wdt_start,
294	.stop = tegra186_wdt_stop,
295	.ping = tegra186_wdt_ping,
296	.set_timeout = tegra186_wdt_set_timeout,
297	.get_timeleft = tegra186_wdt_get_timeleft,
298};
299
300static struct tegra186_wdt *tegra186_wdt_create(struct tegra186_timer *tegra,
301						unsigned int index)
302{
303	unsigned int offset = 0x10000, source;
304	struct tegra186_wdt *wdt;
305	u32 value;
306	int err;
307
308	offset += tegra->soc->num_timers * 0x10000 + index * 0x10000;
309
310	wdt = devm_kzalloc(tegra->dev, sizeof(*wdt), GFP_KERNEL);
311	if (!wdt)
312		return ERR_PTR(-ENOMEM);
313
314	wdt->regs = tegra->regs + offset;
315	wdt->index = index;
316
317	/* read the watchdog configuration since it might be locked down */
318	value = wdt_readl(wdt, WDTCR);
319
320	if (value & WDTCR_LOCAL_INT_ENABLE)
321		wdt->locked = true;
322
323	source = value & WDTCR_TIMER_SOURCE_MASK;
324
325	wdt->tmr = tegra186_tmr_create(tegra, source);
326	if (IS_ERR(wdt->tmr))
327		return ERR_CAST(wdt->tmr);
328
329	wdt->base.info = &tegra186_wdt_info;
330	wdt->base.ops = &tegra186_wdt_ops;
331	wdt->base.min_timeout = 1;
332	wdt->base.max_timeout = 255;
333	wdt->base.parent = tegra->dev;
334
335	err = watchdog_init_timeout(&wdt->base, 5, tegra->dev);
336	if (err < 0)
337		return ERR_PTR(err);
338
339	err = devm_watchdog_register_device(tegra->dev, &wdt->base);
340	if (err < 0)
341		return ERR_PTR(err);
342
343	return wdt;
344}
345
346static u64 tegra186_timer_tsc_read(struct clocksource *cs)
347{
348	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
349						    tsc);
350	u32 hi, lo, ss;
351
352	hi = readl_relaxed(tegra->regs + TKETSC1);
353
354	/*
355	 * The 56-bit value of the TSC is spread across two registers that are
356	 * not synchronized. In order to read them atomically, ensure that the
357	 * high 24 bits match before and after reading the low 32 bits.
358	 */
359	do {
360		/* snapshot the high 24 bits */
361		ss = hi;
362
363		lo = readl_relaxed(tegra->regs + TKETSC0);
364		hi = readl_relaxed(tegra->regs + TKETSC1);
365	} while (hi != ss);
366
367	return (u64)hi << 32 | lo;
368}
369
370static int tegra186_timer_tsc_init(struct tegra186_timer *tegra)
371{
372	tegra->tsc.name = "tsc";
373	tegra->tsc.rating = 300;
374	tegra->tsc.read = tegra186_timer_tsc_read;
375	tegra->tsc.mask = CLOCKSOURCE_MASK(56);
376	tegra->tsc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
377	tegra->tsc.owner = THIS_MODULE;
378
379	return clocksource_register_hz(&tegra->tsc, 31250000);
380}
381
382static u64 tegra186_timer_osc_read(struct clocksource *cs)
383{
384	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
385						    osc);
386
387	return readl_relaxed(tegra->regs + TKEOSC);
388}
389
390static int tegra186_timer_osc_init(struct tegra186_timer *tegra)
391{
392	tegra->osc.name = "osc";
393	tegra->osc.rating = 300;
394	tegra->osc.read = tegra186_timer_osc_read;
395	tegra->osc.mask = CLOCKSOURCE_MASK(32);
396	tegra->osc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
397	tegra->osc.owner = THIS_MODULE;
398
399	return clocksource_register_hz(&tegra->osc, 38400000);
400}
401
402static u64 tegra186_timer_usec_read(struct clocksource *cs)
403{
404	struct tegra186_timer *tegra = container_of(cs, struct tegra186_timer,
405						    usec);
406
407	return readl_relaxed(tegra->regs + TKEUSEC);
408}
409
410static int tegra186_timer_usec_init(struct tegra186_timer *tegra)
411{
412	tegra->usec.name = "usec";
413	tegra->usec.rating = 300;
414	tegra->usec.read = tegra186_timer_usec_read;
415	tegra->usec.mask = CLOCKSOURCE_MASK(32);
416	tegra->usec.flags = CLOCK_SOURCE_IS_CONTINUOUS;
417	tegra->usec.owner = THIS_MODULE;
418
419	return clocksource_register_hz(&tegra->usec, USEC_PER_SEC);
420}
421
422static int tegra186_timer_probe(struct platform_device *pdev)
423{
424	struct device *dev = &pdev->dev;
425	struct tegra186_timer *tegra;
426	int err;
427
428	tegra = devm_kzalloc(dev, sizeof(*tegra), GFP_KERNEL);
429	if (!tegra)
430		return -ENOMEM;
431
432	tegra->soc = of_device_get_match_data(dev);
433	dev_set_drvdata(dev, tegra);
434	tegra->dev = dev;
435
436	tegra->regs = devm_platform_ioremap_resource(pdev, 0);
437	if (IS_ERR(tegra->regs))
438		return PTR_ERR(tegra->regs);
439
440	err = platform_get_irq(pdev, 0);
441	if (err < 0)
442		return err;
443
444	/* create a watchdog using a preconfigured timer */
445	tegra->wdt = tegra186_wdt_create(tegra, 0);
446	if (IS_ERR(tegra->wdt)) {
447		err = PTR_ERR(tegra->wdt);
448		dev_err(dev, "failed to create WDT: %d\n", err);
449		return err;
450	}
451
452	err = tegra186_timer_tsc_init(tegra);
453	if (err < 0) {
454		dev_err(dev, "failed to register TSC counter: %d\n", err);
455		return err;
456	}
457
458	err = tegra186_timer_osc_init(tegra);
459	if (err < 0) {
460		dev_err(dev, "failed to register OSC counter: %d\n", err);
461		goto unregister_tsc;
462	}
463
464	err = tegra186_timer_usec_init(tegra);
465	if (err < 0) {
466		dev_err(dev, "failed to register USEC counter: %d\n", err);
467		goto unregister_osc;
468	}
469
470	return 0;
471
472unregister_osc:
473	clocksource_unregister(&tegra->osc);
474unregister_tsc:
475	clocksource_unregister(&tegra->tsc);
476	return err;
477}
478
479static void tegra186_timer_remove(struct platform_device *pdev)
480{
481	struct tegra186_timer *tegra = platform_get_drvdata(pdev);
482
483	clocksource_unregister(&tegra->usec);
484	clocksource_unregister(&tegra->osc);
485	clocksource_unregister(&tegra->tsc);
486}
487
488static int __maybe_unused tegra186_timer_suspend(struct device *dev)
489{
490	struct tegra186_timer *tegra = dev_get_drvdata(dev);
491
492	if (watchdog_active(&tegra->wdt->base))
493		tegra186_wdt_disable(tegra->wdt);
494
495	return 0;
496}
497
498static int __maybe_unused tegra186_timer_resume(struct device *dev)
499{
500	struct tegra186_timer *tegra = dev_get_drvdata(dev);
501
502	if (watchdog_active(&tegra->wdt->base))
503		tegra186_wdt_enable(tegra->wdt);
504
505	return 0;
506}
507
508static SIMPLE_DEV_PM_OPS(tegra186_timer_pm_ops, tegra186_timer_suspend,
509			 tegra186_timer_resume);
510
511static const struct tegra186_timer_soc tegra186_timer = {
512	.num_timers = 10,
513	.num_wdts = 3,
514};
515
516static const struct tegra186_timer_soc tegra234_timer = {
517	.num_timers = 16,
518	.num_wdts = 3,
519};
520
521static const struct of_device_id tegra186_timer_of_match[] = {
522	{ .compatible = "nvidia,tegra186-timer", .data = &tegra186_timer },
523	{ .compatible = "nvidia,tegra234-timer", .data = &tegra234_timer },
524	{ }
525};
526MODULE_DEVICE_TABLE(of, tegra186_timer_of_match);
527
528static struct platform_driver tegra186_wdt_driver = {
529	.driver = {
530		.name = "tegra186-timer",
531		.pm = &tegra186_timer_pm_ops,
532		.of_match_table = tegra186_timer_of_match,
533	},
534	.probe = tegra186_timer_probe,
535	.remove = tegra186_timer_remove,
536};
537module_platform_driver(tegra186_wdt_driver);
538
539MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
540MODULE_DESCRIPTION("NVIDIA Tegra186 timers driver");
~/ Read-only file preview.