1 /* 2 * Hisilicon SoC reset code 3 * 4 * Copyright (c) 2014 Hisilicon Ltd. 5 * Copyright (c) 2014 Linaro Ltd. 6 * 7 * Author: Haojian Zhuang <haojian.zhuang@linaro.org> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/delay.h> 15 #include <linux/io.h> 16 #include <linux/module.h> 17 #include <linux/notifier.h> 18 #include <linux/of_address.h> 19 #include <linux/platform_device.h> 20 #include <linux/reboot.h> 21 22 #include <asm/proc-fns.h> 23 24 static void __iomem *base; 25 static u32 reboot_offset; 26 27 static int hisi_restart_handler(struct notifier_block *this, 28 unsigned long mode, void *cmd) 29 { 30 writel_relaxed(0xdeadbeef, base + reboot_offset); 31 32 while (1) 33 cpu_do_idle(); 34 35 return NOTIFY_DONE; 36 } 37 38 static struct notifier_block hisi_restart_nb = { 39 .notifier_call = hisi_restart_handler, 40 .priority = 128, 41 }; 42 43 static int hisi_reboot_probe(struct platform_device *pdev) 44 { 45 struct device_node *np = pdev->dev.of_node; 46 int err; 47 48 base = of_iomap(np, 0); 49 if (!base) { 50 WARN(1, "failed to map base address"); 51 return -ENODEV; 52 } 53 54 if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) { 55 pr_err("failed to find reboot-offset property\n"); 56 return -EINVAL; 57 } 58 59 err = register_restart_handler(&hisi_restart_nb); 60 if (err) 61 dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", 62 err); 63 64 return err; 65 } 66 67 static const struct of_device_id hisi_reboot_of_match[] = { 68 { .compatible = "hisilicon,sysctrl" }, 69 {} 70 }; 71 72 static struct platform_driver hisi_reboot_driver = { 73 .probe = hisi_reboot_probe, 74 .driver = { 75 .name = "hisi-reboot", 76 .of_match_table = hisi_reboot_of_match, 77 }, 78 }; 79 module_platform_driver(hisi_reboot_driver); 80