Michał Kopeć has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/82672?usp=email )
Change subject: ec/dasharo/ec: add Dasharo features ......................................................................
ec/dasharo/ec: add Dasharo features
- EC firmware update in ramstage - Setting battery thresholds - PEP hooks for S0ix - Remove unused keyboard backlight, OLED, FCMD
Change-Id: I5600487afcb0a4b261d9ff85e3b2c73535a23f3d Signed-off-by: Michał Kopeć michal.kopec@3mdeb.com --- M src/ec/dasharo/ec/Kconfig M src/ec/dasharo/ec/Makefile.mk A src/ec/dasharo/ec/acpi.h A src/ec/dasharo/ec/acpi/dasharo.asl M src/ec/dasharo/ec/acpi/ec.asl M src/ec/dasharo/ec/acpi/ec_ram.asl M src/ec/dasharo/ec/acpi/lid.asl D src/ec/dasharo/ec/acpi/s76.asl A src/ec/dasharo/ec/buttons.c A src/ec/dasharo/ec/commands.h M src/ec/dasharo/ec/dasharo_ec.c M src/ec/dasharo/ec/dasharo_ec.h D src/ec/dasharo/ec/smbios.c 13 files changed, 899 insertions(+), 307 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/72/82672/1
diff --git a/src/ec/dasharo/ec/Kconfig b/src/ec/dasharo/ec/Kconfig index 1a007fa..901d3ce 100644 --- a/src/ec/dasharo/ec/Kconfig +++ b/src/ec/dasharo/ec/Kconfig @@ -1,6 +1,7 @@ ## SPDX-License-Identifier: GPL-2.0-only
config EC_DASHARO_EC + select EC_ACPI bool help Dasharo EC @@ -15,7 +16,16 @@ bool default n
-config EC_DASHARO_EC_OLED +config EC_DASHARO_EC_UPDATE depends on EC_DASHARO_EC - bool + bool "Update the embedded controller firmware" default n + +config EC_DASHARO_EC_UPDATE_FILE + depends on EC_DASHARO_EC_UPDATE + string "Path to the EC update file" + default "ec.rom" + +config EC_DASHARO_EC_FLASH_SIZE + hex + default 0x20000 diff --git a/src/ec/dasharo/ec/Makefile.mk b/src/ec/dasharo/ec/Makefile.mk index 247bcd4..e3abf1d5 100644 --- a/src/ec/dasharo/ec/Makefile.mk +++ b/src/ec/dasharo/ec/Makefile.mk @@ -1,10 +1,14 @@ -## SPDX-License-Identifier: GPL-2.0-only +# SPDX-License-Identifier: GPL-2.0-only + ifeq ($(CONFIG_EC_DASHARO_EC),y)
all-y += dasharo_ec.c - -ramstage-y += smbios.c - +all-y += buttons.c smm-$(CONFIG_DEBUG_SMI) += dasharo_ec.c
+cbfs-files-$(CONFIG_EC_DASHARO_EC_UPDATE) += ec.rom +ec.rom-file :=$(call strip_quotes,$(CONFIG_EC_DASHARO_EC_UPDATE_FILE)) +ec.rom-compression := $(CBFS_COMPRESS_FLAG) +ec.rom-type := raw + endif diff --git a/src/ec/dasharo/ec/acpi.h b/src/ec/dasharo/ec/acpi.h new file mode 100644 index 0000000..35d7279 --- /dev/null +++ b/src/ec/dasharo/ec/acpi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef EC_DASHARO_EC_ACPI_H +#define EC_DASHARO_EC_ACPI_H + +#include <ec/acpi/ec.h> + +#define DASHARO_EC_REG_LSTE 0x03 +#define DASHARO_EC_REG_LSTE_LID_STATE 0x01 + +#define DASHARO_EC_REG_BATTERY_START_THRESHOLD 0xBC +#define DASHARO_EC_REG_BATTERY_STOP_THRESHOLD 0xBD + +int dasharo_ec_get_lid_state(void); + +enum bat_threshold_type { + BAT_THRESHOLD_START, + BAT_THRESHOLD_STOP +}; + +int dasharo_ec_get_bat_threshold(enum bat_threshold_type type); +void dasharo_ec_set_bat_threshold(enum bat_threshold_type type, uint8_t value); + +#endif /* EC_DASHARO_EC_ACPI_H */ diff --git a/src/ec/dasharo/ec/acpi/dasharo.asl b/src/ec/dasharo/ec/acpi/dasharo.asl new file mode 100644 index 0000000..a51a58f --- /dev/null +++ b/src/ec/dasharo/ec/acpi/dasharo.asl @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +// Notifications: +// 0x80 - hardware backlight toggle +// 0x81 - backlight toggle +// 0x82 - backlight down +// 0x83 - backlight up +// 0x84 - backlight color change +// 0x85 - OLED screen toggle +Device (DASH) { + Name (_HID, "DASHEC00") + Name (_UID, 0) + // Hide the device so that Windows does not warn about a missing driver. + Name (_STA, 0xB) + + Method (RSET, 0, Serialized) { + Debug = "DASH: RSET" + SAPL(0) + } + Method (INIT, 0, Serialized) { + Printf ("DASH: INIT") + RSET() + If (^^PCI0.LPCB.EC0.ECOK) { + // Set flags to use software control + ^^PCI0.LPCB.EC0.ECOS = 2 + Return (0) + } Else { + Return (1) + } + } + + Method (FINI, 0, Serialized) { + Printf ("DASH: FINI") + RSET() + If (^^PCI0.LPCB.EC0.ECOK) { + // Set flags to use hardware control + ^^PCI0.LPCB.EC0.ECOS = 1 + Return (0) + } Else { + Return (1) + } + } + + // Get Airplane LED + Method (GAPL, 0, Serialized) { + If (^^PCI0.LPCB.EC0.ECOK) { + If (^^PCI0.LPCB.EC0.AIRP & 0x40) { + Return (1) + } + } + Return (0) + } + + // Set Airplane LED + Method (SAPL, 1, Serialized) { + If (^^PCI0.LPCB.EC0.ECOK) { + If (Arg0) { + ^^PCI0.LPCB.EC0.AIRP |= 0x40 + } Else { + ^^PCI0.LPCB.EC0.AIRP &= 0xBF + } + } + } + + // Fan names + Method (NFAN, 0, Serialized) { + Return (Package() { + "CPU fan", +#if CONFIG(EC_DASHARO_EC_DGPU) + "GPU fan", +#endif + }) + } + + // Get fan duty cycle and RPM as a single value + Method (GFAN, 1, Serialized) { + Local0 = 0 + Local1 = 0 + If (^^PCI0.LPCB.EC0.ECOK) { + If (Arg0 == 0) { + Local0 = ^^PCI0.LPCB.EC0.DUT1 + Local1 = ^^PCI0.LPCB.EC0.RPM1 + } ElseIf (Arg0 == 1) { + Local0 = ^^PCI0.LPCB.EC0.DUT2 + Local1 = ^^PCI0.LPCB.EC0.RPM2 + } + } + If (Local1 != 0) { + // 60 * (EC frequency / 120) / 2 + Local1 = 2156250 / Local1 + } + Return ((Local1 << 8) | Local0) + } + + // Temperature names + Method (NTMP, 0, Serialized) { + Return (Package() { + "CPU temp", +#if CONFIG(EC_DASHARO_EC_DGPU) + "GPU temp", +#endif + }) + } + + // Get temperature + Method (GTMP, 1, Serialized) { + Local0 = 0; + If (^^PCI0.LPCB.EC0.ECOK) { + If (Arg0 == 0) { + Local0 = ^^PCI0.LPCB.EC0.TMP1 + } ElseIf (Arg0 == 1) { + Local0 = ^^PCI0.LPCB.EC0.TMP2 + } + } + Return (Local0) + } +} diff --git a/src/ec/dasharo/ec/acpi/ec.asl b/src/ec/dasharo/ec/acpi/ec.asl index e4fcdeb..063b23f 100644 --- a/src/ec/dasharo/ec/acpi/ec.asl +++ b/src/ec/dasharo/ec/acpi/ec.asl @@ -6,7 +6,7 @@ #include "buttons.asl" #include "hid.asl" #include "lid.asl" - #include "s76.asl" + #include "dasharo.asl" }
Device (_SB.PCI0.LPCB.EC0) @@ -36,7 +36,7 @@ { Printf ("EC: _REG %o %o", ToHexString(Arg0), ToHexString(Arg1)) If ((Arg0 == 0x03) && (Arg1 == 1)) { - // Enable hardware touchpad lock, airplane mode, and keyboard backlight keys + // Enable hardware touchpad lock and airplane mode keys ECOS = 1
// Enable software display brightness keys @@ -58,7 +58,7 @@ ECOK = Arg1
// Reset Dasharo Device - ^^^^S76D.RSET() + ^^^^DASH.RSET() } }
@@ -90,6 +90,23 @@ // Notify of changes Notify(^^^^AC, 0) Notify(^^^^BAT0, 0) + + // Reset Dasharo Device + ^^^^DASH.RSET() + } + } + + Method (S0IX, 1, Serialized) { + Printf ("EC: S0ix hook") + If (ECOK) { + S0XH = Arg0 + } + } + + Method (EDSX, 1, Serialized) { + Printf ("EC: Display hook") + If (ECOK) { + DSPH = Arg0 } }
@@ -101,9 +118,6 @@ Method (_Q0B, 0, NotSerialized) // Screen Toggle { Printf ("EC: Screen Toggle") -#if CONFIG(EC_DASHARO_EC_OLED) - Notify (^^^^S76D, 0x85) -#endif // CONFIG(EC_DASHARO_EC_OLED) }
Method (_Q0C, 0, NotSerialized) // Mute @@ -111,11 +125,6 @@ Printf ("EC: Mute") }
- Method (_Q0D, 0, NotSerialized) // Keyboard Backlight - { - Printf ("EC: Keyboard Backlight") - } - Method (_Q0E, 0, NotSerialized) // Volume Down { Printf ("EC: Volume Down") @@ -215,24 +224,7 @@ Method (_Q50, 0, NotSerialized) // Other Events { Local0 = OEM4 - If (Local0 == 0x8A) { - Printf ("EC: White Keyboard Backlight") - Notify (^^^^S76D, 0x80) - } ElseIf (Local0 == 0x9F) { - Printf ("EC: Color Keyboard Toggle") - Notify (^^^^S76D, 0x81) - } ElseIf (Local0 == 0x81) { - Printf ("EC: Color Keyboard Down") - Notify (^^^^S76D, 0x82) - } ElseIf (Local0 == 0x82) { - Printf ("EC: Color Keyboard Up") - Notify (^^^^S76D, 0x83) - } ElseIf (Local0 == 0x80) { - Printf ("EC: Color Keyboard Color Change") - Notify (^^^^S76D, 0x84) - } Else { - Printf ("EC: Other: %o", ToHexString(Local0)) - } + Printf ("EC: Other: %o", ToHexString(Local0)) }
#if CONFIG(EC_DASHARO_EC_BAT_THRESHOLDS) diff --git a/src/ec/dasharo/ec/acpi/ec_ram.asl b/src/ec/dasharo/ec/acpi/ec_ram.asl index cb5bcf1..0087377 100644 --- a/src/ec/dasharo/ec/acpi/ec_ram.asl +++ b/src/ec/dasharo/ec/acpi/ec_ram.asl @@ -45,11 +45,7 @@ Offset (0xD9), AIRP, 8, // Airplane mode LED WINF, 8, // Enable ACPI brightness controls - Offset (0xF8), - FCMD, 8, - FDAT, 8, - FBUF, 8, - FBF1, 8, - FBF2, 8, - FBF3, 8, + Offset (0xE0), + S0XH, 1, // S0ix hook + DSPH, 1, // Display hook } diff --git a/src/ec/dasharo/ec/acpi/lid.asl b/src/ec/dasharo/ec/acpi/lid.asl index 0a64341..45e646a 100644 --- a/src/ec/dasharo/ec/acpi/lid.asl +++ b/src/ec/dasharo/ec/acpi/lid.asl @@ -6,16 +6,16 @@ Name (_PRW, Package () { EC_GPE_SWI, 3 })
Method (_LID, 0, NotSerialized) { - Printf ("LID: _LID") + DEBUG = "LID: _LID" If (^^PCI0.LPCB.EC0.ECOK) { Return (^^PCI0.LPCB.EC0.LSTE) } Else { - Return (1) + Return (One) } }
Method (_PSW, 1, NotSerialized) { - Printf ("LID: _PSW: %o", ToHexString(Arg0)) + DEBUG = Concatenate("LID: _PSW: ", ToHexString(Arg0)) If (^^PCI0.LPCB.EC0.ECOK) { ^^PCI0.LPCB.EC0.LWKE = Arg0 } diff --git a/src/ec/dasharo/ec/acpi/s76.asl b/src/ec/dasharo/ec/acpi/s76.asl deleted file mode 100644 index f23f857..0000000 --- a/src/ec/dasharo/ec/acpi/s76.asl +++ /dev/null @@ -1,178 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -// Notifications: -// 0x80 - hardware backlight toggle -// 0x81 - backlight toggle -// 0x82 - backlight down -// 0x83 - backlight up -// 0x84 - backlight color change -// 0x85 - OLED screen toggle -Device (S76D) { - Name (_HID, "17761776") - Name (_UID, 0) - // Hide the device so that Windows does not warn about a missing driver. - Name (_STA, 0xB) - - Method (RSET, 0, Serialized) { - Printf ("S76D: RSET") - SAPL(0) - SKBB(0) - SKBC(0xFFFFFF) - } - - Method (INIT, 0, Serialized) { - Printf ("S76D: INIT") - RSET() - If (^^PCI0.LPCB.EC0.ECOK) { - // Set flags to use software control - ^^PCI0.LPCB.EC0.ECOS = 2 - Return (0) - } Else { - Return (1) - } - } - - Method (FINI, 0, Serialized) { - Printf ("S76D: FINI") - RSET() - If (^^PCI0.LPCB.EC0.ECOK) { - // Set flags to use hardware control - ^^PCI0.LPCB.EC0.ECOS = 1 - Return (0) - } Else { - Return (1) - } - } - - // Get Airplane LED - Method (GAPL, 0, Serialized) { - If (^^PCI0.LPCB.EC0.ECOK) { - If (^^PCI0.LPCB.EC0.AIRP & 0x40) { - Return (1) - } - } - Return (0) - } - - // Set Airplane LED - Method (SAPL, 1, Serialized) { - If (^^PCI0.LPCB.EC0.ECOK) { - If (Arg0) { - ^^PCI0.LPCB.EC0.AIRP |= 0x40 - } Else { - ^^PCI0.LPCB.EC0.AIRP &= 0xBF - } - } - } - - // Get Keyboard Backlight Kind - // 0 - No backlight - // 1 - White backlight - // 2 - RGB backlight - Method (GKBK, 0, Serialized) { - Local0 = 0 - If (^^PCI0.LPCB.EC0.ECOK) { - ^^PCI0.LPCB.EC0.FDAT = 2 - ^^PCI0.LPCB.EC0.FCMD = 0xCA - Local0 = ^^PCI0.LPCB.EC0.FBUF - } - Return (Local0) - } - - // Get Keyboard Brightness - Method (GKBB, 0, Serialized) { - Local0 = 0 - If (^^PCI0.LPCB.EC0.ECOK) { - ^^PCI0.LPCB.EC0.FDAT = 1 - ^^PCI0.LPCB.EC0.FCMD = 0xCA - Local0 = ^^PCI0.LPCB.EC0.FBUF - } - Return (Local0) - } - - // Set Keyboard Brightness - Method (SKBB, 1, Serialized) { - If (^^PCI0.LPCB.EC0.ECOK) { - ^^PCI0.LPCB.EC0.FDAT = 0 - ^^PCI0.LPCB.EC0.FBUF = Arg0 - ^^PCI0.LPCB.EC0.FCMD = 0xCA - } - } - - // Get Keyboard Color - Method (GKBC, 0, Serialized) { - Local0 = 0 - If (^^PCI0.LPCB.EC0.ECOK) { - ^^PCI0.LPCB.EC0.FDAT = 4 - ^^PCI0.LPCB.EC0.FCMD = 0xCA - Local0 = ^^PCI0.LPCB.EC0.FBUF - Local0 |= (^^PCI0.LPCB.EC0.FBF1) << 16 - Local0 |= (^^PCI0.LPCB.EC0.FBF2) << 8 - } - Return (Local0) - } - - // Set Keyboard Color - Method (SKBC, 1, Serialized) { - If (^^PCI0.LPCB.EC0.ECOK) { - ^^PCI0.LPCB.EC0.FDAT = 3 - ^^PCI0.LPCB.EC0.FBUF = (Arg0 & 0xFF) - ^^PCI0.LPCB.EC0.FBF1 = ((Arg0 >> 16) & 0xFF) - ^^PCI0.LPCB.EC0.FBF2 = ((Arg0 >> 8) & 0xFF) - ^^PCI0.LPCB.EC0.FCMD = 0xCA - } - } - - // Fan names - Method (NFAN, 0, Serialized) { - Return (Package() { - "CPU fan", -#if CONFIG(EC_DASHARO_EC_DGPU) - "GPU fan", -#endif - }) - } - - // Get fan duty cycle and RPM as a single value - Method (GFAN, 1, Serialized) { - Local0 = 0 - Local1 = 0 - If (^^PCI0.LPCB.EC0.ECOK) { - If (Arg0 == 0) { - Local0 = ^^PCI0.LPCB.EC0.DUT1 - Local1 = ^^PCI0.LPCB.EC0.RPM1 - } ElseIf (Arg0 == 1) { - Local0 = ^^PCI0.LPCB.EC0.DUT2 - Local1 = ^^PCI0.LPCB.EC0.RPM2 - } - } - If (Local1 != 0) { - // 60 * (EC frequency / 120) / 2 - Local1 = 2156250 / Local1 - } - Return ((Local1 << 8) | Local0) - } - - // Temperature names - Method (NTMP, 0, Serialized) { - Return (Package() { - "CPU temp", -#if CONFIG(EC_DASHARO_EC_DGPU) - "GPU temp", -#endif - }) - } - - // Get temperature - Method (GTMP, 1, Serialized) { - Local0 = 0; - If (^^PCI0.LPCB.EC0.ECOK) { - If (Arg0 == 0) { - Local0 = ^^PCI0.LPCB.EC0.TMP1 - } ElseIf (Arg0 == 1) { - Local0 = ^^PCI0.LPCB.EC0.TMP2 - } - } - Return (Local0) - } -} diff --git a/src/ec/dasharo/ec/buttons.c b/src/ec/dasharo/ec/buttons.c new file mode 100644 index 0000000..d5a5ef4 --- /dev/null +++ b/src/ec/dasharo/ec/buttons.c @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <ec/acpi/ec.h> + +#include "acpi.h" + +/** + * Return the state of lid switch. + * + * @return 1 if the lid is open. + */ +int dasharo_ec_get_lid_state(void) +{ + return ec_read(DASHARO_EC_REG_LSTE) & DASHARO_EC_REG_LSTE_LID_STATE; +} diff --git a/src/ec/dasharo/ec/commands.h b/src/ec/dasharo/ec/commands.h new file mode 100644 index 0000000..f44297f --- /dev/null +++ b/src/ec/dasharo/ec/commands.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <stdint.h> + +// SMFI commands + +// Indicates that EC is ready to accept commands +#define CMD_NONE 0 +// Probe for Dasharo EC protocol +#define CMD_PROBE 1 +// Read board string +#define CMD_BOARD 2 +// Read version string +#define CMD_VERSION 3 +// Write bytes to console +#define CMD_PRINT 4 +// Access SPI chip +#define CMD_SPI 5 +// Reset EC +#define CMD_RESET 6 +// Get fan speeds +#define CMD_FAN_GET 7 +// Set fan speeds +#define CMD_FAN_SET 8 +// Get keyboard map index +#define CMD_KEYMAP_GET 9 +// Set keyboard map index +#define CMD_KEYMAP_SET 10 +// Get LED value by index +#define CMD_LED_GET_VALUE 11 +// Set LED value by index +#define CMD_LED_SET_VALUE 12 +// Get LED color by index +#define CMD_LED_GET_COLOR 13 +// Set LED color by index +#define CMD_LED_SET_COLOR 14 +// Get LED matrix mode and speed +#define CMD_LED_GET_MODE 15 +// Set LED matrix mode and speed +#define CMD_LED_SET_MODE 16 +// Get key matrix state +#define CMD_MATRIX_GET 17 +// Save LED settings to ROM +#define CMD_LED_SAVE 18 +// Enable/disable no input mode +#define CMD_SET_NO_INPUT 19 +// Set fan curve +#define CMD_FAN_CURVE_SET 20 +// Get security state +#define CMD_SECURITY_GET = 21, +// Set security state +#define CMD_SECURITY_SET = 22, +// Set camera enablement +#define CMD_CAMERA_ENABLEMENT_SET 23 +// Set WiFi + Bluetooth card enablement +#define CMD_WIFI_BT_ENABLEMENT_SET 24 +// Get a persistent option by index +#define CMD_OPTION_GET 25 +// Set a persistent option by index +#define CMD_OPTION_SET 26 + +// Print command. Registers are unique for each command +#define CMD_PRINT_REG_FLAGS 2 +#define CMD_PRINT_REG_LEN 3 +#define CMD_PRINT_REG_DATA 4 + +// SPI command +// Read from SPI chip if set, write otherwise +#define CMD_SPI_FLAG_READ BIT(0) +// Disable SPI chip after executing command +#define CMD_SPI_FLAG_DISABLE BIT(1) +// Run firmware from scratch RAM if necessary +#define CMD_SPI_FLAG_SCRATCH BIT(2) +// Write to backup ROM instead +#define CMD_SPI_FLAG_BACKUP BIT(3) + +#define CMD_LED_INDEX_ALL 0xFF + +// Persistent option definitions +enum { + OPT_POWER_ON_AC = 0, + NUM_OPTIONS +}; + +uint8_t dasharo_ec_smfi_cmd(uint8_t cmd, uint8_t len, uint8_t *data); +uint8_t dasharo_ec_read_version(uint8_t *data); +uint8_t dasharo_ec_read_board(uint8_t *data); diff --git a/src/ec/dasharo/ec/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c index 97c9613..985ee3b 100644 --- a/src/ec/dasharo/ec/dasharo_ec.c +++ b/src/ec/dasharo/ec/dasharo_ec.c @@ -1,31 +1,31 @@ /* SPDX-License-Identifier: GPL-2.0-only */
-#include "dasharo_ec.h" +#include <bootstate.h> #include <arch/io.h> -#include <console/dasharo_ec.h> -#include <console/console.h> +#include <cbfs.h> +#include <console/system76_ec.h> +#include <pc80/mc146818rtc.h> +#include <security/vboot/misc.h> +#include <security/vboot/vboot_common.h> #include <timer.h> +#include "acpi.h" +#include "commands.h" +#include "dasharo_ec.h"
// This is the command region for Dasharo EC firmware. It must be // enabled for LPC in the mainboard. #define DASHARO_EC_BASE 0x0E00 #define DASHARO_EC_SIZE 256
-#define REG_CMD 0 +#define SPI_SECTOR_SIZE 1024 + +#define REG_CMD 0 #define REG_RESULT 1 -#define REG_DATA 2 // Start of command data +#define REG_DATA 2 // Start of command data
// When command register is 0, command is complete #define CMD_FINISHED 0
-#define RESULT_OK 0 - -// Print command. Registers are unique for each command -#define CMD_PRINT 4 -#define CMD_PRINT_REG_FLAGS 2 -#define CMD_PRINT_REG_LEN 3 -#define CMD_PRINT_REG_DATA 4 - static inline uint8_t dasharo_ec_read(uint8_t addr) { return inb(DASHARO_EC_BASE + (uint16_t)addr); @@ -36,77 +36,600 @@ outb(data, DASHARO_EC_BASE + (uint16_t)addr); }
-void dasharo_ec_init(void) +uint8_t dasharo_ec_smfi_cmd(uint8_t cmd, uint8_t len, uint8_t *data) { - // Clear entire command region - for (int i = 0; i < DASHARO_EC_SIZE; i++) - dasharo_ec_write((uint8_t)i, 0); -} + int i;
-void dasharo_ec_flush(void) -{ - dasharo_ec_write(REG_CMD, CMD_PRINT); + if (len > DASHARO_EC_SIZE - 2) + return -1;
- // Wait for command completion, for up to 10 milliseconds, with a + // Wait for previous command completion, for up to 10 milliseconds, with a // test period of 1 microsecond wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED);
- dasharo_ec_write(CMD_PRINT_REG_LEN, 0); -} + // Write data first + for (i = 0; i < len; ++i) + dasharo_ec_write(REG_CMD + 2 + i, data[i]);
-void dasharo_ec_print(uint8_t byte) -{ - uint8_t len = dasharo_ec_read(CMD_PRINT_REG_LEN); - dasharo_ec_write(CMD_PRINT_REG_DATA + len, byte); - dasharo_ec_write(CMD_PRINT_REG_LEN, len + 1); - - // If we hit the end of the buffer, or were given a newline, flush - if (byte == '\n' || len >= (DASHARO_EC_SIZE - CMD_PRINT_REG_DATA)) - dasharo_ec_flush(); -} - -bool dasharo_ec_cmd(uint8_t cmd, const uint8_t *request_data, - uint8_t request_size, uint8_t *reply_data, uint8_t reply_size) -{ - if (request_size > DASHARO_EC_SIZE - REG_DATA || - reply_size > DASHARO_EC_SIZE - REG_DATA) { - printk(BIOS_ERR, "EC command %d too long - request size %u, reply size %u\n", - cmd, request_size, reply_size); - return false; - } - - /* If any data were buffered by dasharo_ec_print(), flush it first */ - uint8_t buffered_len = dasharo_ec_read(CMD_PRINT_REG_LEN); - if (buffered_len > 0) - dasharo_ec_flush(); - - /* Write the data */ - uint8_t i; - for (i = 0; i < request_size; ++i) - dasharo_ec_write(REG_DATA + i, request_data[i]); - - /* Write the command */ + // Write command register, which starts command dasharo_ec_write(REG_CMD, cmd);
- /* Wait for the command to complete */ - bool ret = true; - int elapsed = wait_ms(1000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); - if (elapsed == 0) { - /* Timed out: fail the command, don't attempt to read a reply. */ - printk(BIOS_WARNING, "EC command %d timed out - request size %d, reply size %d\n", - cmd, request_size, reply_size); - ret = false; - } else { - /* Read the reply */ - for (i = 0; i < reply_size; ++i) - reply_data[i] = dasharo_ec_read(REG_DATA+i); - /* Check the reply status */ - ret = (dasharo_ec_read(REG_RESULT) == RESULT_OK); + // Wait for previous command completion, for up to 10 milliseconds, with a + // test period of 1 microsecond + wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); + + return (dasharo_ec_read(REG_RESULT)); +} + +uint8_t dasharo_ec_read_version(uint8_t *data) +{ + int i; + uint8_t result; + + if (!data) + return -1; + + // Wait for previous command completion, for up to 10 milliseconds, with a + // test period of 1 microsecond + wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); + + // Write command register, which starts command + dasharo_ec_write(REG_CMD, CMD_VERSION); + + // Wait for previous command completion, for up to 10 milliseconds, with a + // test period of 1 microsecond + wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); + + result = dasharo_ec_read(REG_RESULT); + + if (result != 0) + return result; + + // Read data bytes, index should be valid due to length test above + for (i = 0; i < (DASHARO_EC_SIZE - REG_DATA); i++) { + data[i] = dasharo_ec_read(REG_DATA + i); + if (data[i] == '\0') + break; }
- /* Reset the flags and length so we can buffer console prints again */ - dasharo_ec_write(CMD_PRINT_REG_FLAGS, 0); - dasharo_ec_write(CMD_PRINT_REG_LEN, 0); + return result; +} + +uint8_t dasharo_ec_read_board(uint8_t *data) +{ + int i; + uint8_t result; + + if (!data) + return -1; + + // Wait for previous command completion, for up to 10 milliseconds, with a + // test period of 1 microsecond + wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); + + // Write command register, which starts command + dasharo_ec_write(REG_CMD, CMD_BOARD); + + // Wait for previous command completion, for up to 10 milliseconds, with a + // test period of 1 microsecond + wait_us(10000, dasharo_ec_read(REG_CMD) == CMD_FINISHED); + + result = dasharo_ec_read(REG_RESULT); + + if (result != 0) + return result; + + // Read data bytes, index should be valid due to length test above + for (i = 0; i < (DASHARO_EC_SIZE - REG_DATA); i++) { + data[i] = dasharo_ec_read(REG_DATA + i); + if (data[i] == '\0') + break; + } + + return result; +} + +int dasharo_ec_get_bat_threshold(enum bat_threshold_type type) +{ + int ret = -1; + + switch (type) { + case BAT_THRESHOLD_START: + ret = ec_read(DASHARO_EC_REG_BATTERY_START_THRESHOLD); + break; + case BAT_THRESHOLD_STOP: + ret = ec_read(DASHARO_EC_REG_BATTERY_STOP_THRESHOLD); + break; + default: + break; + }
return ret; } + +void dasharo_ec_set_bat_threshold(enum bat_threshold_type type, uint8_t value) +{ + switch (type) { + case BAT_THRESHOLD_START: + ec_write(DASHARO_EC_REG_BATTERY_START_THRESHOLD, value); + break; + case BAT_THRESHOLD_STOP: + ec_write(DASHARO_EC_REG_BATTERY_STOP_THRESHOLD, value); + break; + default: + break; + } +} + +/* Ported from system76_ectool */ +static int firmware_str(char *data, int data_len, const char *key, char *dest, int dest_len) +{ + int data_i, key_i, ret_i; + int key_len = strlen(key); + + data_i = key_i = ret_i = 0; + + /* Locate the key */ + while (data_i < data_len && key_i < key_len) { + if (data[data_i] == key[key_i]) + key_i += 1; + else + key_i = 0; + data_i += 1; + } + + if (key_i < key_len) + return 0; + + while (data_i < data_len && ret_i < dest_len - 1 && data[data_i] != 0) + dest[ret_i++] = data[data_i++]; + + dest[ret_i] = '\0'; + + return ret_i; +} + +/* Reset the EC SPI bus */ +static uint8_t ec_spi_reset(void) +{ + uint8_t reset_cmd = CMD_SPI_FLAG_DISABLE | CMD_SPI_FLAG_SCRATCH; + + return dasharo_ec_smfi_cmd(CMD_SPI, 1, &reset_cmd); +} + +#define SPI_ACCESS_SIZE 252 + +/* + * Read len bytes from EC SPI bus into dest + * Returns 0 on success, <0 on error + */ +static int ec_spi_bus_read(uint8_t *dest, uint32_t len) +{ + uint32_t addr, i, rv; + + uint8_t read_cmd[2] = { + [0] = CMD_SPI_FLAG_READ | CMD_SPI_FLAG_SCRATCH, + [1] = 0, + }; + + for (addr = 0; addr + SPI_ACCESS_SIZE < len; addr += SPI_ACCESS_SIZE) { + read_cmd[1] = SPI_ACCESS_SIZE; + + if ((rv = dasharo_ec_smfi_cmd(CMD_SPI, ARRAY_SIZE(read_cmd), read_cmd))) + return -rv; + + if (dasharo_ec_read(REG_DATA + 1) != read_cmd[1]) + return -1; + + for (i = 0; i < read_cmd[1]; i++) + dest[addr + i] = dasharo_ec_read(REG_DATA + 2 + i); + } + + if (addr == len) + return 0; + + read_cmd[1] = len % SPI_ACCESS_SIZE; + + if ((rv = dasharo_ec_smfi_cmd(CMD_SPI, ARRAY_SIZE(read_cmd), read_cmd))) + return -rv; + + if (dasharo_ec_read(REG_DATA + 1) != read_cmd[1]) + return -1; + + for (i = 0; i < read_cmd[1]; i++) + dest[addr + i] = dasharo_ec_read(REG_DATA + 2 + i); + + return 0; +} + +/* + * Write len bytes from data to EC SPI bus + * Returns 0 on success, <0 on error + */ +static int ec_spi_bus_write(uint8_t *data, uint8_t len) +{ + uint32_t addr, i, rv; + uint8_t write_cmd[2] = { + [0] = CMD_SPI_FLAG_SCRATCH, + [1] = len, + }; + + for (addr = 0; addr + SPI_ACCESS_SIZE < len; addr += SPI_ACCESS_SIZE) { + write_cmd[1] = SPI_ACCESS_SIZE; + + for (i = 0; i < write_cmd[1]; ++i) + dasharo_ec_write(REG_DATA + 2 + i, data[addr + i]); + + if ((rv = dasharo_ec_smfi_cmd(CMD_SPI, ARRAY_SIZE(write_cmd), write_cmd))) + return -rv; + + if (dasharo_ec_read(REG_DATA + 1) != write_cmd[1]) + return -1; + } + + if (addr == len) + return 0; + + write_cmd[1] = len % SPI_ACCESS_SIZE; + + for (i = 0; i < write_cmd[1]; i++) + dasharo_ec_write(REG_DATA + 2 + i, data[addr + i]); + + if ((rv = dasharo_ec_smfi_cmd(CMD_SPI, ARRAY_SIZE(write_cmd), write_cmd))) + return -rv; + + if (dasharo_ec_read(REG_DATA + 1) != write_cmd[1]) + return -1; + + return 0; +} + +static int ec_spi_cmd_status(void) +{ + int rv; + uint8_t cmd; + + if ((rv = ec_spi_reset())) + return rv; + + cmd = 0x05; /* SPI Read Status */ + + if ((rv = ec_spi_bus_write(&cmd, 1))) + return rv; + + if ((rv = ec_spi_bus_read(&cmd, 1))) + return rv; + + return cmd; +} + +static int ec_spi_cmd_write_enable(void) +{ + int status, rv; + uint8_t cmd; + + if ((rv = ec_spi_reset())) + return rv; + + cmd = 0x06; /* SPI Write Enable */ + + if ((rv = ec_spi_bus_write(&cmd, 1))) + return rv; + + do { + status = ec_spi_cmd_status(); + } while (status > 0 && (status & 3) != 2); + + return 0; +} + +static int ec_spi_cmd_write_disable(void) +{ + int status, rv; + uint8_t cmd; + + if ((rv = ec_spi_reset())) + return rv; + + cmd = 0x04; /* SPI Write Disable */ + + if ((rv = ec_spi_bus_write(&cmd, 1))) + return rv; + + do { + status = ec_spi_cmd_status(); + } while (status > 0 && (status & 3) != 0); + + return 0; +} + +/* Erase a sector at addr. Returns 0 on success <0 on error. */ +static int ec_spi_erase_sector(uint32_t addr) +{ + int status, rv; + uint8_t buf[4] = { + [0] = 0xD7, /* SPI Sector Erase */ + [1] = (addr >> 16) & 0xFF, + [2] = (addr >> 8) & 0xFF, + [3] = addr & 0xFF, + }; + + if ((rv = ec_spi_cmd_write_enable())) + return rv; + + if ((rv = ec_spi_reset())) + return rv; + + if ((rv = ec_spi_bus_write(buf, 4))) + return rv; + + do { + status = ec_spi_cmd_status(); + } while (status > 0 && (status & 1) != 0); + + if ((rv = ec_spi_cmd_write_disable())) + return rv; + + return 0; +} + +/* + * Erase the entire chip sector by sector. + * Chip / bulk erase doesn't work on this hardware. + * Returns erased byte count on success and <0 on error. + */ +static int ec_spi_erase_chip(void) +{ + int rv; + uint32_t addr; + + for (addr = 0; addr < CONFIG_EC_DASHARO_EC_FLASH_SIZE; addr += SPI_SECTOR_SIZE) + if ((rv = ec_spi_erase_sector(addr))) + return rv; + + return addr; +} + +/* + * Program an entire chip with a given image. + * Returns written byte count on success and <0 on error. + */ +static int ec_spi_image_write(uint8_t *image, ssize_t size) +{ + int status, rv; + uint32_t addr; + uint8_t buf[6] = {0}; + + if ((rv = ec_spi_cmd_write_enable())) + return rv; + + /* SPI AAI Word Program */ + buf[0] = 0xAD; + + for (addr = 0; addr < size; addr += 2) { + if ((rv = ec_spi_reset())) + return rv; + + if (addr == 0) { + /* 1st cmd bytes 1,2,3 are the address */ + buf[4] = image[0]; + buf[5] = image[1]; + + rv = ec_spi_bus_write(buf, 6); + } else { + buf[1] = image[addr]; + buf[2] = image[addr + 1]; + + rv = ec_spi_bus_write(buf, 3); + } + + if (rv) + return rv; + + do { + status = ec_spi_cmd_status(); + } while (status > 0 && (status & 1) != 0); + } + + if ((rv = ec_spi_cmd_write_disable())) + return rv; + + return addr; +} + +/* Read a sector into dest. Returns 0 on success and <0 on error. */ +static int ec_spi_read_sector(uint8_t *dest, uint32_t addr) +{ + int rv; + uint8_t buf[5] = { + [0] = 0x0B, /* SPI Read */ + [1] = (addr >> 16) & 0xFF, + [2] = (addr >> 8) & 0xFF, + [3] = addr & 0xFF, + [4] = 0, + }; + + if ((rv = ec_spi_reset())) + return rv; + + if ((rv = ec_spi_bus_write(buf, 5))) + return rv; + + if ((rv = ec_spi_bus_read(dest, SPI_SECTOR_SIZE))) + return rv; + + return 0; +} + +/* Verify an image sector by sector. Returns 0 on success and <0 on error. */ +static int ec_spi_image_verify(uint8_t *image, ssize_t image_sz) +{ + uint8_t *sector; + uint32_t addr; + int rv; + + sector = malloc(SPI_SECTOR_SIZE); + if (!sector) + return -1; + rv = 0; + + for (addr = 0; + addr < CONFIG_EC_DASHARO_EC_FLASH_SIZE && addr + SPI_SECTOR_SIZE < image_sz; + addr += SPI_SECTOR_SIZE) { + if ((rv = ec_spi_read_sector(sector, addr))) + goto exit; + + if ((rv = -memcmp(sector, image + addr, SPI_SECTOR_SIZE))) + goto exit; + } + + if (addr == image_sz) + goto exit; + + if ((rv = ec_spi_read_sector(sector, addr))) + goto exit; + + if ((rv = -memcmp(sector, image + addr, image_sz % SPI_SECTOR_SIZE))) + goto exit; + +exit: + free(sector); + return rv; +} + +/* Sync the EC firmware with an image contained in CBFS. */ +static void dasharo_ec_fw_sync(void *unused) +{ + size_t image_sz; + char *image; + char img_board_str[64]; + char img_version_str[64]; + char cur_board_str[64]; + char cur_version_str[64]; + uint8_t smfi_cmd; + int rv; + + if (!CONFIG(EC_DASHARO_EC_UPDATE)) + return; + + if (vboot_recovery_mode_enabled()) { + printk(BIOS_DEBUG, "EC: skipping update in recovery mode.\n"); + return; + } + + image = malloc(CONFIG_EC_DASHARO_EC_FLASH_SIZE); + if (image == NULL) { + printk(BIOS_ERR, "EC: failed to allocate memory for update."); + return; + } + + if (!(image_sz = cbfs_load("ec.rom", image, CONFIG_EC_DASHARO_EC_FLASH_SIZE))) { + printk(BIOS_ERR, "EC: failed to load update from CBFS."); + goto cleanup; + } + + printk(BIOS_DEBUG, "EC: update found (%ld bytes)\n", image_sz); + + if (!image_sz || image_sz % 2 || image_sz > CONFIG_EC_DASHARO_EC_FLASH_SIZE) { + printk(BIOS_ERR, "EC: incorrect update size.\n"); + goto cleanup; + } + + if (!firmware_str(image, image_sz, "76EC_BOARD=", img_board_str, + ARRAY_SIZE(img_board_str))) { + printk(BIOS_ERR, "EC: could not determine update target board.\n"); + goto cleanup; + } + + if (!firmware_str(image, image_sz, "76EC_VERSION=", img_version_str, + ARRAY_SIZE(img_version_str))) { + printk(BIOS_ERR, "EC: could not determine update version.\n"); + goto cleanup; + } + + printk(BIOS_DEBUG, "EC: update target: %s\n", img_board_str); + printk(BIOS_DEBUG, "EC: update version: %s\n", img_version_str); + + dasharo_ec_read_board((uint8_t *)cur_board_str); + dasharo_ec_read_version((uint8_t *)cur_version_str); + + if (strcmp(img_board_str, cur_board_str)) { + printk(BIOS_ERR, "EC: update target mismatch detected! Found %s, expected %s\n", + img_board_str, cur_board_str); + goto cleanup; + } + + printk(BIOS_DEBUG, "EC: current version: %s\n", cur_version_str); + if (!strcmp(img_version_str, cur_version_str)) { + printk(BIOS_DEBUG, "EC: update not needed.\n"); + goto cleanup; + } else { + printk(BIOS_INFO, "EC: update required!\n"); + } + + if ((ec_read(0x10) & 0x01) != 0x01) { + printk(BIOS_WARNING, "EC: AC adapter not connected, skipping update.\n"); + if (CONFIG(VBOOT)) + vboot_fail_and_reboot(vboot_get_context(), + VB2_RECOVERY_EC_SOFTWARE_SYNC, + EC_UPDATE_ERR_NO_AC); + goto cleanup; + } + + smfi_cmd = CMD_SPI_FLAG_SCRATCH; + if (dasharo_ec_smfi_cmd(CMD_SPI, 1, &smfi_cmd)) { + printk(BIOS_ERR, "EC: failed to jump to scratch ROM!\n"); + if (CONFIG(VBOOT)) + vboot_fail_and_reboot(vboot_get_context(), + VB2_RECOVERY_EC_SOFTWARE_SYNC, + EC_UPDATE_ERR_SCRATCH); + goto cleanup; + } + + rv = ec_spi_erase_chip(); + if (rv < 0) { + printk(BIOS_CRIT, "EC: erase failed!\n"); + if (CONFIG(VBOOT)) + vboot_fail_and_reboot(vboot_get_context(), + VB2_RECOVERY_EC_SOFTWARE_SYNC, + EC_UPDATE_ERR_ERASE); + goto cleanup; + } + printk(BIOS_DEBUG, "EC: erased %d bytes\n", rv); + + rv = ec_spi_image_write((uint8_t *)image, image_sz); + if (rv < 0) { + printk(BIOS_ALERT, "EC: update failed!\n"); + if (CONFIG(VBOOT)) + vboot_fail_and_reboot(vboot_get_context(), + VB2_RECOVERY_EC_SOFTWARE_SYNC, + EC_UPDATE_ERR_PROGRAM); + goto cleanup; + } + printk(BIOS_DEBUG, "EC: wrote %d bytes\n", rv); + + rv = ec_spi_image_verify((uint8_t *)image, image_sz); + if (rv < 0) { + printk(BIOS_ALERT, "EC: update verification failed!\n"); + } else { + printk(BIOS_DEBUG, "EC: update verified.\n"); + } + + smfi_cmd = CMD_SPI_FLAG_DISABLE; + if (dasharo_ec_smfi_cmd(CMD_SPI, 1, &smfi_cmd)) { + printk(BIOS_ERR, "EC: failed to disable SPI bus!\n"); + goto cleanup; + } + + smfi_cmd = 0; + if (dasharo_ec_smfi_cmd(CMD_RESET, 1, &smfi_cmd)) { + printk(BIOS_ERR, "EC: failed to trigger reset!\n"); + goto cleanup; + } + +cleanup: + free(image); + return; +} + +BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, dasharo_ec_fw_sync, NULL); diff --git a/src/ec/dasharo/ec/dasharo_ec.h b/src/ec/dasharo/ec/dasharo_ec.h index f313b0d..d3fa1ab 100644 --- a/src/ec/dasharo/ec/dasharo_ec.h +++ b/src/ec/dasharo/ec/dasharo_ec.h @@ -11,7 +11,18 @@ * request_data can be NULL if request_size is 0. reply_data/reply_size are * the reply payload, reply_data can be NULL if reply_size is 0. */ -bool dasharo_ec_cmd(uint8_t cmd, const uint8_t *request_data, - uint8_t request_size, uint8_t *reply_data, uint8_t reply_size); +bool dasharo_ec_cmd(uint8_t cmd, const uint8_t *request_data, uint8_t request_size, + uint8_t *reply_data, uint8_t reply_size); + +enum ec_update_error { + /* AC adapter is not connected. */ + EC_UPDATE_ERR_NO_AC, + /* EC did not jump to scratch ROM */ + EC_UPDATE_ERR_SCRATCH, + /* EC erase failed */ + EC_UPDATE_ERR_ERASE, + /* Programming EC failed */ + EC_UPDATE_ERR_PROGRAM, +};
#endif diff --git a/src/ec/dasharo/ec/smbios.c b/src/ec/dasharo/ec/smbios.c deleted file mode 100644 index e55d5f0..0000000 --- a/src/ec/dasharo/ec/smbios.c +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#include <smbios.h> - -smbios_wakeup_type smbios_system_wakeup_type(void) -{ - // TODO: Read wake source from EC. - return SMBIOS_WAKEUP_TYPE_POWER_SWITCH; -}