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

keystone-reset.c (4244B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TI keystone reboot driver
      4 *
      5 * Copyright (C) 2014 Texas Instruments Incorporated. https://www.ti.com/
      6 *
      7 * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
      8 */
      9
     10#include <linux/io.h>
     11#include <linux/module.h>
     12#include <linux/notifier.h>
     13#include <linux/reboot.h>
     14#include <linux/regmap.h>
     15#include <linux/mfd/syscon.h>
     16#include <linux/of_platform.h>
     17
     18#define RSTYPE_RG			0x0
     19#define RSCTRL_RG			0x4
     20#define RSCFG_RG			0x8
     21#define RSISO_RG			0xc
     22
     23#define RSCTRL_KEY_MASK			0x0000ffff
     24#define RSCTRL_RESET_MASK		BIT(16)
     25#define RSCTRL_KEY			0x5a69
     26
     27#define RSMUX_OMODE_MASK		0xe
     28#define RSMUX_OMODE_RESET_ON		0xa
     29#define RSMUX_OMODE_RESET_OFF		0x0
     30#define RSMUX_LOCK_MASK			0x1
     31#define RSMUX_LOCK_SET			0x1
     32
     33#define RSCFG_RSTYPE_SOFT		0x300f
     34#define RSCFG_RSTYPE_HARD		0x0
     35
     36#define WDT_MUX_NUMBER			0x4
     37
     38static int rspll_offset;
     39static struct regmap *pllctrl_regs;
     40
     41/**
     42 * rsctrl_enable_rspll_write - enable access to RSCTRL, RSCFG
     43 * To be able to access to RSCTRL, RSCFG registers
     44 * we have to write a key before
     45 */
     46static inline int rsctrl_enable_rspll_write(void)
     47{
     48	return regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
     49				  RSCTRL_KEY_MASK, RSCTRL_KEY);
     50}
     51
     52static int rsctrl_restart_handler(struct notifier_block *this,
     53				  unsigned long mode, void *cmd)
     54{
     55	/* enable write access to RSTCTRL */
     56	rsctrl_enable_rspll_write();
     57
     58	/* reset the SOC */
     59	regmap_update_bits(pllctrl_regs, rspll_offset + RSCTRL_RG,
     60			   RSCTRL_RESET_MASK, 0);
     61
     62	return NOTIFY_DONE;
     63}
     64
     65static struct notifier_block rsctrl_restart_nb = {
     66	.notifier_call = rsctrl_restart_handler,
     67	.priority = 128,
     68};
     69
     70static const struct of_device_id rsctrl_of_match[] = {
     71	{.compatible = "ti,keystone-reset", },
     72	{},
     73};
     74MODULE_DEVICE_TABLE(of, rsctrl_of_match);
     75
     76static int rsctrl_probe(struct platform_device *pdev)
     77{
     78	int i;
     79	int ret;
     80	u32 val;
     81	unsigned int rg;
     82	u32 rsmux_offset;
     83	struct regmap *devctrl_regs;
     84	struct device *dev = &pdev->dev;
     85	struct device_node *np = dev->of_node;
     86
     87	if (!np)
     88		return -ENODEV;
     89
     90	/* get regmaps */
     91	pllctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-pll");
     92	if (IS_ERR(pllctrl_regs))
     93		return PTR_ERR(pllctrl_regs);
     94
     95	devctrl_regs = syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
     96	if (IS_ERR(devctrl_regs))
     97		return PTR_ERR(devctrl_regs);
     98
     99	ret = of_property_read_u32_index(np, "ti,syscon-pll", 1, &rspll_offset);
    100	if (ret) {
    101		dev_err(dev, "couldn't read the reset pll offset!\n");
    102		return -EINVAL;
    103	}
    104
    105	ret = of_property_read_u32_index(np, "ti,syscon-dev", 1, &rsmux_offset);
    106	if (ret) {
    107		dev_err(dev, "couldn't read the rsmux offset!\n");
    108		return -EINVAL;
    109	}
    110
    111	/* set soft/hard reset */
    112	val = of_property_read_bool(np, "ti,soft-reset");
    113	val = val ? RSCFG_RSTYPE_SOFT : RSCFG_RSTYPE_HARD;
    114
    115	ret = rsctrl_enable_rspll_write();
    116	if (ret)
    117		return ret;
    118
    119	ret = regmap_write(pllctrl_regs, rspll_offset + RSCFG_RG, val);
    120	if (ret)
    121		return ret;
    122
    123	/* disable a reset isolation for all module clocks */
    124	ret = regmap_write(pllctrl_regs, rspll_offset + RSISO_RG, 0);
    125	if (ret)
    126		return ret;
    127
    128	/* enable a reset for watchdogs from wdt-list */
    129	for (i = 0; i < WDT_MUX_NUMBER; i++) {
    130		ret = of_property_read_u32_index(np, "ti,wdt-list", i, &val);
    131		if (ret == -EOVERFLOW && !i) {
    132			dev_err(dev, "ti,wdt-list property has to contain at"
    133				"least one entry\n");
    134			return -EINVAL;
    135		} else if (ret) {
    136			break;
    137		}
    138
    139		if (val >= WDT_MUX_NUMBER) {
    140			dev_err(dev, "ti,wdt-list property can contain "
    141				"only numbers < 4\n");
    142			return -EINVAL;
    143		}
    144
    145		rg = rsmux_offset + val * 4;
    146
    147		ret = regmap_update_bits(devctrl_regs, rg, RSMUX_OMODE_MASK,
    148					 RSMUX_OMODE_RESET_ON |
    149					 RSMUX_LOCK_SET);
    150		if (ret)
    151			return ret;
    152	}
    153
    154	ret = register_restart_handler(&rsctrl_restart_nb);
    155	if (ret)
    156		dev_err(dev, "cannot register restart handler (err=%d)\n", ret);
    157
    158	return ret;
    159}
    160
    161static struct platform_driver rsctrl_driver = {
    162	.probe = rsctrl_probe,
    163	.driver = {
    164		.name = KBUILD_MODNAME,
    165		.of_match_table = rsctrl_of_match,
    166	},
    167};
    168module_platform_driver(rsctrl_driver);
    169
    170MODULE_AUTHOR("Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>");
    171MODULE_DESCRIPTION("Texas Instruments keystone reset driver");
    172MODULE_LICENSE("GPL v2");
    173MODULE_ALIAS("platform:" KBUILD_MODNAME);