blob: 99cae75035384baab81b96a583aaabde54912022 [file] [log] [blame]
Duncan Laurieb0bf2802018-10-15 02:18:03 +00001/*
2 * This file is part of the coreboot project.
3 *
Duncan Laurieb0bf2802018-10-15 02:18:03 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <console/console.h>
Duncan Laurie32346f02019-03-20 12:51:07 -070016#include <ec/acpi/ec.h>
Duncan Laurieb0bf2802018-10-15 02:18:03 +000017#include <stdint.h>
18#include <string.h>
19
20#include "ec.h"
21#include "commands.h"
22
23int wilco_ec_get_info(enum get_ec_info_cmd type, char *info)
24{
25 struct ec_response_get_ec_info rsp;
26
27 if (!info)
28 return -1;
29 if (wilco_ec_sendrecv(KB_EC_INFO, type, &rsp, sizeof(rsp)) < 0)
30 return -1;
31
32 /* Copy returned string */
33 strncpy(info, rsp.data, sizeof(rsp.data));
34 return 0;
35}
36
37void wilco_ec_print_all_info(void)
38{
39 char info[EC_INFO_MAX_SIZE];
40
41 if (!wilco_ec_get_info(GET_EC_LABEL, info))
42 printk(BIOS_INFO, "EC Label : %s\n", info);
43
44 if (!wilco_ec_get_info(GET_EC_SVN_REV, info))
45 printk(BIOS_INFO, "EC Revision : %s\n", info);
46
47 if (!wilco_ec_get_info(GET_EC_MODEL_NO, info))
48 printk(BIOS_INFO, "EC Model Num : %s\n", info);
49
50 if (!wilco_ec_get_info(GET_EC_BUILD_DATE, info))
51 printk(BIOS_INFO, "EC Build Date : %s\n", info);
52}
Duncan Laurie2f954922018-10-15 02:28:54 +000053
54static int wilco_ec_get_power_smi(struct ec_pm_event_state *pm)
55{
56 struct ec_response_power_smi {
57 uint8_t pm_event_1;
58 uint8_t pm_state_1;
59 uint8_t hotkey;
60 uint8_t pm_state_2;
61 uint8_t pm_state_3;
62 uint8_t pm_state_4;
63 uint8_t pm_state_5;
64 uint8_t pm_event_2;
65 uint8_t pm_state_6;
66 } __packed rsp;
67
68 if (!pm)
69 return -1;
70 if (wilco_ec_sendrecv_noargs(KB_POWER_SMI, &rsp, sizeof(rsp)) < 0)
71 return -1;
72
73 pm->event[0] = rsp.pm_event_1;
74 pm->event[1] = rsp.pm_event_2;
75 pm->state[0] = rsp.pm_state_1;
76 pm->state[1] = rsp.pm_state_2;
77 pm->state[2] = rsp.pm_state_3;
78 pm->state[3] = rsp.pm_state_4;
79 pm->state[4] = rsp.pm_state_5;
80 pm->state[5] = rsp.pm_state_6;
81 pm->hotkey = rsp.hotkey;
82
83 return 0;
84}
85
86static int wilco_ec_get_power_status(struct ec_pm_event_state *pm)
87{
88 struct ec_response_power_status {
89 uint8_t pm_state_1;
90 uint8_t pm_state_2;
91 uint8_t pm_state_3;
92 uint8_t pm_state_4;
93 uint8_t pm_state_5;
94 uint8_t ac_type_lsb;
95 uint8_t pm_state_6;
96 uint8_t pm_event_2;
97 uint8_t ac_type_msb;
98 } __packed rsp;
99
100 if (!pm)
101 return -1;
102 if (wilco_ec_sendrecv_noargs(KB_POWER_STATUS, &rsp, sizeof(rsp)) < 0)
103 return -1;
104
105 pm->hotkey = 0;
106 pm->event[0] = 0;
107 pm->event[1] = rsp.pm_event_2;
108 pm->state[0] = rsp.pm_state_1;
109 pm->state[1] = rsp.pm_state_2;
110 pm->state[2] = rsp.pm_state_3;
111 pm->state[3] = rsp.pm_state_4;
112 pm->state[4] = rsp.pm_state_5;
113 pm->state[5] = rsp.pm_state_6;
114 pm->ac_type = rsp.ac_type_msb << 8 | rsp.ac_type_lsb;
115
116 return 0;
117}
118
119int wilco_ec_get_pm(struct ec_pm_event_state *pm, bool clear)
120{
121 if (clear)
122 return wilco_ec_get_power_smi(pm);
123 else
124 return wilco_ec_get_power_status(pm);
125}
126
127int wilco_ec_get_lid_state(void)
128{
129 struct ec_pm_event_state pm;
130
131 if (wilco_ec_get_power_status(&pm) < 0)
132 return -1;
133
134 return !!(pm.state[0] & EC_PM1_LID_OPEN);
135}
136
Duncan Laurieb34de932019-04-10 18:43:56 -0700137int wilco_ec_get_board_id(uint8_t *id)
138{
139 return wilco_ec_mailbox(WILCO_EC_MSG_RAW, KB_BOARD_ID,
140 NULL, 0, id, sizeof(*id));
141}
142
Duncan Laurie2f954922018-10-15 02:28:54 +0000143void wilco_ec_slp_en(void)
144{
145 /* EC does not respond to this command */
146 if (wilco_ec_mailbox(WILCO_EC_MSG_NO_RESPONSE,
147 KB_SLP_EN, NULL, 0, NULL, 0) < 0)
148 printk(BIOS_ERR, "%s: command failed\n", __func__);
149}
150
151void wilco_ec_power_off(enum ec_power_off_reason reason)
152{
153 /* EC does not respond to this command */
154 if (wilco_ec_mailbox(WILCO_EC_MSG_NO_RESPONSE,
155 KB_POWER_OFF, &reason, 1, NULL, 0) < 0)
156 printk(BIOS_ERR, "%s: command failed\n", __func__);
157}
Duncan Laurie57f22f62018-11-17 12:17:04 -0700158
159int wilco_ec_radio_control(enum ec_radio radio, uint8_t state)
160{
Duncan Laurie35f95072019-05-23 14:48:29 -0700161 uint8_t radio_control[3] = { radio, RADIO_WRITE, state };
Duncan Laurie57f22f62018-11-17 12:17:04 -0700162
163 return wilco_ec_mailbox(WILCO_EC_MSG_DEFAULT, KB_RADIO_CONTROL,
164 radio_control, ARRAY_SIZE(radio_control),
165 NULL, 0);
166}
Lijian Zhaoa31872c2019-01-10 19:31:15 -0800167
168int wilco_ec_change_wake(uint8_t source, enum ec_wake_change change)
169{
170 uint8_t wake_source[3] = { change, source };
171
172 return wilco_ec_mailbox(WILCO_EC_MSG_DEFAULT, KB_ACPI_WAKEUP_CHANGE,
173 wake_source, ARRAY_SIZE(wake_source),
174 NULL, 0);
175}
Duncan Laurie32346f02019-03-20 12:51:07 -0700176
177int wilco_ec_signed_fw(void)
178{
179 ec_set_ports(CONFIG_EC_BASE_ACPI_COMMAND,
180 CONFIG_EC_BASE_ACPI_DATA);
181 return !!ec_read(EC_RAM_SIGNED_FW);
182}
Keith Short8ef67322019-05-10 11:49:24 -0600183
Keith Shortf41afde2019-05-10 11:52:55 -0600184struct err_code_entry {
185 uint8_t post_code;
186 enum ec_err_code ec_err;
187};
188
189/*
190 * Any post codes not listed in the post_code_err_map[] use default.
191 */
192static const enum ec_err_code default_ec_err = DLED_ROM;
193static const struct err_code_entry post_code_err_map[] = {
194 { .post_code = POST_RAM_FAILURE, .ec_err = DLED_MEMORY, },
195 { .post_code = POST_VIDEO_FAILURE, .ec_err = DLED_PANEL, },
196};
197
198/* Records the most recent post code during boot */
199static uint8_t wilco_ec_saved_post_code;
200
201void wilco_ec_save_post_code(uint8_t post_code)
Keith Short8ef67322019-05-10 11:49:24 -0600202{
Keith Shortf41afde2019-05-10 11:52:55 -0600203 wilco_ec_saved_post_code = post_code;
204}
205
206/* Send error code to the EC based on last saved post code */
207void die_notify(void)
208{
209 size_t i;
210 enum ec_err_code err_code = default_ec_err;
211
212 for (i = 0; i < ARRAY_SIZE(post_code_err_map); i++) {
213 if (post_code_err_map[i].post_code ==
214 wilco_ec_saved_post_code) {
215 err_code = post_code_err_map[i].ec_err;
216 break;
217 }
218 }
219
220 printk(BIOS_EMERG, "Fatal error: post_code 0x%02x, EC err 0x%02x\n",
221 wilco_ec_saved_post_code, err_code);
222
223 wilco_ec_mailbox(WILCO_EC_MSG_DEFAULT, KB_ERR_CODE,
224 &err_code, 1, NULL, 0);
Keith Short8ef67322019-05-10 11:49:24 -0600225}
Eric Laif74b6e32020-01-23 14:43:08 +0800226
227/*
228 * EC CPU ID data struct
229 * MBOX[2] = 0xFF
230 * MBOX[3] = CPUID_Low
231 * MBOX[4] = CPUID_Mid
232 * MBOX[5] = CPUID_High
233 * MBOX[6] = CPU_Core
234 * MBOX[7] = GPU_Core
235 * MBOX[8] = Reserved
236 */
237int wilco_ec_set_cpuid(uint32_t cpuid, uint8_t cpu_cores, uint8_t gpu_cores)
238{
239 uint8_t cpu_id[7] = {0}, i;
240
241 cpu_id[0] = 0xff;
242 for (i = 1; i < 4; i++) {
243 cpu_id[i] = cpuid & 0xff;
244 cpuid = cpuid >> 8;
245 }
246 cpu_id[4] = cpu_cores;
247 cpu_id[5] = gpu_cores;
248
249 return wilco_ec_mailbox(WILCO_EC_MSG_DEFAULT, KB_CPU_ID, cpu_id,
250 ARRAY_SIZE(cpu_id), NULL, 0);
251}