18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Board-specific reboot/shutdown routines
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Lemote Inc.
78c2ecf20Sopenharmony_ci * Author: Wu Zhangjin, wuzhangjin@gmail.com
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/io.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/bootinfo.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <loongson.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <cs5536/cs5536.h>
198c2ecf20Sopenharmony_ci#include "ec_kb3310b.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void reset_cpu(void)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	/*
248c2ecf20Sopenharmony_ci	 * reset cpu to full speed, this is needed when enabling cpu frequency
258c2ecf20Sopenharmony_ci	 * scalling
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	writel(readl(LOONGSON_CHIPCFG) | 0x7, LOONGSON_CHIPCFG);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* reset support for fuloong2f */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic void fl2f_reboot(void)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	reset_cpu();
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* send a reset signal to south bridge.
378c2ecf20Sopenharmony_ci	 *
388c2ecf20Sopenharmony_ci	 * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset
398c2ecf20Sopenharmony_ci	 * normally with this reset operation and it will not work in PMON, but
408c2ecf20Sopenharmony_ci	 * you can type halt command and then reboot, seems the hardware reset
418c2ecf20Sopenharmony_ci	 * logic not work normally.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	{
448c2ecf20Sopenharmony_ci		u32 hi, lo;
458c2ecf20Sopenharmony_ci		_rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo);
468c2ecf20Sopenharmony_ci		lo |= 0x00000001;
478c2ecf20Sopenharmony_ci		_wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo);
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void fl2f_shutdown(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	u32 hi, lo, val;
548c2ecf20Sopenharmony_ci	int gpio_base;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/* get gpio base */
578c2ecf20Sopenharmony_ci	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
588c2ecf20Sopenharmony_ci	gpio_base = lo & 0xff00;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* make cs5536 gpio13 output enable */
618c2ecf20Sopenharmony_ci	val = inl(gpio_base + GPIOL_OUT_EN);
628c2ecf20Sopenharmony_ci	val &= ~(1 << (16 + 13));
638c2ecf20Sopenharmony_ci	val |= (1 << 13);
648c2ecf20Sopenharmony_ci	outl(val, gpio_base + GPIOL_OUT_EN);
658c2ecf20Sopenharmony_ci	mmiowb();
668c2ecf20Sopenharmony_ci	/* make cs5536 gpio13 output low level voltage. */
678c2ecf20Sopenharmony_ci	val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13));
688c2ecf20Sopenharmony_ci	val |= (1 << (16 + 13));
698c2ecf20Sopenharmony_ci	outl(val, gpio_base + GPIOL_OUT_VAL);
708c2ecf20Sopenharmony_ci	mmiowb();
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* reset support for yeeloong2f and mengloong2f notebook */
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void ml2f_reboot(void)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	reset_cpu();
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* sending an reset signal to EC(embedded controller) */
808c2ecf20Sopenharmony_ci	ec_write(REG_RESET, BIT_RESET_ON);
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define yl2f89_reboot ml2f_reboot
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* menglong(7inches) laptop has different shutdown logic from 8.9inches */
868c2ecf20Sopenharmony_ci#define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d
878c2ecf20Sopenharmony_ci#define EC_SHUTDOWN_IO_PORT_LOW	 0xff2e
888c2ecf20Sopenharmony_ci#define EC_SHUTDOWN_IO_PORT_DATA 0xff2f
898c2ecf20Sopenharmony_ci#define REG_SHUTDOWN_HIGH	 0xFC
908c2ecf20Sopenharmony_ci#define REG_SHUTDOWN_LOW	 0x29
918c2ecf20Sopenharmony_ci#define BIT_SHUTDOWN_ON		 (1 << 1)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void ml2f_shutdown(void)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	u8 val;
968c2ecf20Sopenharmony_ci	u64 i;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH);
998c2ecf20Sopenharmony_ci	outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW);
1008c2ecf20Sopenharmony_ci	mmiowb();
1018c2ecf20Sopenharmony_ci	val = inb(EC_SHUTDOWN_IO_PORT_DATA);
1028c2ecf20Sopenharmony_ci	outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA);
1038c2ecf20Sopenharmony_ci	mmiowb();
1048c2ecf20Sopenharmony_ci	/* need enough wait here... how many microseconds needs? */
1058c2ecf20Sopenharmony_ci	for (i = 0; i < 0x10000; i++)
1068c2ecf20Sopenharmony_ci		delay();
1078c2ecf20Sopenharmony_ci	outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA);
1088c2ecf20Sopenharmony_ci	mmiowb();
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void yl2f89_shutdown(void)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	/* cpu-gpio0 output low */
1148c2ecf20Sopenharmony_ci	LOONGSON_GPIODATA &= ~0x00000001;
1158c2ecf20Sopenharmony_ci	/* cpu-gpio0 as output */
1168c2ecf20Sopenharmony_ci	LOONGSON_GPIOIE &= ~0x00000001;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_civoid mach_prepare_reboot(void)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	switch (mips_machtype) {
1228c2ecf20Sopenharmony_ci	case MACH_LEMOTE_FL2F:
1238c2ecf20Sopenharmony_ci	case MACH_LEMOTE_NAS:
1248c2ecf20Sopenharmony_ci	case MACH_LEMOTE_LL2F:
1258c2ecf20Sopenharmony_ci		fl2f_reboot();
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case MACH_LEMOTE_ML2F7:
1288c2ecf20Sopenharmony_ci		ml2f_reboot();
1298c2ecf20Sopenharmony_ci		break;
1308c2ecf20Sopenharmony_ci	case MACH_LEMOTE_YL2F89:
1318c2ecf20Sopenharmony_ci		yl2f89_reboot();
1328c2ecf20Sopenharmony_ci		break;
1338c2ecf20Sopenharmony_ci	default:
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_civoid mach_prepare_shutdown(void)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	switch (mips_machtype) {
1418c2ecf20Sopenharmony_ci	case MACH_LEMOTE_FL2F:
1428c2ecf20Sopenharmony_ci	case MACH_LEMOTE_NAS:
1438c2ecf20Sopenharmony_ci	case MACH_LEMOTE_LL2F:
1448c2ecf20Sopenharmony_ci		fl2f_shutdown();
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	case MACH_LEMOTE_ML2F7:
1478c2ecf20Sopenharmony_ci		ml2f_shutdown();
1488c2ecf20Sopenharmony_ci		break;
1498c2ecf20Sopenharmony_ci	case MACH_LEMOTE_YL2F89:
1508c2ecf20Sopenharmony_ci		yl2f89_shutdown();
1518c2ecf20Sopenharmony_ci		break;
1528c2ecf20Sopenharmony_ci	default:
1538c2ecf20Sopenharmony_ci		break;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci}
156