1/* Board-specific reboot/shutdown routines
2 *
3 * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
4 *
5 * Copyright (C) 2009 Lemote Inc.
6 * Author: Wu Zhangjin, wuzhangjin@gmail.com
7 *
8 * This program is free software; you can redistribute	it and/or modify it
9 * under  the terms of	the GNU General	 Public License as published by the
10 * Free Software Foundation;  either version 2 of the  License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/io.h>
15#include <linux/delay.h>
16#include <linux/types.h>
17
18#include <asm/bootinfo.h>
19
20#include <loongson.h>
21
22#include <cs5536/cs5536.h>
23#include "ec_kb3310b.h"
24
25static void reset_cpu(void)
26{
27	/*
28	 * reset cpu to full speed, this is needed when enabling cpu frequency
29	 * scalling
30	 */
31	LOONGSON_CHIPCFG(0) |= 0x7;
32}
33
34/* reset support for fuloong2f */
35
36static void fl2f_reboot(void)
37{
38	reset_cpu();
39
40	/* send a reset signal to south bridge.
41	 *
42	 * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset
43	 * normally with this reset operation and it will not work in PMON, but
44	 * you can type halt command and then reboot, seems the hardware reset
45	 * logic not work normally.
46	 */
47	{
48		u32 hi, lo;
49		_rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo);
50		lo |= 0x00000001;
51		_wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo);
52	}
53}
54
55static void fl2f_shutdown(void)
56{
57	u32 hi, lo, val;
58	int gpio_base;
59
60	/* get gpio base */
61	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
62	gpio_base = lo & 0xff00;
63
64	/* make cs5536 gpio13 output enable */
65	val = inl(gpio_base + GPIOL_OUT_EN);
66	val &= ~(1 << (16 + 13));
67	val |= (1 << 13);
68	outl(val, gpio_base + GPIOL_OUT_EN);
69	mmiowb();
70	/* make cs5536 gpio13 output low level voltage. */
71	val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13));
72	val |= (1 << (16 + 13));
73	outl(val, gpio_base + GPIOL_OUT_VAL);
74	mmiowb();
75}
76
77/* reset support for yeeloong2f and mengloong2f notebook */
78
79static void ml2f_reboot(void)
80{
81	reset_cpu();
82
83	/* sending an reset signal to EC(embedded controller) */
84	ec_write(REG_RESET, BIT_RESET_ON);
85}
86
87#define yl2f89_reboot ml2f_reboot
88
89/* menglong(7inches) laptop has different shutdown logic from 8.9inches */
90#define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d
91#define EC_SHUTDOWN_IO_PORT_LOW	 0xff2e
92#define EC_SHUTDOWN_IO_PORT_DATA 0xff2f
93#define REG_SHUTDOWN_HIGH	 0xFC
94#define REG_SHUTDOWN_LOW	 0x29
95#define BIT_SHUTDOWN_ON		 (1 << 1)
96
97static void ml2f_shutdown(void)
98{
99	u8 val;
100	u64 i;
101
102	outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH);
103	outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW);
104	mmiowb();
105	val = inb(EC_SHUTDOWN_IO_PORT_DATA);
106	outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA);
107	mmiowb();
108	/* need enough wait here... how many microseconds needs? */
109	for (i = 0; i < 0x10000; i++)
110		delay();
111	outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA);
112	mmiowb();
113}
114
115static void yl2f89_shutdown(void)
116{
117	/* cpu-gpio0 output low */
118	LOONGSON_GPIODATA &= ~0x00000001;
119	/* cpu-gpio0 as output */
120	LOONGSON_GPIOIE &= ~0x00000001;
121}
122
123void mach_prepare_reboot(void)
124{
125	switch (mips_machtype) {
126	case MACH_LEMOTE_FL2F:
127	case MACH_LEMOTE_NAS:
128	case MACH_LEMOTE_LL2F:
129		fl2f_reboot();
130		break;
131	case MACH_LEMOTE_ML2F7:
132		ml2f_reboot();
133		break;
134	case MACH_LEMOTE_YL2F89:
135		yl2f89_reboot();
136		break;
137	default:
138		break;
139	}
140}
141
142void mach_prepare_shutdown(void)
143{
144	switch (mips_machtype) {
145	case MACH_LEMOTE_FL2F:
146	case MACH_LEMOTE_NAS:
147	case MACH_LEMOTE_LL2F:
148		fl2f_shutdown();
149		break;
150	case MACH_LEMOTE_ML2F7:
151		ml2f_shutdown();
152		break;
153	case MACH_LEMOTE_YL2F89:
154		yl2f89_shutdown();
155		break;
156	default:
157		break;
158	}
159}
160