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

rtd119x_wdt.c (3724B)


      1/*
      2 * Realtek RTD129x watchdog
      3 *
      4 * Copyright (c) 2017 Andreas Färber
      5 *
      6 * SPDX-License-Identifier: GPL-2.0+
      7 */
      8
      9#include <linux/bitops.h>
     10#include <linux/clk.h>
     11#include <linux/io.h>
     12#include <linux/of.h>
     13#include <linux/of_address.h>
     14#include <linux/platform_device.h>
     15#include <linux/watchdog.h>
     16
     17#define RTD119X_TCWCR		0x0
     18#define RTD119X_TCWTR		0x4
     19#define RTD119X_TCWOV		0xc
     20
     21#define RTD119X_TCWCR_WDEN_DISABLED		0xa5
     22#define RTD119X_TCWCR_WDEN_ENABLED		0xff
     23#define RTD119X_TCWCR_WDEN_MASK			0xff
     24
     25#define RTD119X_TCWTR_WDCLR			BIT(0)
     26
     27struct rtd119x_watchdog_device {
     28	struct watchdog_device wdt_dev;
     29	void __iomem *base;
     30	struct clk *clk;
     31};
     32
     33static int rtd119x_wdt_start(struct watchdog_device *wdev)
     34{
     35	struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
     36	u32 val;
     37
     38	val = readl_relaxed(data->base + RTD119X_TCWCR);
     39	val &= ~RTD119X_TCWCR_WDEN_MASK;
     40	val |= RTD119X_TCWCR_WDEN_ENABLED;
     41	writel(val, data->base + RTD119X_TCWCR);
     42
     43	return 0;
     44}
     45
     46static int rtd119x_wdt_stop(struct watchdog_device *wdev)
     47{
     48	struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
     49	u32 val;
     50
     51	val = readl_relaxed(data->base + RTD119X_TCWCR);
     52	val &= ~RTD119X_TCWCR_WDEN_MASK;
     53	val |= RTD119X_TCWCR_WDEN_DISABLED;
     54	writel(val, data->base + RTD119X_TCWCR);
     55
     56	return 0;
     57}
     58
     59static int rtd119x_wdt_ping(struct watchdog_device *wdev)
     60{
     61	struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
     62
     63	writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
     64
     65	return rtd119x_wdt_start(wdev);
     66}
     67
     68static int rtd119x_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
     69{
     70	struct rtd119x_watchdog_device *data = watchdog_get_drvdata(wdev);
     71
     72	writel(val * clk_get_rate(data->clk), data->base + RTD119X_TCWOV);
     73
     74	data->wdt_dev.timeout = val;
     75
     76	return 0;
     77}
     78
     79static const struct watchdog_ops rtd119x_wdt_ops = {
     80	.owner = THIS_MODULE,
     81	.start		= rtd119x_wdt_start,
     82	.stop		= rtd119x_wdt_stop,
     83	.ping		= rtd119x_wdt_ping,
     84	.set_timeout	= rtd119x_wdt_set_timeout,
     85};
     86
     87static const struct watchdog_info rtd119x_wdt_info = {
     88	.identity = "rtd119x-wdt",
     89	.options = 0,
     90};
     91
     92static const struct of_device_id rtd119x_wdt_dt_ids[] = {
     93	 { .compatible = "realtek,rtd1295-watchdog" },
     94	 { }
     95};
     96
     97static void rtd119x_clk_disable_unprepare(void *data)
     98{
     99	clk_disable_unprepare(data);
    100}
    101
    102static int rtd119x_wdt_probe(struct platform_device *pdev)
    103{
    104	struct device *dev = &pdev->dev;
    105	struct rtd119x_watchdog_device *data;
    106	int ret;
    107
    108	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
    109	if (!data)
    110		return -ENOMEM;
    111
    112	data->base = devm_platform_ioremap_resource(pdev, 0);
    113	if (IS_ERR(data->base))
    114		return PTR_ERR(data->base);
    115
    116	data->clk = devm_clk_get(dev, NULL);
    117	if (IS_ERR(data->clk))
    118		return PTR_ERR(data->clk);
    119
    120	ret = clk_prepare_enable(data->clk);
    121	if (ret)
    122		return ret;
    123	ret = devm_add_action_or_reset(dev, rtd119x_clk_disable_unprepare,
    124				       data->clk);
    125	if (ret)
    126		return ret;
    127
    128	data->wdt_dev.info = &rtd119x_wdt_info;
    129	data->wdt_dev.ops = &rtd119x_wdt_ops;
    130	data->wdt_dev.timeout = 120;
    131	data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk);
    132	data->wdt_dev.min_timeout = 1;
    133	data->wdt_dev.parent = dev;
    134
    135	watchdog_stop_on_reboot(&data->wdt_dev);
    136	watchdog_set_drvdata(&data->wdt_dev, data);
    137	platform_set_drvdata(pdev, data);
    138
    139	writel_relaxed(RTD119X_TCWTR_WDCLR, data->base + RTD119X_TCWTR);
    140	rtd119x_wdt_set_timeout(&data->wdt_dev, data->wdt_dev.timeout);
    141	rtd119x_wdt_stop(&data->wdt_dev);
    142
    143	return devm_watchdog_register_device(dev, &data->wdt_dev);
    144}
    145
    146static struct platform_driver rtd119x_wdt_driver = {
    147	.probe = rtd119x_wdt_probe,
    148	.driver = {
    149		.name = "rtd1295-watchdog",
    150		.of_match_table	= rtd119x_wdt_dt_ids,
    151	},
    152};
    153builtin_platform_driver(rtd119x_wdt_driver);