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
|
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
*
* 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; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <arch/io.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <southbridge/intel/bd82x6x/nvs.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <southbridge/intel/bd82x6x/me.h>
#include <northbridge/intel/sandybridge/sandybridge.h>
#include <cpu/intel/model_206ax/model_206ax.h>
#include <elog.h>
#include <ec/compal/ene932/ec.h>
#include "ec.h"
static u8 mainboard_smi_ec(void)
{
u8 src;
u32 pm1_cnt;
#if CONFIG_ELOG_GSMI
static int battery_critical_logged;
#endif
ec_kbc_write_cmd(0x56);
src = ec_kbc_read_ob();
printk(BIOS_DEBUG, "mainboard_smi_ec src: %x\n", src);
switch (src) {
case EC_BATTERY_CRITICAL:
#if CONFIG_ELOG_GSMI
if (!battery_critical_logged)
elog_add_event_byte(ELOG_TYPE_EC_EVENT,
EC_EVENT_BATTERY_CRITICAL);
battery_critical_logged = 1;
#endif
break;
case EC_LID_CLOSE:
printk(BIOS_DEBUG, "LID CLOSED, SHUTDOWN\n");
#if CONFIG_ELOG_GSMI
elog_add_event_byte(ELOG_TYPE_EC_EVENT, EC_EVENT_LID_CLOSED);
#endif
/* Go to S5 */
pm1_cnt = inl(smm_get_pmbase() + PM1_CNT);
pm1_cnt |= (0xf << 10);
outl(pm1_cnt, smm_get_pmbase() + PM1_CNT);
break;
}
return src;
}
void mainboard_smi_gpi(u32 gpi_sts)
{
u32 pm1_cnt;
printk(BIOS_DEBUG, "mainboard_smi_gpi: %x\n", gpi_sts);
if (gpi_sts & (1 << EC_SMI_GPI)) {
/* Process all pending events from EC */
while (mainboard_smi_ec() != EC_NO_EVENT);
}
else if (gpi_sts & (1 << EC_LID_GPI)) {
printk(BIOS_DEBUG, "LID CLOSED, SHUTDOWN\n");
#if CONFIG_ELOG_GSMI
elog_add_event_byte(ELOG_TYPE_EC_EVENT, EC_EVENT_LID_CLOSED);
#endif
/* Go to S5 */
pm1_cnt = inl(smm_get_pmbase() + PM1_CNT);
pm1_cnt |= (0xf << 10);
outl(pm1_cnt, smm_get_pmbase() + PM1_CNT);
}
}
void mainboard_smi_sleep(u8 slp_typ)
{
printk(BIOS_DEBUG, "mainboard_smi_sleep: %x\n", slp_typ);
/* Disable SCI and SMI events */
/* Clear pending events that may trigger immediate wake */
/* Enable wake events */
/* Tell the EC to Disable USB power */
if (smm_get_gnvs()->s3u0 == 0 && smm_get_gnvs()->s3u1 == 0) {
ec_kbc_write_cmd(0x45);
ec_kbc_write_ib(0xF2);
}
}
#define APMC_ACPI_EN 0xe1
#define APMC_ACPI_DIS 0x1e
int mainboard_smi_apmc(u8 apmc)
{
printk(BIOS_DEBUG, "mainboard_smi_apmc: %x\n", apmc);
switch (apmc) {
case APMC_ACPI_EN:
printk(BIOS_DEBUG, "APMC: ACPI_EN\n");
/* Clear all pending events */
/* EC cmd:59 data:E8 */
ec_kbc_write_cmd(0x59);
ec_kbc_write_ib(0xE8);
/* Set LID GPI to generate SCIs */
gpi_route_interrupt(EC_LID_GPI, GPI_IS_SCI);
break;
case APMC_ACPI_DIS:
printk(BIOS_DEBUG, "APMC: ACPI_DIS\n");
/* Clear all pending events */
/* EC cmd:59 data:e9 */
ec_kbc_write_cmd(0x59);
ec_kbc_write_ib(0xE9);
/* Set LID GPI to generate SMIs */
gpi_route_interrupt(EC_LID_GPI, GPI_IS_SMI);
break;
}
return 0;
}
|