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

syscon-reboot.c (2526B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Generic Syscon Reboot Driver
      4 *
      5 * Copyright (c) 2013, Applied Micro Circuits Corporation
      6 * Author: Feng Kan <fkan@apm.com>
      7 */
      8#include <linux/delay.h>
      9#include <linux/io.h>
     10#include <linux/notifier.h>
     11#include <linux/mfd/syscon.h>
     12#include <linux/of_address.h>
     13#include <linux/of_device.h>
     14#include <linux/platform_device.h>
     15#include <linux/reboot.h>
     16#include <linux/regmap.h>
     17
     18struct syscon_reboot_context {
     19	struct regmap *map;
     20	u32 offset;
     21	u32 value;
     22	u32 mask;
     23	struct notifier_block restart_handler;
     24};
     25
     26static int syscon_restart_handle(struct notifier_block *this,
     27					unsigned long mode, void *cmd)
     28{
     29	struct syscon_reboot_context *ctx =
     30			container_of(this, struct syscon_reboot_context,
     31					restart_handler);
     32
     33	/* Issue the reboot */
     34	regmap_update_bits(ctx->map, ctx->offset, ctx->mask, ctx->value);
     35
     36	mdelay(1000);
     37
     38	pr_emerg("Unable to restart system\n");
     39	return NOTIFY_DONE;
     40}
     41
     42static int syscon_reboot_probe(struct platform_device *pdev)
     43{
     44	struct syscon_reboot_context *ctx;
     45	struct device *dev = &pdev->dev;
     46	int mask_err, value_err;
     47	int err;
     48
     49	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
     50	if (!ctx)
     51		return -ENOMEM;
     52
     53	ctx->map = syscon_regmap_lookup_by_phandle(dev->of_node, "regmap");
     54	if (IS_ERR(ctx->map)) {
     55		ctx->map = syscon_node_to_regmap(dev->parent->of_node);
     56		if (IS_ERR(ctx->map))
     57			return PTR_ERR(ctx->map);
     58	}
     59
     60	if (of_property_read_u32(pdev->dev.of_node, "offset", &ctx->offset))
     61		return -EINVAL;
     62
     63	value_err = of_property_read_u32(pdev->dev.of_node, "value", &ctx->value);
     64	mask_err = of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask);
     65	if (value_err && mask_err) {
     66		dev_err(dev, "unable to read 'value' and 'mask'");
     67		return -EINVAL;
     68	}
     69
     70	if (value_err) {
     71		/* support old binding */
     72		ctx->value = ctx->mask;
     73		ctx->mask = 0xFFFFFFFF;
     74	} else if (mask_err) {
     75		/* support value without mask*/
     76		ctx->mask = 0xFFFFFFFF;
     77	}
     78
     79	ctx->restart_handler.notifier_call = syscon_restart_handle;
     80	ctx->restart_handler.priority = 192;
     81	err = register_restart_handler(&ctx->restart_handler);
     82	if (err)
     83		dev_err(dev, "can't register restart notifier (err=%d)\n", err);
     84
     85	return err;
     86}
     87
     88static const struct of_device_id syscon_reboot_of_match[] = {
     89	{ .compatible = "syscon-reboot" },
     90	{}
     91};
     92
     93static struct platform_driver syscon_reboot_driver = {
     94	.probe = syscon_reboot_probe,
     95	.driver = {
     96		.name = "syscon-reboot",
     97		.of_match_table = syscon_reboot_of_match,
     98	},
     99};
    100builtin_platform_driver(syscon_reboot_driver);