18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Hisilicon SoC reset code 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Hisilicon Ltd. 68c2ecf20Sopenharmony_ci * Copyright (c) 2014 Linaro Ltd. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Haojian Zhuang <haojian.zhuang@linaro.org> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/notifier.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/reboot.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/proc-fns.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic void __iomem *base; 228c2ecf20Sopenharmony_cistatic u32 reboot_offset; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int hisi_restart_handler(struct notifier_block *this, 258c2ecf20Sopenharmony_ci unsigned long mode, void *cmd) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci writel_relaxed(0xdeadbeef, base + reboot_offset); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci while (1) 308c2ecf20Sopenharmony_ci cpu_do_idle(); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return NOTIFY_DONE; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct notifier_block hisi_restart_nb = { 368c2ecf20Sopenharmony_ci .notifier_call = hisi_restart_handler, 378c2ecf20Sopenharmony_ci .priority = 128, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int hisi_reboot_probe(struct platform_device *pdev) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 438c2ecf20Sopenharmony_ci int err; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci base = of_iomap(np, 0); 468c2ecf20Sopenharmony_ci if (!base) { 478c2ecf20Sopenharmony_ci WARN(1, "failed to map base address"); 488c2ecf20Sopenharmony_ci return -ENODEV; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "reboot-offset", &reboot_offset) < 0) { 528c2ecf20Sopenharmony_ci pr_err("failed to find reboot-offset property\n"); 538c2ecf20Sopenharmony_ci iounmap(base); 548c2ecf20Sopenharmony_ci return -EINVAL; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci err = register_restart_handler(&hisi_restart_nb); 588c2ecf20Sopenharmony_ci if (err) { 598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", 608c2ecf20Sopenharmony_ci err); 618c2ecf20Sopenharmony_ci iounmap(base); 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return err; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic const struct of_device_id hisi_reboot_of_match[] = { 688c2ecf20Sopenharmony_ci { .compatible = "hisilicon,sysctrl" }, 698c2ecf20Sopenharmony_ci {} 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic struct platform_driver hisi_reboot_driver = { 738c2ecf20Sopenharmony_ci .probe = hisi_reboot_probe, 748c2ecf20Sopenharmony_ci .driver = { 758c2ecf20Sopenharmony_ci .name = "hisi-reboot", 768c2ecf20Sopenharmony_ci .of_match_table = hisi_reboot_of_match, 778c2ecf20Sopenharmony_ci }, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_cimodule_platform_driver(hisi_reboot_driver); 80