18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 68c2ecf20Sopenharmony_ci * Copyright (C) 2013 John Crispin <john@phrozen.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/pm.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/reboot.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/mach-ralink/ralink_regs.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Reset Control */ 208c2ecf20Sopenharmony_ci#define SYSC_REG_RESET_CTRL 0x034 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define RSTCTL_RESET_PCI BIT(26) 238c2ecf20Sopenharmony_ci#define RSTCTL_RESET_SYSTEM BIT(0) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int ralink_assert_device(struct reset_controller_dev *rcdev, 268c2ecf20Sopenharmony_ci unsigned long id) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci u32 val; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (id < 8) 318c2ecf20Sopenharmony_ci return -1; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci val = rt_sysc_r32(SYSC_REG_RESET_CTRL); 348c2ecf20Sopenharmony_ci val |= BIT(id); 358c2ecf20Sopenharmony_ci rt_sysc_w32(val, SYSC_REG_RESET_CTRL); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return 0; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int ralink_deassert_device(struct reset_controller_dev *rcdev, 418c2ecf20Sopenharmony_ci unsigned long id) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci u32 val; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (id < 8) 468c2ecf20Sopenharmony_ci return -1; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci val = rt_sysc_r32(SYSC_REG_RESET_CTRL); 498c2ecf20Sopenharmony_ci val &= ~BIT(id); 508c2ecf20Sopenharmony_ci rt_sysc_w32(val, SYSC_REG_RESET_CTRL); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int ralink_reset_device(struct reset_controller_dev *rcdev, 568c2ecf20Sopenharmony_ci unsigned long id) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci ralink_assert_device(rcdev, id); 598c2ecf20Sopenharmony_ci return ralink_deassert_device(rcdev, id); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic const struct reset_control_ops reset_ops = { 638c2ecf20Sopenharmony_ci .reset = ralink_reset_device, 648c2ecf20Sopenharmony_ci .assert = ralink_assert_device, 658c2ecf20Sopenharmony_ci .deassert = ralink_deassert_device, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct reset_controller_dev reset_dev = { 698c2ecf20Sopenharmony_ci .ops = &reset_ops, 708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 718c2ecf20Sopenharmony_ci .nr_resets = 32, 728c2ecf20Sopenharmony_ci .of_reset_n_cells = 1, 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_civoid ralink_rst_init(void) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci reset_dev.of_node = of_find_compatible_node(NULL, NULL, 788c2ecf20Sopenharmony_ci "ralink,rt2880-reset"); 798c2ecf20Sopenharmony_ci if (!reset_dev.of_node) 808c2ecf20Sopenharmony_ci pr_err("Failed to find reset controller node"); 818c2ecf20Sopenharmony_ci else 828c2ecf20Sopenharmony_ci reset_controller_register(&reset_dev); 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void ralink_restart(char *command) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PCI)) { 888c2ecf20Sopenharmony_ci rt_sysc_m32(0, RSTCTL_RESET_PCI, SYSC_REG_RESET_CTRL); 898c2ecf20Sopenharmony_ci mdelay(50); 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci local_irq_disable(); 938c2ecf20Sopenharmony_ci rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL); 948c2ecf20Sopenharmony_ci unreachable(); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int __init mips_reboot_setup(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci _machine_restart = ralink_restart; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciarch_initcall(mips_reboot_setup); 105