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