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