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
|
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <ec/acpi/ec.h>
#include <swab.h>
#include <timer.h>
#include <types.h>
#include "chip.h"
#include "commands.h"
#include "ec.h"
#define ec_cmd send_ec_command
#define ec_dat send_ec_data
static void ec_fcmd(uint8_t fcmd)
{
write8p(ECRAM + FCMD, fcmd);
ec_cmd(ECCMD_NOP);
/* EC sets FCMD = 0x00 on completion (FCMD = 0xfa on some commands) */
int time = wait_us(50000, read8p(ECRAM + FCMD) == 0x00 || read8p(ECRAM + FCMD) == 0xfa);
if (time)
printk(BIOS_DEBUG, "EC: FCMD 0x%02x completed after %d us\n", fcmd, time);
else
printk(BIOS_ERR, "EC: FCMD 0x%02x timed out\n", fcmd);
}
static void ec_recv_str(char *buf, size_t size)
{
while (size--) {
*buf = recv_ec_data();
if (*buf == '$') { /* end mark */
*buf = '\0';
return;
}
buf++;
}
/* Truncate and discard the rest */
*--buf = '\0';
do {} while (recv_ec_data() != '$');
printk(BIOS_ERR, "EC: Received string longer than buffer. Data truncated.\n");
}
char *ec_read_model(void)
{
static char model[10];
ec_cmd(ECCMD_READ_MODEL);
ec_recv_str(model, sizeof(model));
return model;
}
char *ec_read_fw_version(void)
{
static char version[10] = "1.";
ec_cmd(ECCMD_READ_FW_VER);
ec_recv_str(version + 2, sizeof(version) - 2);
return version;
}
void ec_set_acpi_mode(bool state)
{
ec_cmd(state ? ECCMD_ENABLE_ACPI_MODE : ECCMD_DISABLE_ACPI_MODE);
if (state)
ec_cmd(ECCMD_ENABLE_HOTKEYS);
}
void ec_set_enter_g3_in_s4s5(bool state)
{
clrsetbits8p(ECRAM + 0x1e6, 1 << G3FG, state << G3FG);
}
void ec_set_aprd(void)
{
setbits8p(ECRAM + 0x1eb, 1 << APRD);
}
/* To be called by a graphics driver, when detecting a dGPU */
void ec_set_dgpu_present(bool state)
{
clrsetbits8p(ECRAM + 0x1eb, 1 << DGPT, state << DGPT);
}
void ec_set_fn_win_swap(bool state)
{
clrsetbits8p(ECRAM + ECKS, 1 << SWFN, state << SWFN);
}
void ec_set_ac_fan_always_on(bool state)
{
clrsetbits8p(ECRAM + 0x1e6, 1 << FOAC, state << FOAC);
}
void ec_set_kbled_timeout(uint16_t timeout)
{
printk(BIOS_DEBUG, "EC: set keyboard backlight timeout to %us\n", timeout);
write8p(ECRAM + FDAT, timeout ? 0xff : 0x00);
write16p(ECRAM + FBUF, swab16(timeout));
ec_fcmd(FCMD_SET_KBLED_TIMEOUT);
}
void ec_set_flexicharger(bool state, uint8_t start, uint8_t stop)
{
printk(BIOS_DEBUG, "EC: set flexicharger: enabled=%d, start=%u%%, stop=%u%%\n",
state, start, stop);
if (!state) {
start = 0xff;
stop = 0xff;
} else if (start > 100 || stop > 100) {
printk(BIOS_ERR, "EC: invalid flexicharger settings: start/stop > 100%%\n");
return;
} else if (start >= stop) {
printk(BIOS_ERR, "EC: invalid flexicharger settings: start >= stop\n");
return;
}
write8p(ECRAM + FBF1, state << 1);
write8p(ECRAM + FBUF, start);
write8p(ECRAM + FDAT, stop);
ec_fcmd(FCMD_FLEXICHARGER);
}
void ec_set_camera_boot_state(enum camera_state state)
{
if (state > CAMERA_STATE_KEEP) {
printk(BIOS_ERR,
"EC: invalid camera boot state %u. Keeping previous state.\n", state);
state = CAMERA_STATE_KEEP;
}
if (state == CAMERA_STATE_KEEP) {
/*
* The EC maintains the camera's state in RAM. However, it doesn't sync the GPIO
* on a concurrent boot. Thus, read the previous state from the EC and set the
* state and the GPIO by sending the state command even in the keep-case.
*/
ec_cmd(ECCMD_GET_DEVICES_STATE);
state = recv_ec_data() & 1;
}
printk(BIOS_DEBUG, "EC: set camera: enabled=%u\n", state);
ec_dat(DEVICE_CAMERA | DEVICE_STATE(state));
ec_cmd(ECCMD_SET_INV_DEVICE_STATE);
}
void ec_set_tp_toggle_mode(uint8_t mode)
{
switch (mode) {
case 0: /* CtrlAltF9 */
setbits8p(ECRAM + RINF, TP_TOGGLE_CTRLALTF9);
break;
case 1: /* KeycodeF7F8*/
clrbits8p(ECRAM + RINF, TP_TOGGLE_CTRLALTF9);
break;
}
}
|