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

digicolor_wdt.c (3876B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Watchdog driver for Conexant Digicolor
      4 *
      5 * Copyright (C) 2015 Paradox Innovation Ltd.
      6 *
      7 */
      8
      9#include <linux/types.h>
     10#include <linux/module.h>
     11#include <linux/io.h>
     12#include <linux/delay.h>
     13#include <linux/clk.h>
     14#include <linux/watchdog.h>
     15#include <linux/platform_device.h>
     16#include <linux/of_address.h>
     17
     18#define TIMER_A_CONTROL		0
     19#define TIMER_A_COUNT		4
     20
     21#define TIMER_A_ENABLE_COUNT	BIT(0)
     22#define TIMER_A_ENABLE_WATCHDOG	BIT(1)
     23
     24struct dc_wdt {
     25	void __iomem		*base;
     26	struct clk		*clk;
     27	spinlock_t		lock;
     28};
     29
     30static unsigned timeout;
     31module_param(timeout, uint, 0);
     32MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
     33
     34static void dc_wdt_set(struct dc_wdt *wdt, u32 ticks)
     35{
     36	unsigned long flags;
     37
     38	spin_lock_irqsave(&wdt->lock, flags);
     39
     40	writel_relaxed(0, wdt->base + TIMER_A_CONTROL);
     41	writel_relaxed(ticks, wdt->base + TIMER_A_COUNT);
     42	writel_relaxed(TIMER_A_ENABLE_COUNT | TIMER_A_ENABLE_WATCHDOG,
     43		       wdt->base + TIMER_A_CONTROL);
     44
     45	spin_unlock_irqrestore(&wdt->lock, flags);
     46}
     47
     48static int dc_wdt_restart(struct watchdog_device *wdog, unsigned long action,
     49			  void *data)
     50{
     51	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
     52
     53	dc_wdt_set(wdt, 1);
     54	/* wait for reset to assert... */
     55	mdelay(500);
     56
     57	return 0;
     58}
     59
     60static int dc_wdt_start(struct watchdog_device *wdog)
     61{
     62	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
     63
     64	dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk));
     65
     66	return 0;
     67}
     68
     69static int dc_wdt_stop(struct watchdog_device *wdog)
     70{
     71	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
     72
     73	writel_relaxed(0, wdt->base + TIMER_A_CONTROL);
     74
     75	return 0;
     76}
     77
     78static int dc_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
     79{
     80	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
     81
     82	dc_wdt_set(wdt, t * clk_get_rate(wdt->clk));
     83	wdog->timeout = t;
     84
     85	return 0;
     86}
     87
     88static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog)
     89{
     90	struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
     91	uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT);
     92
     93	return count / clk_get_rate(wdt->clk);
     94}
     95
     96static const struct watchdog_ops dc_wdt_ops = {
     97	.owner		= THIS_MODULE,
     98	.start		= dc_wdt_start,
     99	.stop		= dc_wdt_stop,
    100	.set_timeout	= dc_wdt_set_timeout,
    101	.get_timeleft	= dc_wdt_get_timeleft,
    102	.restart        = dc_wdt_restart,
    103};
    104
    105static const struct watchdog_info dc_wdt_info = {
    106	.options	= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE
    107			| WDIOF_KEEPALIVEPING,
    108	.identity	= "Conexant Digicolor Watchdog",
    109};
    110
    111static struct watchdog_device dc_wdt_wdd = {
    112	.info		= &dc_wdt_info,
    113	.ops		= &dc_wdt_ops,
    114	.min_timeout	= 1,
    115};
    116
    117static int dc_wdt_probe(struct platform_device *pdev)
    118{
    119	struct device *dev = &pdev->dev;
    120	struct dc_wdt *wdt;
    121
    122	wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL);
    123	if (!wdt)
    124		return -ENOMEM;
    125
    126	wdt->base = devm_platform_ioremap_resource(pdev, 0);
    127	if (IS_ERR(wdt->base))
    128		return PTR_ERR(wdt->base);
    129
    130	wdt->clk = devm_clk_get(dev, NULL);
    131	if (IS_ERR(wdt->clk))
    132		return PTR_ERR(wdt->clk);
    133	dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk);
    134	dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout;
    135	dc_wdt_wdd.parent = dev;
    136
    137	spin_lock_init(&wdt->lock);
    138
    139	watchdog_set_drvdata(&dc_wdt_wdd, wdt);
    140	watchdog_set_restart_priority(&dc_wdt_wdd, 128);
    141	watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
    142	watchdog_stop_on_reboot(&dc_wdt_wdd);
    143	return devm_watchdog_register_device(dev, &dc_wdt_wdd);
    144}
    145
    146static const struct of_device_id dc_wdt_of_match[] = {
    147	{ .compatible = "cnxt,cx92755-wdt", },
    148	{},
    149};
    150MODULE_DEVICE_TABLE(of, dc_wdt_of_match);
    151
    152static struct platform_driver dc_wdt_driver = {
    153	.probe		= dc_wdt_probe,
    154	.driver = {
    155		.name =		"digicolor-wdt",
    156		.of_match_table = dc_wdt_of_match,
    157	},
    158};
    159module_platform_driver(dc_wdt_driver);
    160
    161MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
    162MODULE_DESCRIPTION("Driver for Conexant Digicolor watchdog timer");
    163MODULE_LICENSE("GPL");