aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/loongson/lemote-2f/reset.c
blob: 980299dbeac3e4b30011e4ecd0fe9e12353da95d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* Board-specific reboot/shutdown routines
 *
 * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
 *
 * Copyright (C) 2009 Lemote Inc.
 * Author: Wu Zhangjin, wuzj@lemote.com
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 */

#include <linux/io.h>
#include <linux/delay.h>
#include <linux/types.h>

#include <asm/bootinfo.h>

#include <loongson.h>

#include <cs5536/cs5536.h>

static void reset_cpu(void)
{
	/*
	 * reset cpu to full speed, this is needed when enabling cpu frequency
	 * scalling
	 */
	LOONGSON_CHIPCFG0 |= 0x7;
}

/* reset support for fuloong2f */

static void fl2f_reboot(void)
{
	reset_cpu();

	/* send a reset signal to south bridge.
	 *
	 * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset
	 * normally with this reset operation and it will not work in PMON, but
	 * you can type halt command and then reboot, seems the hardware reset
	 * logic not work normally.
	 */
	{
		u32 hi, lo;
		_rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo);
		lo |= 0x00000001;
		_wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo);
	}
}

static void fl2f_shutdown(void)
{
	u32 hi, lo, val;
	int gpio_base;

	/* get gpio base */
	_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo);
	gpio_base = lo & 0xff00;

	/* make cs5536 gpio13 output enable */
	val = inl(gpio_base + GPIOL_OUT_EN);
	val &= ~(1 << (16 + 13));
	val |= (1 << 13);
	outl(val, gpio_base + GPIOL_OUT_EN);
	mmiowb();
	/* make cs5536 gpio13 output low level voltage. */
	val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13));
	val |= (1 << (16 + 13));
	outl(val, gpio_base + GPIOL_OUT_VAL);
	mmiowb();
}

/* reset support for yeeloong2f and mengloong2f notebook */

/*
 * The following registers are determined by the EC index configuration.
 * 1. fill the PORT_HIGH as EC register high part.
 * 2. fill the PORT_LOW as EC register low part.
 * 3. fill the PORT_DATA as EC register write data or get the data from it.
 */

#define	EC_IO_PORT_HIGH	0x0381
#define	EC_IO_PORT_LOW	0x0382
#define	EC_IO_PORT_DATA	0x0383
#define	REG_RESET_HIGH	0xF4	/* reset the machine auto-clear : rd/wr */
#define REG_RESET_LOW	0xEC
#define	BIT_RESET_ON	(1 << 0)

void ml2f_reboot(void)
{
	reset_cpu();

	/* sending an reset signal to EC(embedded controller) */
	outb(REG_RESET_HIGH, EC_IO_PORT_HIGH);
	outb(REG_RESET_LOW, EC_IO_PORT_LOW);
	mmiowb();
	outb(BIT_RESET_ON, EC_IO_PORT_DATA);
	mmiowb();
}

#define yl2f89_reboot ml2f_reboot

/* menglong(7inches) laptop has different shutdown logic from 8.9inches */
#define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d
#define EC_SHUTDOWN_IO_PORT_LOW	 0xff2e
#define EC_SHUTDOWN_IO_PORT_DATA 0xff2f
#define REG_SHUTDOWN_HIGH        0xFC
#define REG_SHUTDOWN_LOW         0x29
#define BIT_SHUTDOWN_ON          (1 << 1)

static void ml2f_shutdown(void)
{
	u8 val;
	u64 i;

	outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH);
	outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW);
	mmiowb();
	val = inb(EC_SHUTDOWN_IO_PORT_DATA);
	outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA);
	mmiowb();
	/* need enough wait here... how many microseconds needs? */
	for (i = 0; i < 0x10000; i++)
		delay();
	outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA);
	mmiowb();
}

static void yl2f89_shutdown(void)
{
	/* cpu-gpio0 output low */
	LOONGSON_GPIODATA &= ~0x00000001;
	/* cpu-gpio0 as output */
	LOONGSON_GPIOIE &= ~0x00000001;
}

void mach_prepare_reboot(void)
{
	switch (mips_machtype) {
	case MACH_LEMOTE_FL2F:
	case MACH_LEMOTE_NAS:
		fl2f_reboot();
		break;
	case MACH_LEMOTE_ML2F7:
		ml2f_reboot();
		break;
	case MACH_LEMOTE_YL2F89:
		yl2f89_reboot();
		break;
	default:
		break;
	}
}

void mach_prepare_shutdown(void)
{
	switch (mips_machtype) {
	case MACH_LEMOTE_FL2F:
	case MACH_LEMOTE_NAS:
		fl2f_shutdown();
		break;
	case MACH_LEMOTE_ML2F7:
		ml2f_shutdown();
		break;
	case MACH_LEMOTE_YL2F89:
		yl2f89_shutdown();
		break;
	default:
		break;
	}
}