cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mt7621_wdt.c (4633B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Ralink MT7621/MT7628 built-in hardware watchdog timer
      4 *
      5 * Copyright (C) 2014 John Crispin <john@phrozen.org>
      6 *
      7 * This driver was based on: drivers/watchdog/rt2880_wdt.c
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/reset.h>
     12#include <linux/module.h>
     13#include <linux/kernel.h>
     14#include <linux/watchdog.h>
     15#include <linux/moduleparam.h>
     16#include <linux/platform_device.h>
     17#include <linux/mod_devicetable.h>
     18
     19#include <asm/mach-ralink/ralink_regs.h>
     20
     21#define SYSC_RSTSTAT			0x38
     22#define WDT_RST_CAUSE			BIT(1)
     23
     24#define RALINK_WDT_TIMEOUT		30
     25
     26#define TIMER_REG_TMRSTAT		0x00
     27#define TIMER_REG_TMR1LOAD		0x24
     28#define TIMER_REG_TMR1CTL		0x20
     29
     30#define TMR1CTL_ENABLE			BIT(7)
     31#define TMR1CTL_RESTART			BIT(9)
     32#define TMR1CTL_PRESCALE_SHIFT		16
     33
     34static void __iomem *mt7621_wdt_base;
     35static struct reset_control *mt7621_wdt_reset;
     36
     37static bool nowayout = WATCHDOG_NOWAYOUT;
     38module_param(nowayout, bool, 0);
     39MODULE_PARM_DESC(nowayout,
     40		 "Watchdog cannot be stopped once started (default="
     41		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
     42
     43static inline void rt_wdt_w32(unsigned reg, u32 val)
     44{
     45	iowrite32(val, mt7621_wdt_base + reg);
     46}
     47
     48static inline u32 rt_wdt_r32(unsigned reg)
     49{
     50	return ioread32(mt7621_wdt_base + reg);
     51}
     52
     53static int mt7621_wdt_ping(struct watchdog_device *w)
     54{
     55	rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART);
     56
     57	return 0;
     58}
     59
     60static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
     61{
     62	w->timeout = t;
     63	rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000);
     64	mt7621_wdt_ping(w);
     65
     66	return 0;
     67}
     68
     69static int mt7621_wdt_start(struct watchdog_device *w)
     70{
     71	u32 t;
     72
     73	/* set the prescaler to 1ms == 1000us */
     74	rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT);
     75
     76	mt7621_wdt_set_timeout(w, w->timeout);
     77
     78	t = rt_wdt_r32(TIMER_REG_TMR1CTL);
     79	t |= TMR1CTL_ENABLE;
     80	rt_wdt_w32(TIMER_REG_TMR1CTL, t);
     81
     82	return 0;
     83}
     84
     85static int mt7621_wdt_stop(struct watchdog_device *w)
     86{
     87	u32 t;
     88
     89	mt7621_wdt_ping(w);
     90
     91	t = rt_wdt_r32(TIMER_REG_TMR1CTL);
     92	t &= ~TMR1CTL_ENABLE;
     93	rt_wdt_w32(TIMER_REG_TMR1CTL, t);
     94
     95	return 0;
     96}
     97
     98static int mt7621_wdt_bootcause(void)
     99{
    100	if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
    101		return WDIOF_CARDRESET;
    102
    103	return 0;
    104}
    105
    106static int mt7621_wdt_is_running(struct watchdog_device *w)
    107{
    108	return !!(rt_wdt_r32(TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE);
    109}
    110
    111static const struct watchdog_info mt7621_wdt_info = {
    112	.identity = "Mediatek Watchdog",
    113	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
    114};
    115
    116static const struct watchdog_ops mt7621_wdt_ops = {
    117	.owner = THIS_MODULE,
    118	.start = mt7621_wdt_start,
    119	.stop = mt7621_wdt_stop,
    120	.ping = mt7621_wdt_ping,
    121	.set_timeout = mt7621_wdt_set_timeout,
    122};
    123
    124static struct watchdog_device mt7621_wdt_dev = {
    125	.info = &mt7621_wdt_info,
    126	.ops = &mt7621_wdt_ops,
    127	.min_timeout = 1,
    128	.max_timeout = 0xfffful / 1000,
    129};
    130
    131static int mt7621_wdt_probe(struct platform_device *pdev)
    132{
    133	struct device *dev = &pdev->dev;
    134	mt7621_wdt_base = devm_platform_ioremap_resource(pdev, 0);
    135	if (IS_ERR(mt7621_wdt_base))
    136		return PTR_ERR(mt7621_wdt_base);
    137
    138	mt7621_wdt_reset = devm_reset_control_get_exclusive(dev, NULL);
    139	if (!IS_ERR(mt7621_wdt_reset))
    140		reset_control_deassert(mt7621_wdt_reset);
    141
    142	mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause();
    143
    144	watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout,
    145			      dev);
    146	watchdog_set_nowayout(&mt7621_wdt_dev, nowayout);
    147	if (mt7621_wdt_is_running(&mt7621_wdt_dev)) {
    148		/*
    149		 * Make sure to apply timeout from watchdog core, taking
    150		 * the prescaler of this driver here into account (the
    151		 * boot loader might be using a different prescaler).
    152		 *
    153		 * To avoid spurious resets because of different scaling,
    154		 * we first disable the watchdog, set the new prescaler
    155		 * and timeout, and then re-enable the watchdog.
    156		 */
    157		mt7621_wdt_stop(&mt7621_wdt_dev);
    158		mt7621_wdt_start(&mt7621_wdt_dev);
    159		set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status);
    160	}
    161
    162	return devm_watchdog_register_device(dev, &mt7621_wdt_dev);
    163}
    164
    165static void mt7621_wdt_shutdown(struct platform_device *pdev)
    166{
    167	mt7621_wdt_stop(&mt7621_wdt_dev);
    168}
    169
    170static const struct of_device_id mt7621_wdt_match[] = {
    171	{ .compatible = "mediatek,mt7621-wdt" },
    172	{},
    173};
    174MODULE_DEVICE_TABLE(of, mt7621_wdt_match);
    175
    176static struct platform_driver mt7621_wdt_driver = {
    177	.probe		= mt7621_wdt_probe,
    178	.shutdown	= mt7621_wdt_shutdown,
    179	.driver		= {
    180		.name		= KBUILD_MODNAME,
    181		.of_match_table	= mt7621_wdt_match,
    182	},
    183};
    184
    185module_platform_driver(mt7621_wdt_driver);
    186
    187MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver");
    188MODULE_AUTHOR("John Crispin <john@phrozen.org");
    189MODULE_LICENSE("GPL v2");