summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ec/dasharo/ec/Kconfig21
-rw-r--r--src/ec/dasharo/ec/Makefile.mk10
-rw-r--r--src/ec/dasharo/ec/acpi/ac.asl22
-rw-r--r--src/ec/dasharo/ec/acpi/battery.asl248
-rw-r--r--src/ec/dasharo/ec/acpi/battery_thresholds.asl46
-rw-r--r--src/ec/dasharo/ec/acpi/buttons.asl13
-rw-r--r--src/ec/dasharo/ec/acpi/ec.asl241
-rw-r--r--src/ec/dasharo/ec/acpi/ec_ram.asl55
-rw-r--r--src/ec/dasharo/ec/acpi/hid.asl50
-rw-r--r--src/ec/dasharo/ec/acpi/lid.asl23
-rw-r--r--src/ec/dasharo/ec/acpi/s76.asl178
-rw-r--r--src/ec/dasharo/ec/dasharo_ec.c112
-rw-r--r--src/ec/dasharo/ec/dasharo_ec.h17
-rw-r--r--src/ec/dasharo/ec/smbios.c9
14 files changed, 1045 insertions, 0 deletions
diff --git a/src/ec/dasharo/ec/Kconfig b/src/ec/dasharo/ec/Kconfig
new file mode 100644
index 0000000000..1a007fa163
--- /dev/null
+++ b/src/ec/dasharo/ec/Kconfig
@@ -0,0 +1,21 @@
+## SPDX-License-Identifier: GPL-2.0-only
+
+config EC_DASHARO_EC
+ bool
+ help
+ Dasharo EC
+
+config EC_DASHARO_EC_BAT_THRESHOLDS
+ depends on EC_DASHARO_EC
+ bool
+ default y
+
+config EC_DASHARO_EC_DGPU
+ depends on EC_DASHARO_EC
+ bool
+ default n
+
+config EC_DASHARO_EC_OLED
+ depends on EC_DASHARO_EC
+ bool
+ default n
diff --git a/src/ec/dasharo/ec/Makefile.mk b/src/ec/dasharo/ec/Makefile.mk
new file mode 100644
index 0000000000..247bcd40ee
--- /dev/null
+++ b/src/ec/dasharo/ec/Makefile.mk
@@ -0,0 +1,10 @@
+## SPDX-License-Identifier: GPL-2.0-only
+ifeq ($(CONFIG_EC_DASHARO_EC),y)
+
+all-y += dasharo_ec.c
+
+ramstage-y += smbios.c
+
+smm-$(CONFIG_DEBUG_SMI) += dasharo_ec.c
+
+endif
diff --git a/src/ec/dasharo/ec/acpi/ac.asl b/src/ec/dasharo/ec/acpi/ac.asl
new file mode 100644
index 0000000000..66cf742dec
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/ac.asl
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Device (AC)
+{
+ Name (_HID, "ACPI0003" /* Power Source Device */)
+ Name (_PCL, Package (0x01) // _PCL: Power Consumer List
+ {
+ _SB
+ })
+
+ Name (ACFG, 1)
+
+ Method (_PSR, 0, NotSerialized) // _PSR: Power Source
+ {
+ Return (ACFG)
+ }
+
+ Method (_STA, 0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+}
diff --git a/src/ec/dasharo/ec/acpi/battery.asl b/src/ec/dasharo/ec/acpi/battery.asl
new file mode 100644
index 0000000000..106f3d1be0
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/battery.asl
@@ -0,0 +1,248 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Device (BAT0)
+{
+ Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */)
+ Name (_UID, 0)
+ Name (_PCL, Package (0x01) // _PCL: Power Consumer List
+ {
+ _SB
+ })
+ Name (BFCC, 0)
+ Method (_STA, 0, NotSerialized)
+ {
+ If (^^PCI0.LPCB.EC0.ECOK)
+ {
+ If (^^PCI0.LPCB.EC0.BAT0)
+ {
+ Return (0x1F)
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+ Else
+ {
+ Return (0x0F)
+ }
+ }
+
+ Name (PBIF, Package (0x0D)
+ {
+ 1, // 0 - Power Unit
+ 0xFFFFFFFF, // 1 - Design Capacity
+ 0xFFFFFFFF, // 2 - Last Full Charge Capacity
+ 1, // 3 - Battery Technology
+ 0xFFFFFFFF, // 4 - Design Voltage
+ 0, // 5 - Design Capacity of Warning
+ 0, // 6 - Design Capacity of Low
+ 0x40, // 7 - Battery Capacity Granularity 1
+ 0x40, // 8 - Battery Capacity Granularity 2
+ " ", // 9 - Model Number
+ " ", // 10 - Serial Number
+ " ", // 11 - Battery Type
+ " " // 12 - OEM Information
+ })
+ Method (IVBI, 0, NotSerialized)
+ {
+ PBIF [1] = 0xFFFFFFFF
+ PBIF [2] = 0xFFFFFFFF
+ PBIF [4] = 0xFFFFFFFF
+ PBIF [9] = " "
+ PBIF [10] = " "
+ PBIF [11] = " "
+ PBIF [12] = " "
+ BFCC = 0
+ }
+
+ Method (UPBI, 0, NotSerialized)
+ {
+ If (^^PCI0.LPCB.EC0.BAT0)
+ {
+ Local0 = (^^PCI0.LPCB.EC0.BDC0 & 0xFFFF)
+ PBIF [1] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BFC0 & 0xFFFF)
+ PBIF [2] = Local0
+ BFCC = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BDV0 & 0xFFFF)
+ PBIF [4] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BCW0 & 0xFFFF)
+ PBIF [5] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BCL0 & 0xFFFF)
+ PBIF [6] = Local0
+ PBIF [9] = "BAT"
+ PBIF [10] = "0001"
+ PBIF [11] = "LION"
+ PBIF [12] = "Notebook"
+ }
+ Else
+ {
+ IVBI ()
+ }
+ }
+
+ Method (_BIF, 0, NotSerialized) // _BIF: Battery Information
+ {
+ If (^^PCI0.LPCB.EC0.ECOK)
+ {
+ UPBI ()
+ }
+ Else
+ {
+ IVBI ()
+ }
+
+ Return (PBIF) /* \_SB_.BAT0.PBIF */
+ }
+
+ Name (PBIX, Package ()
+ {
+ 0, // 0 - Revision
+ 1, // 1 - Power Unit: mAh
+ 0xFFFFFFFF, // 2 - Design Capacity
+ 0xFFFFFFFF, // 3 - Last Full Charge Capacity
+ 1, // 4 - Battery Technology: Rechargeable
+ 0xFFFFFFFF, // 5 - Design Voltage
+ 0, // 6 - Design Capacity of Warning
+ 0, // 7 - Design Capacity of Low
+ 0, // 8 - Cycle Count
+ 98000, // 9 - Measurement Accuracy
+ 0xFFFFFFFF, // 10 - Max Sampling Time
+ 0xFFFFFFFF, // 11 - Min Sampling Time
+ 0xFFFFFFFF, // 12 - Max Averaging Interval
+ 0xFFFFFFFF, // 13 - Min Averaging Interval
+ 0x40, // 14 - Battery Capacity Granularity 1
+ 0x40, // 15 - Battery Capacity Granularity 2
+ " ", // 16 - Model Number
+ " ", // 17 - Serial Number
+ " ", // 18 - Battery Type
+ " " // 19 - OEM Information
+ })
+
+ Method (IVBX, 0, NotSerialized)
+ {
+ PBIX [2] = 0xFFFFFFFF
+ PBIX [3] = 0xFFFFFFFF
+ PBIX [5] = 0xFFFFFFFF
+ PBIX [16] = " "
+ PBIX [17] = " "
+ PBIX [18] = " "
+ PBIX [19] = " "
+ BFCC = 0
+ }
+
+ Method (UPBX, 0, NotSerialized)
+ {
+ If (^^PCI0.LPCB.EC0.BAT0)
+ {
+ Local0 = (^^PCI0.LPCB.EC0.BDC0 & 0xFFFF)
+ PBIX [2] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BFC0 & 0xFFFF)
+ PBIX [3] = Local0
+ BFCC = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BDV0 & 0xFFFF)
+ PBIX [5] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BCW0 & 0xFFFF)
+ PBIX [6] = Local0
+ Local0 = (^^PCI0.LPCB.EC0.BCL0 & 0xFFFF)
+ PBIX [7] = Local0
+ LOCAL0 = ^^PCI0.LPCB.EC0.CYC0
+ PBIX [8] = LOCAL0
+ PBIX [16] = "BAT"
+ PBIX [17] = "0001"
+ PBIX [18] = "LION"
+ PBIX [19] = "Notebook"
+ }
+ Else
+ {
+ IVBX ()
+ }
+ }
+
+ // _BIX: Battery Information Extended
+ Method (_BIX, 0, NotSerialized)
+ {
+ If (^^PCI0.LPCB.EC0.ECOK)
+ {
+ UPBX ()
+ }
+ Else
+ {
+ IVBX ()
+ }
+ Return (PBIX) /* \_SB_.BAT0.PBIX */
+ }
+
+ Name (PBST, Package (0x04)
+ {
+ 0, // 0 - Battery state
+ 0xFFFFFFFF, // 1 - Battery present rate
+ 0xFFFFFFFF, // 2 - Battery remaining capacity
+ 0xFFFFFFFF // 3 - Battery present voltage
+ })
+ Method (IVBS, 0, NotSerialized)
+ {
+ PBST [0] = 0
+ PBST [1] = 0xFFFFFFFF
+ PBST [2] = 0xFFFFFFFF
+ PBST [3] = 0xFFFFFFFF
+ }
+
+ Method (UPBS, 0, NotSerialized)
+ {
+ If (^^PCI0.LPCB.EC0.BAT0)
+ {
+ Local0 = 0
+ Local1 = 0
+ If (^^AC.ACFG)
+ {
+ If (((^^PCI0.LPCB.EC0.BST0 & 0x02) == 0x02))
+ {
+ Local0 |= 0x02
+ Local1 = (^^PCI0.LPCB.EC0.BPR0 & 0xFFFF)
+ }
+ }
+ Else
+ {
+ Local0 |= 1
+ Local1 = (^^PCI0.LPCB.EC0.BPR0 & 0xFFFF)
+ }
+
+ Local7 = (Local1 & 0x8000)
+ If ((Local7 == 0x8000))
+ {
+ Local1 ^= 0xFFFF
+ }
+
+ Local2 = (^^PCI0.LPCB.EC0.BRC0 & 0xFFFF)
+ Local3 = (^^PCI0.LPCB.EC0.BPV0 & 0xFFFF)
+ PBST [0] = Local0
+ PBST [1] = Local1
+ PBST [2] = Local2
+ PBST [3] = Local3
+ If ((BFCC != ^^PCI0.LPCB.EC0.BFC0))
+ {
+ Notify (BAT0, 0x81) // Information Change
+ }
+ }
+ Else
+ {
+ IVBS ()
+ }
+ }
+
+ Method (_BST, 0, NotSerialized) // _BST: Battery Status
+ {
+ If (^^PCI0.LPCB.EC0.ECOK)
+ {
+ UPBS ()
+ }
+ Else
+ {
+ IVBS ()
+ }
+
+ Return (PBST) /* \_SB_.BAT0.PBST */
+ }
+}
diff --git a/src/ec/dasharo/ec/acpi/battery_thresholds.asl b/src/ec/dasharo/ec/acpi/battery_thresholds.asl
new file mode 100644
index 0000000000..3bb1330fbf
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/battery_thresholds.asl
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Field (ERAM, ByteAcc, Lock, Preserve)
+{
+ Offset (0xBC),
+ BTL0, 8, /* BAT0 charging start threshold */
+ BTH0, 8, /* BAT0 charging end threshold */
+}
+
+/*
+ * Get battery charging threshold
+ *
+ * Arg0: 0: Start threshold
+ * 1: Stop threshold
+ */
+Method (GBCT, 1, NotSerialized)
+{
+ If (Arg0 == 0) {
+ Return (BTL0)
+ }
+
+ If (Arg0 == 1) {
+ Return (BTH0)
+ }
+
+ Return (0xFF)
+}
+
+/*
+ * Set battery charging threshold
+ *
+ * Arg0: 0: Start threshold
+ * 1: Stop threshold
+ * Arg1: Percentage
+ */
+Method (SBCT, 2, NotSerialized)
+{
+ If (Arg1 <= 100) {
+ If (Arg0 == 0) {
+ BTL0 = Arg1
+ }
+ If (Arg0 == 1) {
+ BTH0 = Arg1
+ }
+ }
+}
diff --git a/src/ec/dasharo/ec/acpi/buttons.asl b/src/ec/dasharo/ec/acpi/buttons.asl
new file mode 100644
index 0000000000..ae85c67ccc
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/buttons.asl
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Device (PWRB)
+{
+ Name (_HID, EisaId ("PNP0C0C"))
+ Name (_PRW, Package () { EC_GPE_SWI, 3 })
+}
+
+Device (SLPB)
+{
+ Name (_HID, EisaId ("PNP0C0E"))
+ Name (_PRW, Package () { EC_GPE_SWI, 3 })
+}
diff --git a/src/ec/dasharo/ec/acpi/ec.asl b/src/ec/dasharo/ec/acpi/ec.asl
new file mode 100644
index 0000000000..e4fcdebf09
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/ec.asl
@@ -0,0 +1,241 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Scope (\_SB) {
+ #include "ac.asl"
+ #include "battery.asl"
+ #include "buttons.asl"
+ #include "hid.asl"
+ #include "lid.asl"
+ #include "s76.asl"
+}
+
+Device (\_SB.PCI0.LPCB.EC0)
+{
+ Name (_HID, EisaId ("PNP0C09") /* Embedded Controller Device */)
+ Name (_GPE, EC_GPE_SCI) // _GPE: General Purpose Events
+ Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings
+ {
+ IO (Decode16,
+ 0x0062, // Range Minimum
+ 0x0062, // Range Maximum
+ 0x00, // Alignment
+ 0x01, // Length
+ )
+ IO (Decode16,
+ 0x0066, // Range Minimum
+ 0x0066, // Range Maximum
+ 0x00, // Alignment
+ 0x01, // Length
+ )
+ })
+
+ #include "ec_ram.asl"
+
+ Name (ECOK, 0)
+ Method (_REG, 2, Serialized) // _REG: Region Availability
+ {
+ Printf ("EC: _REG %o %o", ToHexString(Arg0), ToHexString(Arg1))
+ If ((Arg0 == 0x03) && (Arg1 == 1)) {
+ // Enable hardware touchpad lock, airplane mode, and keyboard backlight keys
+ ECOS = 1
+
+ // Enable software display brightness keys
+ WINF = 1
+
+ // Set current AC state
+ ^^^^AC.ACFG = ADP
+ // Update battery information and status
+ ^^^^BAT0.UPBI()
+ ^^^^BAT0.UPBS()
+
+ // Notify of changes
+ Notify(^^^^AC, 0)
+ Notify(^^^^BAT0, 0)
+
+ PNOT ()
+
+ // EC is now available
+ ECOK = Arg1
+
+ // Reset Dasharo Device
+ ^^^^S76D.RSET()
+ }
+ }
+
+ Name (S3OS, 0)
+ Method (PTS, 1, Serialized) {
+ Printf ("EC: PTS: %o", ToHexString(Arg0))
+ If (ECOK) {
+ // Save ECOS during sleep
+ S3OS = ECOS
+
+ // Clear wake cause
+ WFNO = 0
+ }
+ }
+
+ Method (WAK, 1, Serialized) {
+ Printf ("EC: WAK: %o", ToHexString(Arg0))
+ If (ECOK) {
+ // Restore ECOS after sleep
+ ECOS = S3OS
+
+ // Set current AC state
+ ^^^^AC.ACFG = ADP
+
+ // Update battery information and status
+ ^^^^BAT0.UPBI()
+ ^^^^BAT0.UPBS()
+
+ // Notify of changes
+ Notify(^^^^AC, 0)
+ Notify(^^^^BAT0, 0)
+ }
+ }
+
+ Method (_Q0A, 0, NotSerialized) // Touchpad Toggle
+ {
+ Printf ("EC: Touchpad Toggle")
+ }
+
+ 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
+ {
+ Printf ("EC: Mute")
+ }
+
+ Method (_Q0D, 0, NotSerialized) // Keyboard Backlight
+ {
+ Printf ("EC: Keyboard Backlight")
+ }
+
+ Method (_Q0E, 0, NotSerialized) // Volume Down
+ {
+ Printf ("EC: Volume Down")
+ }
+
+ Method (_Q0F, 0, NotSerialized) // Volume Up
+ {
+ Printf ("EC: Volume Up")
+ }
+
+ Method (_Q10, 0, NotSerialized) // Switch Video Mode
+ {
+ Printf ("EC: Switch Video Mode")
+ }
+
+ Method (_Q11, 0, NotSerialized) // Brightness Down
+ {
+ Printf ("EC: Brightness Down")
+ if (^^^^HIDD.HRDY) {
+ ^^^^HIDD.HPEM (20)
+ }
+ }
+
+ Method (_Q12, 0, NotSerialized) // Brightness Up
+ {
+ Printf ("EC: Brightness Up")
+ if (^^^^HIDD.HRDY) {
+ ^^^^HIDD.HPEM (19)
+ }
+ }
+
+ Method (_Q13, 0, NotSerialized) // Camera Toggle
+ {
+ Printf ("EC: Camera Toggle")
+ }
+
+ Method (_Q14, 0, NotSerialized) // Airplane Mode
+ {
+ Printf ("EC: Airplane Mode")
+ if (^^^^HIDD.HRDY) {
+ ^^^^HIDD.HPEM (8)
+ }
+ // TODO: hardware airplane mode
+ }
+
+ Method (_Q15, 0, NotSerialized) // Suspend Button
+ {
+ Printf ("EC: Suspend Button")
+ Notify (SLPB, 0x80)
+ }
+
+ Method (_Q16, 0, NotSerialized) // AC Detect
+ {
+ Printf ("EC: AC Detect")
+ ^^^^AC.ACFG = ADP
+ Notify (AC, 0x80) // Status Change
+ If (BAT0)
+ {
+ Notify (^^^^BAT0, 0x81) // Information Change
+ Notify (^^^^BAT0, 0x80) // Status Change
+ }
+ }
+
+ Method (_Q17, 0, NotSerialized) // BAT0 Update
+ {
+ Printf ("EC: BAT0 Update (17)")
+ Notify (^^^^BAT0, 0x81) // Information Change
+ }
+
+ Method (_Q19, 0, NotSerialized) // BAT0 Update
+ {
+ Printf ("EC: BAT0 Update (19)")
+ Notify (^^^^BAT0, 0x81) // Information Change
+ }
+
+ Method (_Q1B, 0, NotSerialized) // Lid Close
+ {
+ Printf ("EC: Lid Close")
+ Notify (LID0, 0x80)
+ }
+
+ Method (_Q1C, 0, NotSerialized) // Thermal Trip
+ {
+ Printf ("EC: Thermal Trip")
+ /* TODO
+ Notify (\_TZ.TZ0, 0x81) // Thermal Trip Point Change
+ Notify (\_TZ.TZ0, 0x80) // Thermal Status Change
+ */
+ }
+
+ Method (_Q1D, 0, NotSerialized) // Power Button
+ {
+ Printf ("EC: Power Button")
+ Notify (PWRB, 0x80)
+ }
+
+ 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))
+ }
+ }
+
+ #if CONFIG(EC_DASHARO_EC_BAT_THRESHOLDS)
+ #include "battery_thresholds.asl"
+ #endif
+}
diff --git a/src/ec/dasharo/ec/acpi/ec_ram.asl b/src/ec/dasharo/ec/acpi/ec_ram.asl
new file mode 100644
index 0000000000..cb5bcf1444
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/ec_ram.asl
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+OperationRegion (ERAM, EmbeddedControl, 0, 0xFF)
+Field (ERAM, ByteAcc, Lock, Preserve)
+{
+ Offset (0x03),
+ LSTE, 1, // Lid is open
+ , 1,
+ LWKE, 1, // Lid wake
+ , 5,
+ Offset (0x07),
+ TMP1, 8, // CPU temperature
+ Offset (0x10),
+ ADP, 1, // AC adapter connected
+ , 1,
+ BAT0, 1, // Battery connected
+ , 5,
+ WFNO, 8, // Wake cause (not implemented)
+ Offset (0x16),
+ BDC0, 32, // Battery design capacity
+ BFC0, 32, // Battery full capacity
+ Offset (0x22),
+ BDV0, 32, // Battery design voltage
+ BST0, 32, // Battery status
+ BPR0, 32, // Battery current
+ BRC0, 32, // Battery remaining capacity
+ BPV0, 32, // Battery voltage
+ Offset (0x3A),
+ BCW0, 32,
+ BCL0, 32,
+ CYC0, 16, // Battery cycle count
+ Offset (0x68),
+ ECOS, 8, // Detected OS, 0 = no ACPI, 1 = ACPI but no driver, 2 = ACPI with driver
+ Offset (0xC8),
+ OEM1, 8,
+ OEM2, 8,
+ OEM3, 16,
+ OEM4, 8, // Extra SCI data
+ Offset (0xCD),
+ TMP2, 8, // GPU temperature
+ DUT1, 8, // Fan 1 duty
+ DUT2, 8, // Fan 2 duty
+ RPM1, 16, // Fan 1 RPM
+ RPM2, 16, // Fan 2 RPM
+ 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,
+}
diff --git a/src/ec/dasharo/ec/acpi/hid.asl b/src/ec/dasharo/ec/acpi/hid.asl
new file mode 100644
index 0000000000..eb5f420cce
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/hid.asl
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Device (HIDD)
+{
+ Name (_HID, "INT33D5")
+ Name (HBSY, 0)
+ Name (HIDX, 0)
+ Name (HRDY, 0)
+
+ Method (HDEM, 0, Serialized)
+ {
+ HBSY = 0
+ Return (HIDX)
+ }
+
+ Method (HDMM, 0, Serialized)
+ {
+ Return (0)
+ }
+
+ Method (HDSM, 1, Serialized)
+ {
+ HRDY = Arg0
+ }
+
+ Method (HPEM, 1, Serialized)
+ {
+ HBSY = 1
+ HIDX = Arg0
+
+ Notify (HIDD, 0xC0)
+ Local0 = 0
+ While ((Local0 < 0xFA) && HBSY)
+ {
+ Sleep (0x04)
+ Local0++
+ }
+
+ If (HBSY == 1)
+ {
+ HBSY = 0
+ HIDX = 0
+ Return (1)
+ }
+ Else
+ {
+ Return (0)
+ }
+ }
+}
diff --git a/src/ec/dasharo/ec/acpi/lid.asl b/src/ec/dasharo/ec/acpi/lid.asl
new file mode 100644
index 0000000000..0a643416e3
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/lid.asl
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+Device (LID0)
+{
+ Name (_HID, EisaId ("PNP0C0D"))
+ Name (_PRW, Package () { EC_GPE_SWI, 3 })
+
+ Method (_LID, 0, NotSerialized) {
+ Printf ("LID: _LID")
+ If (^^PCI0.LPCB.EC0.ECOK) {
+ Return (^^PCI0.LPCB.EC0.LSTE)
+ } Else {
+ Return (1)
+ }
+ }
+
+ Method (_PSW, 1, NotSerialized) {
+ Printf ("LID: _PSW: %o", 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
new file mode 100644
index 0000000000..f23f85709f
--- /dev/null
+++ b/src/ec/dasharo/ec/acpi/s76.asl
@@ -0,0 +1,178 @@
+/* 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/dasharo_ec.c b/src/ec/dasharo/ec/dasharo_ec.c
new file mode 100644
index 0000000000..97c9613f82
--- /dev/null
+++ b/src/ec/dasharo/ec/dasharo_ec.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "dasharo_ec.h"
+#include <arch/io.h>
+#include <console/dasharo_ec.h>
+#include <console/console.h>
+#include <timer.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 REG_RESULT 1
+#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);
+}
+
+static inline void dasharo_ec_write(uint8_t addr, uint8_t data)
+{
+ outb(data, DASHARO_EC_BASE + (uint16_t)addr);
+}
+
+void dasharo_ec_init(void)
+{
+ // Clear entire command region
+ for (int i = 0; i < DASHARO_EC_SIZE; i++)
+ dasharo_ec_write((uint8_t)i, 0);
+}
+
+void dasharo_ec_flush(void)
+{
+ dasharo_ec_write(REG_CMD, CMD_PRINT);
+
+ // Wait for 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);
+}
+
+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 */
+ 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);
+ }
+
+ /* 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 ret;
+}
diff --git a/src/ec/dasharo/ec/dasharo_ec.h b/src/ec/dasharo/ec/dasharo_ec.h
new file mode 100644
index 0000000000..f313b0d0f5
--- /dev/null
+++ b/src/ec/dasharo/ec/dasharo_ec.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef DASHARO_EC_H
+#define DASHARO_EC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * Send a command to the EC. request_data/request_size are the request payload,
+ * 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);
+
+#endif
diff --git a/src/ec/dasharo/ec/smbios.c b/src/ec/dasharo/ec/smbios.c
new file mode 100644
index 0000000000..e55d5f0965
--- /dev/null
+++ b/src/ec/dasharo/ec/smbios.c
@@ -0,0 +1,9 @@
+/* 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;
+}