blob: 72f276863819fdce363a6c4dfc87b3f5538c9fc9 [file] [log] [blame]
Benjamin Doron289a67d2019-09-22 17:33:12 +10001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <arch/io.h>
4#include <ec/acpi/ec.h>
5#include "include/ec.h"
6
7/*
8 * Notes:
9 * - ACPI "CMDB": Writing to this offset is equivalent to sending commands.
10 * The CMDx bytes contain the command parameters.
11 *
12 * TODO - Implement:
13 * - Commands: 0x58, 0xE1 and 0xE2
14 * - 0x51, 0x52: EC flash write?
15 * - ACPI CMDB: 0x63 and 0x64, 0xC7
16 * - 0x0B: Flash lock/write (Set offset 0x0B?)
17 * - Key/recovery detection?
18 *
19 * Vendor's protocols:
20 * - Only read and write are used.
21 * - Query, ACPI "CMDB" processing and command 58 are unused.
22 * - Equivalent KbcPeim is an unused PPI.
23 *
24 * NB: Also look for potential EC library
25 */
26
27#define EC_INDEX_IO_PORT 0x1200
28#define EC_INDEX_IO_HIGH_ADDR_PORT (EC_INDEX_IO_PORT + 1)
29#define EC_INDEX_IO_LOW_ADDR_PORT (EC_INDEX_IO_PORT + 2)
30#define EC_INDEX_IO_DATA_PORT (EC_INDEX_IO_PORT + 3)
31
32uint8_t ec_cmd_90_read(uint8_t addr)
33{
34 /* EC ports: 0x62/0x66 */
35 send_ec_command(0x90);
36 send_ec_data(addr);
37 return recv_ec_data();
38}
39
40void ec_cmd_91_write(uint8_t addr, uint8_t data)
41{
42 /* EC ports: 0x62/0x66 */
43 send_ec_command(0x91);
44 send_ec_data(addr);
45 send_ec_data(data);
46}
47
48uint8_t ec_cmd_94_query(void)
49{
50 send_ec_command(0x94);
51 return recv_ec_data();
52}
53
54uint8_t ec_idx_read(uint16_t addr)
55{
Elyes Haouas486240f2022-11-18 15:21:03 +010056 outb((uint8_t)(addr >> 8), EC_INDEX_IO_HIGH_ADDR_PORT);
57 outb((uint8_t)addr, EC_INDEX_IO_LOW_ADDR_PORT);
Benjamin Doron289a67d2019-09-22 17:33:12 +100058 return inb(EC_INDEX_IO_DATA_PORT);
59}
60
61void ec_idx_write(uint16_t addr, uint8_t data)
62{
Elyes Haouas486240f2022-11-18 15:21:03 +010063 outb((uint8_t)(addr >> 8), EC_INDEX_IO_HIGH_ADDR_PORT);
64 outb((uint8_t)addr, EC_INDEX_IO_LOW_ADDR_PORT);
Benjamin Doron289a67d2019-09-22 17:33:12 +100065 outb(data, EC_INDEX_IO_DATA_PORT);
66}
67
68/* TODO: Check if ADC is valid. Are there 4, or actually 8 ADCs? */
69uint16_t read_ec_adc_converter(uint8_t adc)
70{
71 uint8_t adc_converters_enabled; // Contains some ADCs and some DACs
72 uint8_t idx_data;
73 uint16_t adc_data;
74
75 /* Backup enabled ADCs */
76 adc_converters_enabled = ec_idx_read(0xff15); // ADDAEN
77
78 /* Enable desired ADC in bitmask (not enabled by EC FW, not used by vendor FW) */
79 ec_idx_write(0xff15, adc_converters_enabled | ((1 << adc) & 0xf)); // ADDAEN
80
81 /* Sample the desired ADC in binary field; OR the start bit */
82 ec_idx_write(0xff18, ((adc << 1) & 0xf) | 1); // ADCTRL
83
84 /* Read the desired ADC */
85 idx_data = ec_idx_read(0xff19); // ADCDAT
86 adc_data = (idx_data << 2);
87 /* Lower 2-bits of 10-bit ADC are in high bits of next register */
88 idx_data = ec_idx_read(0xff1a); // ECIF
89 adc_data |= ((idx_data & 0xc0) >> 6);
90
91 /* Restore enabled ADCs */
92 ec_idx_write(0xff15, adc_converters_enabled); // ADDAEN
93
94 return adc_data;
95}