162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology 562306a36Sopenharmony_ci * Author: Fuxin Zhang, zhangfx@lemote.com 662306a36Sopenharmony_ci * Copyright (C) 2009 Lemote, Inc. 762306a36Sopenharmony_ci * Author: Zhangjin Wu, wuzhangjin@gmail.com 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/pm.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/idle.h> 1362306a36Sopenharmony_ci#include <asm/reboot.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <loongson.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic inline void loongson_reboot(void) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci#ifndef CONFIG_CPU_JUMP_WORKAROUNDS 2062306a36Sopenharmony_ci ((void (*)(void))ioremap(LOONGSON_BOOT_BASE, 4)) (); 2162306a36Sopenharmony_ci#else 2262306a36Sopenharmony_ci void (*func)(void); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci func = (void *)ioremap(LOONGSON_BOOT_BASE, 4); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci __asm__ __volatile__( 2762306a36Sopenharmony_ci " .set noat \n" 2862306a36Sopenharmony_ci " jr %[func] \n" 2962306a36Sopenharmony_ci " .set at \n" 3062306a36Sopenharmony_ci : /* No outputs */ 3162306a36Sopenharmony_ci : [func] "r" (func)); 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void loongson_restart(char *command) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci /* do preparation for reboot */ 3862306a36Sopenharmony_ci mach_prepare_reboot(); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* reboot via jumping to boot base address */ 4162306a36Sopenharmony_ci loongson_reboot(); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void loongson_poweroff(void) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci mach_prepare_shutdown(); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * It needs a wait loop here, but mips/kernel/reset.c already calls 5062306a36Sopenharmony_ci * a generic delay loop, machine_hang(), so simply return. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci return; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void loongson_halt(void) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci pr_notice("\n\n** You can safely turn off the power now **\n\n"); 5862306a36Sopenharmony_ci while (1) { 5962306a36Sopenharmony_ci if (cpu_wait) 6062306a36Sopenharmony_ci cpu_wait(); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int __init mips_reboot_setup(void) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci _machine_restart = loongson_restart; 6762306a36Sopenharmony_ci _machine_halt = loongson_halt; 6862306a36Sopenharmony_ci pm_power_off = loongson_poweroff; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciarch_initcall(mips_reboot_setup); 74