blob: 7a85b8f769c5452d0db5e7e46cb6587d9b0a5abf [file] [log] [blame]
Michael Niewöhnere1e65cb2021-12-01 19:09:13 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <console/console.h>
4#include <delay.h>
5#include <device/mmio.h>
6#include <ec/acpi/ec.h>
7#include <swab.h>
8#include <timer.h>
9#include <types.h>
10
11#include "chip.h"
12#include "commands.h"
13#include "ec.h"
14
15#define ec_cmd send_ec_command
16#define ec_dat send_ec_data
17
18static void ec_fcmd(uint8_t fcmd)
19{
20 write8p(ECRAM + FCMD, fcmd);
21 ec_cmd(ECCMD_NOP);
22
23 /* EC sets FCMD = 0x00 on completion (FCMD = 0xfa on some commands) */
24 int time = wait_us(50000, read8p(ECRAM + FCMD) == 0x00 || read8p(ECRAM + FCMD) == 0xfa);
25 if (time)
26 printk(BIOS_DEBUG, "EC: FCMD 0x%02x completed after %d us\n", fcmd, time);
27 else
28 printk(BIOS_ERR, "EC: FCMD 0x%02x timed out\n", fcmd);
29}
30
31static void ec_recv_str(char *buf, size_t size)
32{
33 while (size--) {
34 *buf = recv_ec_data();
35 if (*buf == '$') { /* end mark */
36 *buf = '\0';
37 return;
38 }
39 buf++;
40 }
41
42 /* Truncate and discard the rest */
43 *--buf = '\0';
44 do {} while (recv_ec_data() != '$');
45 printk(BIOS_ERR, "EC: Received string longer than buffer. Data truncated.\n");
46}
47
48char *ec_read_model(void)
49{
50 static char model[10];
51
52 ec_cmd(ECCMD_READ_MODEL);
53 ec_recv_str(model, sizeof(model));
54
55 return model;
56}
57
58char *ec_read_fw_version(void)
59{
60 static char version[10] = "1.";
61
62 ec_cmd(ECCMD_READ_FW_VER);
63 ec_recv_str(version + 2, sizeof(version) - 2);
64
65 return version;
66}
67
68void ec_set_acpi_mode(bool state)
69{
70 ec_cmd(state ? ECCMD_ENABLE_ACPI_MODE : ECCMD_DISABLE_ACPI_MODE);
71 if (state)
72 ec_cmd(ECCMD_ENABLE_HOTKEYS);
73}
74
75void ec_set_enter_g3_in_s4s5(bool state)
76{
77 clrsetbits8p(ECRAM + 0x1e6, 1 << G3FG, state << G3FG);
78}
79
80void ec_set_aprd(void)
81{
82 setbits8p(ECRAM + 0x1eb, 1 << APRD);
83}
84
85/* To be called by a graphics driver, when detecting a dGPU */
86void ec_set_dgpu_present(bool state)
87{
88 clrsetbits8p(ECRAM + 0x1eb, 1 << DGPT, state << DGPT);
89}
90
91void ec_set_fn_win_swap(bool state)
92{
93 clrsetbits8p(ECRAM + ECKS, 1 << SWFN, state << SWFN);
94}
95
96void ec_set_ac_fan_always_on(bool state)
97{
98 clrsetbits8p(ECRAM + 0x1e6, 1 << FOAC, state << FOAC);
99}
100
101void ec_set_kbled_timeout(uint16_t timeout)
102{
103 printk(BIOS_DEBUG, "EC: set keyboard backlight timeout to %us\n", timeout);
104
105 write8p(ECRAM + FDAT, timeout ? 0xff : 0x00);
106 write16p(ECRAM + FBUF, swab16(timeout));
107 ec_fcmd(FCMD_SET_KBLED_TIMEOUT);
108}
109
110void ec_set_flexicharger(bool state, uint8_t start, uint8_t stop)
111{
112 printk(BIOS_DEBUG, "EC: set flexicharger: enabled=%d, start=%u%%, stop=%u%%\n",
113 state, start, stop);
114
115 if (!state) {
116 start = 0xff;
117 stop = 0xff;
118
119 } else if (start > 100 || stop > 100) {
120 printk(BIOS_ERR, "EC: invalid flexicharger settings: start/stop > 100%%\n");
121 return;
122
123 } else if (start >= stop) {
124 printk(BIOS_ERR, "EC: invalid flexicharger settings: start >= stop\n");
125 return;
126 }
127
128 write8p(ECRAM + FBF1, state << 1);
129 write8p(ECRAM + FBUF, start);
130 write8p(ECRAM + FDAT, stop);
131 ec_fcmd(FCMD_FLEXICHARGER);
132}
133
134void ec_set_camera_boot_state(enum camera_state state)
135{
136 if (state > CAMERA_STATE_KEEP) {
137 printk(BIOS_ERR,
138 "EC: invalid camera boot state %u. Keeping previous state.\n", state);
139 state = CAMERA_STATE_KEEP;
140 }
141
142 if (state == CAMERA_STATE_KEEP) {
143 /*
144 * The EC maintains the camera's state in RAM. However, it doesn't sync the GPIO
145 * on a concurrent boot. Thus, read the previous state from the EC and set the
146 * state and the GPIO by sending the state command even in the keep-case.
147 */
148 ec_cmd(ECCMD_GET_DEVICES_STATE);
149 state = recv_ec_data() & 1;
150 }
151
152 printk(BIOS_DEBUG, "EC: set camera: enabled=%u\n", state);
153
154 ec_dat(DEVICE_CAMERA | DEVICE_STATE(state));
155 ec_cmd(ECCMD_SET_INV_DEVICE_STATE);
156}
157
158void ec_set_tp_toggle_mode(uint8_t mode)
159{
160 switch (mode) {
161 case 0: /* CtrlAltF9 */
162 setbits8p(ECRAM + RINF, TP_TOGGLE_CTRLALTF9);
163 break;
164 case 1: /* KeycodeF7F8*/
165 clrbits8p(ECRAM + RINF, TP_TOGGLE_CTRLALTF9);
166 break;
167 }
168}