blob: 591a52112e65d0f381c3654761f9d4f288d25c87 [file] [log] [blame]
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2008-2009 coresystems GmbH
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +010015 */
16
17#include <arch/io.h>
18#include <console/console.h>
19#include <cpu/x86/smm.h>
20#include "southbridge/intel/ibexpeak/nvs.h"
21#include "southbridge/intel/ibexpeak/pch.h"
Vladimir Serbinenko484a5bf2014-01-10 19:43:33 +010022#include "southbridge/intel/ibexpeak/me.h"
Alexander Couzens60d44dd02015-01-27 11:57:43 +010023#include <northbridge/intel/nehalem/nehalem.h>
Vladimir Serbinenko484a5bf2014-01-10 19:43:33 +010024#include <cpu/intel/model_2065x/model_2065x.h>
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +010025#include <ec/acpi/ec.h>
26#include <pc80/mc146818rtc.h>
27#include <ec/lenovo/h8/h8.h>
28#include <delay.h>
29#include "dock.h"
30#include "smi.h"
31
Kyösti Mälkki189f3ba2014-12-29 11:32:27 +020032#define GPE_EC_SCI 1
33#define GPE_EC_WAKE 13
34
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +010035static void mainboard_smm_init(void)
36{
37 printk(BIOS_DEBUG, "initializing SMI\n");
38 /* Enable 0x1600/0x1600 register pair */
39 ec_set_bit(0x00, 0x05);
40}
41
42int mainboard_io_trap_handler(int smif)
43{
44 static int smm_initialized;
45
46 if (!smm_initialized) {
47 mainboard_smm_init();
48 smm_initialized = 1;
49 }
50
51 switch (smif) {
52 case SMI_DOCK_CONNECT:
53 ec_clr_bit(0x03, 2);
54 udelay(250000);
55 dock_connect();
56 ec_set_bit(0x03, 2);
57 /* set dock LED to indicate status */
58 ec_write(0x0c, 0x09);
59 ec_write(0x0c, 0x88);
60 break;
61
62 case SMI_DOCK_DISCONNECT:
63 ec_clr_bit(0x03, 2);
64 dock_disconnect();
65 break;
66
67 default:
68 return 0;
69 }
70
71 /* On success, the IO Trap Handler returns 1
72 * On failure, the IO Trap Handler returns a value != 1 */
73 return 1;
74}
75
76static void mainboard_smi_brightness_up(void)
77{
78 u8 value;
79
80 if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) < 0xf0)
81 pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, (value + 0x10) | 0xf);
82}
83
84static void mainboard_smi_brightness_down(void)
85{
86 u8 value;
87
88 if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) > 0x10)
89 pci_write_config8(PCI_DEV(0, 2, 1), 0xf4,
90 (value - 0x10) & 0xf0);
91}
92
93static void mainboard_smi_handle_ec_sci(void)
94{
95 u8 status = inb(EC_SC);
96 u8 event;
97
98 if (!(status & EC_SCI_EVT))
99 return;
100
101 event = ec_query();
102 printk(BIOS_DEBUG, "EC event %02x\n", event);
103
104 switch (event) {
105 case 0x14:
106 /* brightness up */
107 mainboard_smi_brightness_up();
108 break;
109 case 0x15:
110 /* brightness down */
111 mainboard_smi_brightness_down();
112 break;
113 case 0x18:
114 /* Fn-F9 key */
115 case 0x27:
116 /* Power loss */
117 case 0x50:
118 /* Undock Key */
119 mainboard_io_trap_handler(SMI_DOCK_DISCONNECT);
120 break;
121 case 0x37:
122 case 0x58:
123 /* Dock Event */
124 mainboard_io_trap_handler(SMI_DOCK_CONNECT);
125 break;
126 default:
127 break;
128 }
129}
130
131void mainboard_smi_gpi(u32 gpi_sts)
132{
Kyösti Mälkki189f3ba2014-12-29 11:32:27 +0200133 if (gpi_sts & (1 << GPE_EC_SCI))
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100134 mainboard_smi_handle_ec_sci();
135}
136
Vladimir Serbinenko484a5bf2014-01-10 19:43:33 +0100137static int mainboard_finalized = 0;
138
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100139int mainboard_smi_apmc(u8 data)
140{
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100141 switch (data) {
Vladimir Serbinenko484a5bf2014-01-10 19:43:33 +0100142 case APM_CNT_FINALIZE:
143 printk(BIOS_DEBUG, "APMC: FINALIZE\n");
144 if (mainboard_finalized) {
145 printk(BIOS_DEBUG, "APMC#: Already finalized\n");
146 return 0;
147 }
148
149 intel_me_finalize_smm();
150 intel_pch_finalize_smm();
Alexander Couzens60d44dd02015-01-27 11:57:43 +0100151 intel_nehalem_finalize_smm();
Vladimir Serbinenko484a5bf2014-01-10 19:43:33 +0100152 intel_model_2065x_finalize_smm();
153
154 mainboard_finalized = 1;
155 break;
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100156 case APM_CNT_ACPI_ENABLE:
157 /* use 0x1600/0x1604 to prevent races with userspace */
158 ec_set_ports(0x1604, 0x1600);
159 /* route H8SCI to SCI */
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200160 gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SCI);
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100161 /* discard all events, and enable attention */
162 ec_write(0x80, 0x01);
163 break;
164 case APM_CNT_ACPI_DISABLE:
165 /* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't
166 provide a EC query function */
167 ec_set_ports(0x66, 0x62);
168 /* route H8SCI# to SMI */
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200169 gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SMI);
Vladimir Serbinenko9bf05de2013-11-14 19:11:19 +0100170 /* discard all events, and enable attention */
171 ec_write(0x80, 0x01);
172 break;
173 default:
174 break;
175 }
176 return 0;
177}
Vladimir Serbinenko8a57b392014-08-08 00:10:28 +0200178
179void mainboard_smi_sleep(u8 slp_typ)
180{
181 if (slp_typ == 3) {
182 u8 ec_wake = ec_read(0x32);
183 /* If EC wake events are enabled, enable wake on EC WAKE GPE. */
184 if (ec_wake & 0x14) {
Vladimir Serbinenko8a57b392014-08-08 00:10:28 +0200185 /* Redirect EC WAKE GPE to SCI. */
Kyösti Mälkkib85a87b2014-12-29 11:32:27 +0200186 gpi_route_interrupt(GPE_EC_WAKE, GPI_IS_SCI);
Vladimir Serbinenko8a57b392014-08-08 00:10:28 +0200187 }
188 }
189}