Attention is currently required from: Michał Żygowski. Hello Michał Żygowski,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/62495
to review the following change.
Change subject: ec/clevo/it5570: Add Clevo EC implementation found on Clevo laptops ......................................................................
ec/clevo/it5570: Add Clevo EC implementation found on Clevo laptops
This is IT5570 EC implementation for Clevo laptops with Insyde firmware. The driver and ACPI code support all functionalities, including dGPU, FN keys, Type-C UCSI and S0ix.
The only issue is with TP toggle hotkey when TP works in I2C HID mode under Linux. One needs to add udev rules as specified in: https://docs.dasharo.com/variants/clevo_nv41/post_install/ Windows can handle the EC query function that toggles the TP's _STA field and OS disables/enabels the touchpad accordingly.
TEST=Boot Ubuntu and Windows 11 on Clevo NV41 and see battery/AC is detected, S0ix is working and FN keys are functional.
Signed-off-by: Michał Kopeć michal.kopec@3mdeb.com Signed-off-by: Michał Żygowski michal.zygowski@3mdeb.com Change-Id: I07c7d1d4f86d764bd10cfa3b0da23d1116281f3b --- A src/ec/clevo/it5570/Kconfig A src/ec/clevo/it5570/Makefile.inc A src/ec/clevo/it5570/acpi/ac.asl A src/ec/clevo/it5570/acpi/battery.asl A src/ec/clevo/it5570/acpi/buttons.asl A src/ec/clevo/it5570/acpi/ec.asl A src/ec/clevo/it5570/acpi/ec_ram.asl A src/ec/clevo/it5570/acpi/gpe.asl A src/ec/clevo/it5570/acpi/hid.asl A src/ec/clevo/it5570/acpi/lid.asl A src/ec/clevo/it5570/acpi/ucsi.asl A src/ec/clevo/it5570/chip.c A src/ec/clevo/it5570/chip.h A src/ec/clevo/it5570/ec.c A src/ec/clevo/it5570/ec.h 15 files changed, 1,666 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/95/62495/1
diff --git a/src/ec/clevo/it5570/Kconfig b/src/ec/clevo/it5570/Kconfig new file mode 100644 index 0000000..bdd3a59 --- /dev/null +++ b/src/ec/clevo/it5570/Kconfig @@ -0,0 +1,14 @@ +config EC_CLEVO_IT5570 + bool + select EC_ACPI + help + Clevo IT5570 EC + +config EC_CLEVO_IT5570_RAM_BASE + depends on EC_CLEVO_IT5570 + hex + default 0xfe0b0100 + help + The base of LPC window that maps the EC RAM to host memory space. + This is the ACPI address for EC RAM, the address programmed to registers + is always rounded to the nearest 64K. diff --git a/src/ec/clevo/it5570/Makefile.inc b/src/ec/clevo/it5570/Makefile.inc new file mode 100644 index 0000000..1568d94 --- /dev/null +++ b/src/ec/clevo/it5570/Makefile.inc @@ -0,0 +1,8 @@ +ifeq ($(CONFIG_EC_CLEVO_IT5570),y) + +ramstage-y += chip.c +ramstage-y += ec.c + +smm-y += ec.c + +endif diff --git a/src/ec/clevo/it5570/acpi/ac.asl b/src/ec/clevo/it5570/acpi/ac.asl new file mode 100644 index 0000000..7326676 --- /dev/null +++ b/src/ec/clevo/it5570/acpi/ac.asl @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +Device (AC) +{ + Name (_HID, "ACPI0003" /* Power Source Device */) // _HID: Hardware ID + Name (_PCL, Package (0x01) // _PCL: Power Consumer List + { + _SB + }) + + Name (ACFG, One) + + Method (_PSR, 0, NotSerialized) // _PSR: Power Source + { + Return (ACFG) + } + + Method (_STA, 0, NotSerialized) // _STA: Status + { + Return (0x0F) + } +} diff --git a/src/ec/clevo/it5570/acpi/battery.asl b/src/ec/clevo/it5570/acpi/battery.asl new file mode 100644 index 0000000..bc239dd --- /dev/null +++ b/src/ec/clevo/it5570/acpi/battery.asl @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +Device (BAT0) +{ + Name (_HID, EisaId ("PNP0C0A") /* Control Method Battery */) // _HID: Hardware ID + Name (_UID, Zero) // _UID: Unique ID + Name (_PCL, Package (0x01) // _PCL: Power Consumer List + { + _SB + }) + Name (BFCC, Zero) + Method (_STA, 0, NotSerialized) // _STA: Status + { + If (^^PCI0.LPCB.EC0.ECOK) + { + If (^^PCI0.LPCB.EC0.BAT0) + { + Return (0x1F) + } + Else + { + Return (0x0F) + } + } + Else + { + Return (0x0F) + } + } + + Name (PBIF, Package (0x0D) + { + One, + 0xFFFFFFFF, + 0xFFFFFFFF, + One, + 0x39D0, + Zero, + Zero, + 0x40, + 0x40, + "BAT", + "0001", + "LION", + "Notebook" + }) + Method (IVBI, 0, NotSerialized) + { + PBIF [One] = 0xFFFFFFFF + PBIF [0x02] = 0xFFFFFFFF + PBIF [0x04] = 0xFFFFFFFF + PBIF [0x09] = " " + PBIF [0x0A] = " " + PBIF [0x0B] = " " + PBIF [0x0C] = " " + BFCC = Zero + } + + Method (UPBI, 0, NotSerialized) + { + If (^^PCI0.LPCB.EC0.BAT0) + { + Local0 = (^^PCI0.LPCB.EC0.BDC0 & 0xFFFF) + PBIF [One] = Local0 + Local0 = (^^PCI0.LPCB.EC0.BFC0 & 0xFFFF) + PBIF [0x02] = Local0 + BFCC = Local0 + Local0 = (^^PCI0.LPCB.EC0.BDV0 & 0xFFFF) + PBIF [0x04] = Local0 + Local0 = (^^PCI0.LPCB.EC0.BCW0 & 0xFFFF) + PBIF [0x05] = Local0 + Local0 = (^^PCI0.LPCB.EC0.BCL0 & 0xFFFF) + PBIF [0x06] = Local0 + PBIF [0x09] = "BAT" + PBIF [0x0A] = "0001" + PBIF [0x0B] = "LION" + PBIF [0x0C] = "Notebook" + } + Else + { + IVBI () + } + } + + Method (_BIF, 0, NotSerialized) // _BIF: Battery Information + { + If (^^PCI0.LPCB.EC0.ECOK) + { + UPBI () + } + Else + { + IVBI () + } + + Return (PBIF) /* _SB_.BAT0.PBIF */ + } + + Name (PBST, Package (0x04) + { + Zero, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0x3D90 + }) + Method (IVBS, 0, NotSerialized) + { + PBST [Zero] = Zero + PBST [One] = 0xFFFFFFFF + PBST [0x02] = 0xFFFFFFFF + PBST [0x03] = 0x2710 + } + + Method (UPBS, 0, NotSerialized) + { + If (^^PCI0.LPCB.EC0.BAT0) + { + Local0 = Zero + Local1 = Zero + If (^^AC.ACFG) + { + If (((^^PCI0.LPCB.EC0.BST0 & 0x02) == 0x02)) + { + Local0 |= 0x02 + Local1 = (^^PCI0.LPCB.EC0.BPR0 & 0xFFFF) + } + } + Else + { + Local0 |= One + 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 [Zero] = Local0 + PBST [One] = Local1 + PBST [0x02] = Local2 + PBST [0x03] = 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/clevo/it5570/acpi/buttons.asl b/src/ec/clevo/it5570/acpi/buttons.asl new file mode 100644 index 0000000..040d189 --- /dev/null +++ b/src/ec/clevo/it5570/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_PWRB, 3 }) +} + +Device (SLPB) +{ + Name (_HID, EisaId ("PNP0C0E")) + Name (_PRW, Package () { EC_GPE_SLPB, 3 }) +} diff --git a/src/ec/clevo/it5570/acpi/ec.asl b/src/ec/clevo/it5570/acpi/ec.asl new file mode 100644 index 0000000..f894a0f --- /dev/null +++ b/src/ec/clevo/it5570/acpi/ec.asl @@ -0,0 +1,389 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* Generated in SSDT */ +External (_SB.PCI0.LPCB.EC0.SFCV, MethodObj) + +Device (EC0) +{ + Name (_HID, EisaId ("PNP0C09") /* Embedded Controller Device */) // _HID: Hardware ID + 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 + ) + IO (Decode16, + 0x002e, // Range Minimum + 0x002e, // Range Maximum + 0x00, // Alignment + 0x02, // Length + ) + }) + + #include "ec_ram.asl" + + Name (ECOK, Zero) + Method (_REG, 2, Serialized) // _REG: Region Availability + { + Debug = Concatenate("EC: _REG", Concatenate(ToHexString(Arg0), Concatenate(" ", ToHexString(Arg1)))) + If (((Arg0 == 0x03) && (Arg1 == One))) { + // Enable hardware touchpad lock and keyboard backlight keys + // Enable software airplane mode key + ECOS = 2 + + // Enable software display brightness keys + WINF = 1 + + // Enable camera toggle hotkey + OEM3 = OEM3 | 4 + + // Set current AC state + _SB.AC.ACFG = ADP + // Update battery information and status + _SB.BAT0.UPBI () + _SB.BAT0.UPBS () + + PNOT () + + // Initialize UCSI + ^UCSI.INIT () + + // Apply custom fan curve + _SB.PCI0.LPCB.EC0.SFCV () + + // EC is now available + ECOK = Arg1 + } + } + + Method (UPB, 0, Serialized) { + Debug = "EC: UPB" + // Set current AC state + _SB.AC.ACFG = ADP + + // Update battery information and status + _SB.BAT0.UPBI () + _SB.BAT0.UPBS () + + // Notify of changes + Notify(_SB.AC, Zero) + Notify(_SB.BAT0, Zero) + + Sleep (1000) + } + + Method (PTS, 1, Serialized) { + Debug = Concatenate("EC: PTS: ", ToHexString(Arg0)) + If (ECOK) { + // Clear wake cause + WFNO = Zero + } + } + + Method (WAK, 1, Serialized) { + Debug = Concatenate("EC: WAK: ", ToHexString(Arg0)) + If (ECOK) { + UPB () + _SB.PCI0.LPCB.EC0.SFCV () + } + } + + Method (I2ER, 1, NotSerialized) + { + SIOI = 0x2e + SIOD = 0x11 + SIOI = 0x2f + SIOD = ((Arg0 >> 8) & 0xff) + SIOI = 0x2e + SIOD = 0x10 + SIOI = 0x2f + SIOD = (Arg0 & 0xff) + SIOI = 0x2e + SIOD = 0x12 + SIOI = 0x2f + Local0 = SIOD + + Return (Local0) + } + + Method (I2EW, 2, NotSerialized) + { + SIOI = 0x2e + SIOD = 0x11 + SIOI = 0x2f + SIOD = ((Arg0 >> 8) & 0xff) + SIOI = 0x2e + SIOD = 0x10 + SIOI = 0x2f + SIOD = (Arg0 & 0xff) + SIOI = 0x2e + SIOD = 0x12 + SIOI = 0x2f + + SIOD = Arg1; + } + + Method (GKBL, 0, Serialized) // Get Keyboard LED + { + Local0 = 0 + If (ECOK) { + FDAT = One + FCMD = 0xCA + Local0 = FBUF + FCMD = Zero + } + Return (Local0) + } + + Method (SKBL, 1, Serialized) // Set Keyboard LED + { + If (ECOK) { + FDAT = Zero + FBUF = Arg0 + FCMD = 0xCA + } + } + + Method (S0IX, 1, Serialized) // S0IX Entry/Exit + { + If (Arg0) { + Debug = "EC: S0IX Enter" + } Else { + Debug = "EC: S0IX Exit" + UPB () + _SB.PCI0.LPCB.EC0.SFCV () + } + + FDAT = 0xC2 + FBUF = Arg0 + FCMD = 0xD2 + Local0 = 0xFF + Local1 = 0xFF + While (Local0 != Arg0 && Local1 > Zero) + { + Sleep(50) + FDAT = 0xC3 + FCMD = 0xD2 + Local3 = FBUF + If (Local3 == Zero || Local3 == One) + { + Local0 = Local3 + } + Local1 = Local1 - 1 + } + } + + Method (DGPM, 1, Serialized) // Handle dGPU power state change + { + If (ECOK) { + If (Arg0 == 0x0) { + AIRP &= 0x7F + Debug = "EC: DGPU Off" + } ElseIf (Arg0 == 0x1) { + AIRP |= 0x80 + Debug = "EC: DGPU On" + } + } + } + + Method (_Q0A, 0, NotSerialized) // Touchpad Toggle + { + Debug = "EC: Touchpad Toggle" + } + + Method (_Q0B, 0, NotSerialized) // Screen Toggle + { + Debug = "EC: Screen Toggle" + } + + Method (_Q0C, 0, NotSerialized) // Mute + { + Debug = "EC: Mute" + } + + Method (_Q0D, 0, NotSerialized) // Keyboard Backlight + { + Debug = "EC: Keyboard Backlight" + } + + Method (_Q0E, 0, NotSerialized) // Volume Down + { + Debug = "EC: Volume Down" + } + + Method (_Q0F, 0, NotSerialized) // Volume Up + { + Debug = "EC: Volume Up" + } + + Method (_Q10, 0, NotSerialized) // Switch Video Mode + { + Debug = "EC: Switch Video Mode" + If (CondRefOf (_SB.PCI0.GFX0)) { + Notify (_SB.PCI0.GFX0, 0x80) + } + } + + Method (_Q11, 0, NotSerialized) // Brightness Down + { + Debug = "EC: Brightness Down" + + If (CondRefOf (_SB.PCI0.GFX0.LCD0)) { + Notify (_SB.PCI0.GFX0.LCD0, 0x87) + } + } + + Method (_Q12, 0, NotSerialized) // Brightness Up + { + Debug = "EC: Brightness Up" + + If (CondRefOf (_SB.PCI0.GFX0.LCD0)) { + Notify (_SB.PCI0.GFX0.LCD0, 0x86) + } + } + + Method (_Q13, 0, NotSerialized) // Camera Toggle + { + Debug = "EC: Camera Toggle" + } + + Method (_Q14, 0, NotSerialized) // Airplane Mode + { + Debug = "EC: Airplane Mode" + + If (CondRefOf (^HIDD.HPEM)) + { + ^HIDD.HPEM (8) + } + } + + Method (_Q15, 0, NotSerialized) // Suspend Button + { + Debug = "EC: Suspend Button" + Notify (SLPB, 0x80) + } + + Method (_Q16, 0, NotSerialized) // AC Detect + { + Debug = "EC: AC Detect" + + If (MSFG) + { + FDAT = Zero + FBUF = 0xC1 + FCMD = 0xD2 + If ((FBUF & 0x80)) + { + FBUF = Zero + Return (Zero) + } + } + + _SB.AC.ACFG = ADP + Notify (AC, 0x80) // Status Change + Sleep (0x01F4) + If (BAT0) + { + Notify (_SB.BAT0, 0x81) // Information Change + Sleep (0x32) + Notify (_SB.BAT0, 0x80) // Status Change + Sleep (0x32) + } + + Return (Zero) + } + + Method (_Q17, 0, NotSerialized) // BAT0 Update + { + Debug = "EC: BAT0 Update (17)" + Notify (_SB.BAT0, 0x81) // Information Change + } + + Method (_Q19, 0, NotSerialized) // BAT0 Update + { + Debug = "EC: BAT0 Update (19)" + Notify (_SB.BAT0, 0x81) // Information Change + } + + Method (_Q1B, 0, NotSerialized) // Lid Close + { + Debug = "EC: Lid Close" + Notify (LID0, 0x80) + } + + Method (_Q1C, 0, NotSerialized) // Thermal Trip + { + Debug = "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 + { + Debug = "EC: Power Button" + Notify (PWRB, 0x80) + } + + Method (_Q50, 0, NotSerialized) // Other Events + { + Local0 = OEM4 + If (Local0 == 0x8A) { + Debug = "EC: White Keyboard Backlight" + } ElseIf (Local0 == 0x9F) { + Debug = "EC: Color Keyboard Toggle" + } ElseIf (Local0 == 0x81) { + Debug = "EC: Color Keyboard Down" + } ElseIf (Local0 == 0x82) { + Debug = "EC: Color Keyboard Up" + } ElseIf (Local0 == 0x80) { + Debug = "EC: Color Keyboard Color Change" + } ElseIf (Local0 == 0xF3) { + Debug = "EC: Fan Cooling Mode Enable" + } ElseIf (Local0 == 0x6C) { + Debug = "EC: Fan Cooling Mode Disable" + _SB.PCI0.LPCB.EC0.SFCV () + } Else { + Debug = Concatenate("EC: Other: ", ToHexString(Local0)) + } + } + + Method (_Q62, 0, NotSerialized) // UCSI event + { + Debug = "EC: UCSI Event" + ^UCSI.MGI0 = MGI0 + ^UCSI.MGI1 = MGI1 + ^UCSI.MGI2 = MGI2 + ^UCSI.MGI3 = MGI3 + ^UCSI.MGI4 = MGI4 + ^UCSI.MGI5 = MGI5 + ^UCSI.MGI6 = MGI6 + ^UCSI.MGI7 = MGI7 + ^UCSI.MGI8 = MGI8 + ^UCSI.MGI9 = MGI9 + ^UCSI.MGIA = MGIA + ^UCSI.MGIB = MGIB + ^UCSI.MGIC = MGIC + ^UCSI.MGID = MGID + ^UCSI.MGIE = MGIE + ^UCSI.MGIF = MGIF + ^UCSI.CCI0 = CCI0 + ^UCSI.CCI1 = CCI1 + ^UCSI.CCI2 = CCI2 + ^UCSI.CCI3 = CCI3 + Notify (^UCSI, 0x80) + } + + #include "hid.asl" + #include "ucsi.asl" +} diff --git a/src/ec/clevo/it5570/acpi/ec_ram.asl b/src/ec/clevo/it5570/acpi/ec_ram.asl new file mode 100644 index 0000000..ce8cce0 --- /dev/null +++ b/src/ec/clevo/it5570/acpi/ec_ram.asl @@ -0,0 +1,307 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +OperationRegion (ERAM, SystemMemory, CONFIG_EC_CLEVO_IT5570_RAM_BASE, 0x400) +Field (ERAM, ByteAcc, Lock, Preserve) +{ + NMSG, 8, + SLED, 4, + Offset (0x02), + MODE, 1, + FAN0, 1, + TME0, 1, + TME1, 1, + FAN1, 1, + , 2, + Offset (0x03), + LSTE, 1, + LSW0, 1, + LWKE, 1, + WAKF, 1, + , 2, + PWKE, 1, + MWKE, 1, + AC0, 8, + PSV, 8, + CRT, 8, + TMP, 8, + AC1, 8, + BBST, 8, + DPTT, 8, + DPT1, 8, + Offset (0x0D), + Offset (0x0E), + SLPT, 8, + SWEJ, 1, + SWCH, 1, + Offset (0x10), + ADP, 1, + AFLT, 1, + BAT0, 1, + BAT1, 1, + , 3, + PWOF, 1, + WFNO, 8, + BPU0, 32, + BDC0, 32, + BFC0, 32, + BTC0, 32, + BDV0, 32, + BST0, 32, + BPR0, 32, + BRC0, 32, + BPV0, 32, + BTP0, 16, + BRS0, 16, + BCW0, 32, + BCL0, 32, + BCG0, 32, + BG20, 32, + BMO0, 64, + BIF0, 64, + BSN0, 32, + BTY0, 64, + Offset (0x67), + Offset (0x68), + ECOS, 8, + LNXD, 8, + ECPS, 8, + Offset (0x6C), + BTMP, 16, + EVTN, 8, + Offset (0x72), + PRCL, 8, + PRC0, 8, + PRC1, 8, + PRCM, 8, + PRIN, 8, + PSTE, 8, + PCAD, 8, + PEWL, 8, + PWRL, 8, + PECD, 8, + PEHI, 8, + PECI, 8, + PEPL, 8, + PEPM, 8, + PWFC, 8, + PECC, 8, + PDT0, 8, + PDT1, 8, + PDT2, 8, + PDT3, 8, + PRFC, 8, + PRS0, 8, + PRS1, 8, + PRS2, 8, + PRS3, 8, + PRS4, 8, + PRCS, 8, + PEC0, 8, + PEC1, 8, + PEC2, 8, + PEC3, 8, + CMDR, 8, + CVRT, 8, + GTVR, 8, + FANT, 8, + SKNT, 8, + AMBT, 8, + MCRT, 8, + DIM0, 8, + DIM1, 8, + PMAX, 8, + PPDT, 8, + PECH, 8, + PMDT, 8, + TSD0, 8, + TSD1, 8, + TSD2, 8, + TSD3, 8, + CPUP, 16, + MCHP, 16, + SYSP, 16, + CPAP, 16, + MCAP, 16, + SYAP, 16, + CFSP, 16, + CPUE, 16, + Offset (0xC6), + Offset (0xC7), + VGAT, 8, + OEM1, 8, + OEM2, 8, + OEM3, 16, + OEM4, 8, + OEM5, 8, + DUT1, 8, + DUT2, 8, + RPM1, 16, + RPM2, 16, + RPM4, 16, + Offset (0xD7), + DTHL, 8, + DTBP, 8, + AIRP, 8, + WINF, 8, + RINF, 8, + Offset (0xDD), + INF2, 8, + MUTE, 1, + Offset (0xE0), + RPM3, 16, + ECKS, 8, + Offset (0xE4), + , 4, + XTUF, 1, + EP12, 1, + FN_G, 1, + Offset (0xE5), + INF3, 8, + DFAL, 1, + DFAE, 1, + Offset (0xE7), + XFAN, 8, + , 2, + MAXQ, 1, + Offset (0xE9), + EKBS, 1, + Offset (0xEA), + , 4, + MSFG, 1, + RCHG, 1, + ACOT, 1, + S5FG, 1, + , 3, + DGPT, 1, + TOPN, 1, + , 1, + APRD, 1, + Offset (0xF0), + PL1T, 16, + PL2T, 16, + TAUT, 8, + Offset (0x280), + KLCR, 8, + KLCG, 8, + KLCB, 8, + KMCR, 8, + KMCG, 8, + KMCB, 8, + KRCR, 8, + KRCG, 8, + KRCB, 8, + KBNS, 8, + FANC, 8, + KBLD, 8, + P1F1, 8, + P2F1, 8, + P3F1, 8, + P4F1, 8, + P1D1, 8, + P2D1, 8, + P3D1, 8, + P4D1, 8, + SH11, 8, + SL11, 8, + SH12, 8, + SL12, 8, + SH13, 8, + SL13, 8, + P1F2, 8, + P2F2, 8, + P3F2, 8, + P4F2, 8, + P1D2, 8, + P2D2, 8, + P3D2, 8, + P4D2, 8, + SH21, 8, + SL21, 8, + SH22, 8, + SL22, 8, + SH23, 8, + SL23, 8, + P1F3, 8, + P2F3, 8, + P3F3, 8, + P4F3, 8, + P1D3, 8, + P2D3, 8, + P3D3, 8, + P4D3, 8, + SH31, 8, + SL31, 8, + SH32, 8, + SL32, 8, + SH33, 8, + SL33, 8, + Offset (0x2CF), + VER0, 8, + VER1, 8, + RSV1, 8, + RSV2, 8, + CCI0, 8, + CCI1, 8, + CCI2, 8, + CCI3, 8, + CTL0, 8, + CTL1, 8, + CTL2, 8, + CTL3, 8, + CTL4, 8, + CTL5, 8, + CTL6, 8, + CTL7, 8, + MGI0, 8, + MGI1, 8, + MGI2, 8, + MGI3, 8, + MGI4, 8, + MGI5, 8, + MGI6, 8, + MGI7, 8, + MGI8, 8, + MGI9, 8, + MGIA, 8, + MGIB, 8, + MGIC, 8, + MGID, 8, + MGIE, 8, + MGIF, 8, + MGO0, 8, + MGO1, 8, + MGO2, 8, + MGO3, 8, + MGO4, 8, + MGO5, 8, + MGO6, 8, + MGO7, 8, + MGO8, 8, + MGO9, 8, + MGOA, 8, + MGOB, 8, + MGOC, 8, + MGOD, 8, + MGOE, 8, + MGOF, 8, + MSTS, 8 +} + +OperationRegion (EC81, EmbeddedControl, Zero, 0xFF) +Field (EC81, ByteAcc, Lock, Preserve) +{ + Offset (0xF8), + FCMD, 8, + FDAT, 8, + FBUF, 8, + FBF1, 8, + FBF2, 8, + FBF3, 8 +} + +OperationRegion (SIO, SystemIO, 0x2e, 0x02) +Field (SIO, ByteAcc, Lock, Preserve) +{ + SIOI, 8, + SIOD, 8 +} diff --git a/src/ec/clevo/it5570/acpi/gpe.asl b/src/ec/clevo/it5570/acpi/gpe.asl new file mode 100644 index 0000000..68f33a6 --- /dev/null +++ b/src/ec/clevo/it5570/acpi/gpe.asl @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +Method (_L02, 0, Serialized) { + Debug = Concatenate("GPE_L02: ", ToHexString(_SB.PCI0.LPCB.EC0.WFNO)) + If (_SB.PCI0.LPCB.EC0.ECOK) { + If (_SB.PCI0.LPCB.EC0.WFNO == One) { + Notify(_SB.LID0, 0x80) + } + } +} diff --git a/src/ec/clevo/it5570/acpi/hid.asl b/src/ec/clevo/it5570/acpi/hid.asl new file mode 100644 index 0000000..5c7d448 --- /dev/null +++ b/src/ec/clevo/it5570/acpi/hid.asl @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This file is part of the coreboot project. */ + +Device (HIDD) +{ + Name (_HID, "INTC1051") // _HID: Hardware ID + Name (HBSY, Zero) + Name (HIDX, Zero) + Name (HMDE, Zero) + Name (HRDY, Zero) + Name (BTLD, Zero) + Name (BTS1, Zero) + Name (HEB1, 0x02) + Name (HEB2, Zero) + Name (BIST, Zero) + + Name (DPKG, Package (0x04) + { + 0x11111111, + 0x22222222, + 0x33333333, + 0x44444444 + }) + + Method (_STA, 0, Serialized) // _STA: Status + { + Return (0x0F) + } + + Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method + { + If ((Arg0 == ToUUID ("eeec56b3-4442-408f-a792-4edd4d758054"))) + { + If ((One == ToInteger (Arg1))) + { + BIST = One + Switch (ToInteger (Arg2)) + { + Case (Zero) + { + Return (Buffer (0x02) + { + 0xFF, 0x01 + }) + } + Case (One) + { + BTNL () + } + Case (0x02) + { + Return (HDMM ()) + } + Case (0x03) + { + HDSM (DerefOf (Arg3 [Zero])) + } + Case (0x04) + { + Return (HDEM ()) + } + Case (0x05) + { + Return (BTNS ()) + } + Case (0x06) + { + BTNE (DerefOf (Arg3 [Zero])) + } + Case (0x07) + { + Return (HEBC ()) + } + Case (0x08) + { + } + + } + } + Else + { + BIST = Zero + } + } + + Return (Buffer (One) { 0x00 }) + } + + Method (HDDM, 0, Serialized) + { + Return (DPKG) + } + + Method (HDEM, 0, Serialized) + { + HBSY = Zero + If ((HMDE == Zero)) + { + Return (HIDX) + } + + Return (HMDE) + } + + Method (HDMM, 0, Serialized) + { + Return (HMDE) + } + + Method (HDSM, 1, Serialized) + { + HRDY = Arg0 + } + + Method (HPEM, 1, Serialized) + { + HBSY = One + If ((HMDE == Zero)) + { + HIDX = Arg0 + } + Else + { + HIDX = Arg0 + } + + Notify (HIDD, 0xC0) + Local0 = Zero + + While (((Local0 < 0xFA) && HBSY)) + { + Sleep (0x04) + Local0++ + } + + If ((HBSY == One)) + { + HBSY = Zero + HIDX = Zero + Return (One) + } + Else + { + Return (Zero) + } + } + + Method (BTNL, 0, Serialized) + { + BTS1 = Zero + } + + Method (BTNE, 1, Serialized) + { + BTS1 = ((Arg0 & 0x1E) | One) + } + + Method (BTNS, 0, Serialized) + { + Return (BTS1) + } + + Method (BTNC, 0, Serialized) + { + Return (Zero) + } + + Method (HEBC, 0, Serialized) + { + Return (HEB1) + } + + Method (HEEC, 0, Serialized) + { + Return (HEB2) + } +} diff --git a/src/ec/clevo/it5570/acpi/lid.asl b/src/ec/clevo/it5570/acpi/lid.asl new file mode 100644 index 0000000..5f7ca6d --- /dev/null +++ b/src/ec/clevo/it5570/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_LID, 3 }) + + Method (_LID, 0, NotSerialized) { + DEBUG = "LID: _LID" + If (^^PCI0.LPCB.EC0.ECOK) { + Return (^^PCI0.LPCB.EC0.LSTE) + } Else { + Return (One) + } + } + + Method (_PSW, 1, NotSerialized) { + DEBUG = Concatenate("LID: _PSW: ", ToHexString(Arg0)) + If (^^PCI0.LPCB.EC0.ECOK) { + ^^PCI0.LPCB.EC0.LWKE = Arg0 + } + } +} diff --git a/src/ec/clevo/it5570/acpi/ucsi.asl b/src/ec/clevo/it5570/acpi/ucsi.asl new file mode 100644 index 0000000..ad8450a --- /dev/null +++ b/src/ec/clevo/it5570/acpi/ucsi.asl @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +Device (UCSI) +{ + Name (_HID, EisaId ("USBC000")) + Name (_CID, EisaId ("PNP0CA0")) + Name (_UID, One) + Name (_DDN, "USB Type-C") + Name (_STA, 0xf) + + /* Shared memory fields are defined in the SSDT */ + External (_SB.PCI0.LPCB.EC0.UCSI.VER0, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.VER1, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CCI0, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CCI1, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CCI2, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CCI3, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL0, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL1, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL2, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL3, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL4, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL5, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL6, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.CTL7, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI0, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI1, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI2, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI3, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI4, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI5, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI6, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI7, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI8, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGI9, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGIA, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGIB, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGIC, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGID, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGIE, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGIF, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO0, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO1, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO2, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO3, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO4, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO5, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO6, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO7, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO8, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGO9, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOA, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOB, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOC, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOD, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOE, FieldUnitObj) + External (_SB.PCI0.LPCB.EC0.UCSI.MGOF, FieldUnitObj) + + Method (INIT) + { + /* Read UCSI version from EC into shared memory */ + VER0 = _SB.PCI0.LPCB.EC0.VER0 + VER1 = _SB.PCI0.LPCB.EC0.VER1 + } + + Method (_DSM, 4, Serialized) + { + If (Arg0 != ToUUID ("6f8398c2-7ca4-11e4-ad36-631042b5008f")) { + Return (Buffer (One) { Zero }) + } + + Switch (ToInteger (Arg2)) + { + Case (Zero) + { + Return (Buffer (One) { 0x0F }) + } + Case (One) + { + /* Write Message Out */ + _SB.PCI0.LPCB.EC0.MGO0 = MGO0 + _SB.PCI0.LPCB.EC0.MGO1 = MGO1 + _SB.PCI0.LPCB.EC0.MGO2 = MGO2 + _SB.PCI0.LPCB.EC0.MGO3 = MGO3 + _SB.PCI0.LPCB.EC0.MGO4 = MGO4 + _SB.PCI0.LPCB.EC0.MGO5 = MGO5 + _SB.PCI0.LPCB.EC0.MGO6 = MGO6 + _SB.PCI0.LPCB.EC0.MGO7 = MGO7 + _SB.PCI0.LPCB.EC0.MGO8 = MGO8 + _SB.PCI0.LPCB.EC0.MGO9 = MGO9 + _SB.PCI0.LPCB.EC0.MGOA = MGOA + _SB.PCI0.LPCB.EC0.MGOB = MGOB + _SB.PCI0.LPCB.EC0.MGOC = MGOC + _SB.PCI0.LPCB.EC0.MGOD = MGOD + _SB.PCI0.LPCB.EC0.MGOE = MGOE + _SB.PCI0.LPCB.EC0.MGOF = MGOF + + /* Write Control */ + _SB.PCI0.LPCB.EC0.CTL0 = CTL0 + _SB.PCI0.LPCB.EC0.CTL1 = CTL1 + _SB.PCI0.LPCB.EC0.CTL2 = CTL2 + _SB.PCI0.LPCB.EC0.CTL3 = CTL3 + _SB.PCI0.LPCB.EC0.CTL4 = CTL4 + _SB.PCI0.LPCB.EC0.CTL5 = CTL5 + _SB.PCI0.LPCB.EC0.CTL6 = CTL6 + _SB.PCI0.LPCB.EC0.CTL7 = CTL7 + + /* Start EC Command */ + _SB.PCI0.LPCB.EC0.FDAT = One + _SB.PCI0.LPCB.EC0.FCMD = 0xE0 + } + Case (2) + { + /* Read Message In */ + MGI0 = _SB.PCI0.LPCB.EC0.MGI0 + MGI1 = _SB.PCI0.LPCB.EC0.MGI1 + MGI2 = _SB.PCI0.LPCB.EC0.MGI2 + MGI3 = _SB.PCI0.LPCB.EC0.MGI3 + MGI4 = _SB.PCI0.LPCB.EC0.MGI4 + MGI5 = _SB.PCI0.LPCB.EC0.MGI5 + MGI6 = _SB.PCI0.LPCB.EC0.MGI6 + MGI7 = _SB.PCI0.LPCB.EC0.MGI7 + MGI8 = _SB.PCI0.LPCB.EC0.MGI8 + MGI9 = _SB.PCI0.LPCB.EC0.MGI9 + MGIA = _SB.PCI0.LPCB.EC0.MGIA + MGIB = _SB.PCI0.LPCB.EC0.MGIB + MGIC = _SB.PCI0.LPCB.EC0.MGIC + MGID = _SB.PCI0.LPCB.EC0.MGID + MGIE = _SB.PCI0.LPCB.EC0.MGIE + MGIF = _SB.PCI0.LPCB.EC0.MGIF + + /* Read Status */ + CCI0 = _SB.PCI0.LPCB.EC0.CCI0 + CCI1 = _SB.PCI0.LPCB.EC0.CCI1 + CCI2 = _SB.PCI0.LPCB.EC0.CCI2 + CCI3 = _SB.PCI0.LPCB.EC0.CCI3 + } + } + Return (Buffer (One) { Zero }) + } +} diff --git a/src/ec/clevo/it5570/chip.c b/src/ec/clevo/it5570/chip.c new file mode 100644 index 0000000..a16266d --- /dev/null +++ b/src/ec/clevo/it5570/chip.c @@ -0,0 +1,331 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <acpi/acpi_device.h> +#include <acpi/acpigen.h> +#include <arch/io.h> +#include <cbmem.h> +#include <commonlib/bsd/helpers.h> +#include <console/console.h> +#include <device/pnp.h> +#include <pc80/keyboard.h> +#include <superio/conf_mode.h> +#include <stdint.h> +#include <stdio.h> +#include "chip.h" + +#define I2EC_ADDR_L 0x10 +#define I2EC_ADDR_H 0x11 +#define I2EC_DATA 0x12 + +#define IT5570_SMFI_LDN 0xf + +#define IT5570_SMFI_LPCMWBA 0xf0 /* LPC Memory Window Base Address */ +#define IT5570_SMFI_HLPCRAMBA 0xf5 /* H2RAM-HLPC Base Address */ +#define IT5570_SMFI_HLPCRAMBA_24 0xfc /* H2RAM-HLPC Base Address */ + +#define IT5570_SMFI_HRAMWC 0x105a /* Host RAM Window Control */ +#define IT5570_SMFI_HRAMW0AAS 0x105d /* Host RAM Window 0 Access Allow Size */ + +enum { + H2RAM_WINDOW_16B, + H2RAM_WINDOW_32B, + H2RAM_WINDOW_64B, + H2RAM_WINDOW_128B, + H2RAM_WINDOW_256B, + H2RAM_WINDOW_512B, + H2RAM_WINDOW_1024B, + H2RAM_WINDOW_2048B, +}; + +/* + * Setting minimum length of UCSI_ACPI will ensure this region is placed out of IMD Small. + * Having this region out of IMD Small will prevent any memory mapping conflicts. + */ +#define UCSI_MIN_ALLOC_REGION_LEN CBMEM_SM_ROOT_SIZE +/* + * The UCSI fields are defined in the UCSI specification at + * https://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-u... + * https://www.intel.com/content/www/us/en/io/universal-serial-bus/bios-impleme... + */ + +static struct fieldlist ucsi_region_fields[] = { + FIELDLIST_NAMESTR("VER0", 8), + FIELDLIST_NAMESTR("VER1", 8), + FIELDLIST_NAMESTR("RSV0", 8), + FIELDLIST_NAMESTR("RSV1", 8), + FIELDLIST_NAMESTR("CCI0", 8), + FIELDLIST_NAMESTR("CCI1", 8), + FIELDLIST_NAMESTR("CCI2", 8), + FIELDLIST_NAMESTR("CCI3", 8), + FIELDLIST_NAMESTR("CTL0", 8), + FIELDLIST_NAMESTR("CTL1", 8), + FIELDLIST_NAMESTR("CTL2", 8), + FIELDLIST_NAMESTR("CTL3", 8), + FIELDLIST_NAMESTR("CTL4", 8), + FIELDLIST_NAMESTR("CTL5", 8), + FIELDLIST_NAMESTR("CTL6", 8), + FIELDLIST_NAMESTR("CTL7", 8), + FIELDLIST_NAMESTR("MGI0", 8), + FIELDLIST_NAMESTR("MGI1", 8), + FIELDLIST_NAMESTR("MGI2", 8), + FIELDLIST_NAMESTR("MGI3", 8), + FIELDLIST_NAMESTR("MGI4", 8), + FIELDLIST_NAMESTR("MGI5", 8), + FIELDLIST_NAMESTR("MGI6", 8), + FIELDLIST_NAMESTR("MGI7", 8), + FIELDLIST_NAMESTR("MGI8", 8), + FIELDLIST_NAMESTR("MGI9", 8), + FIELDLIST_NAMESTR("MGIA", 8), + FIELDLIST_NAMESTR("MGIB", 8), + FIELDLIST_NAMESTR("MGIC", 8), + FIELDLIST_NAMESTR("MGID", 8), + FIELDLIST_NAMESTR("MGIE", 8), + FIELDLIST_NAMESTR("MGIF", 8), + FIELDLIST_NAMESTR("MGO0", 8), + FIELDLIST_NAMESTR("MGO1", 8), + FIELDLIST_NAMESTR("MGO2", 8), + FIELDLIST_NAMESTR("MGO3", 8), + FIELDLIST_NAMESTR("MGO4", 8), + FIELDLIST_NAMESTR("MGO5", 8), + FIELDLIST_NAMESTR("MGO6", 8), + FIELDLIST_NAMESTR("MGO7", 8), + FIELDLIST_NAMESTR("MGO8", 8), + FIELDLIST_NAMESTR("MGO9", 8), + FIELDLIST_NAMESTR("MGOA", 8), + FIELDLIST_NAMESTR("MGOB", 8), + FIELDLIST_NAMESTR("MGOC", 8), + FIELDLIST_NAMESTR("MGOD", 8), + FIELDLIST_NAMESTR("MGOE", 8), + FIELDLIST_NAMESTR("MGOF", 8), +}; +static const size_t ucsi_region_len = ARRAY_SIZE(ucsi_region_fields); + +/* Depth 2 space is always avaiable, no need for conf mode */ +static void i2ec_depth2_write(uint8_t index, uint8_t data) +{ + outb(0x2e,0x2e); + outb(index, 0x2f); + outb(0x2f, 0x2e); + outb(data, 0x2f); +} + +static uint8_t i2ec_depth2_read(uint8_t index) +{ + outb(0x2e,0x2e); + outb(index, 0x2f); + outb(0x2f, 0x2e); + return inb(0x2f); +} + +static uint8_t i2ec_direct_read(uint16_t addr) +{ + i2ec_depth2_write(I2EC_ADDR_H, addr >> 8); + i2ec_depth2_write(I2EC_ADDR_L, addr & 0xff); + return i2ec_depth2_read(I2EC_DATA); +} + +static void i2ec_direct_write(uint16_t addr, uint8_t data) +{ + + i2ec_depth2_write(I2EC_ADDR_H, addr >> 8); + i2ec_depth2_write(I2EC_ADDR_L, addr & 0xff); + i2ec_depth2_write(I2EC_DATA, data); +} + +static void it5570_set_h2ram_base(struct device *dev, uint32_t addr) +{ + uint8_t *h2ram_base = (uint8_t *)&addr; + + if (h2ram_base[3] != 0xfe && h2ram_base[3] != 0xff) { + printk(BIOS_ERR, "ERROR: Invalid H2RAM memory window base\n"); + return; + } + + pnp_enter_conf_mode(dev); + pnp_set_logical_device(dev); + + /* Configure LPC memory window for LGMR */ + pnp_write_config(dev, IT5570_SMFI_LPCMWBA, h2ram_base[3]); + pnp_write_config(dev, IT5570_SMFI_LPCMWBA + 1, h2ram_base[2]); + + /* Configure H2RAM-HLPC base */ + pnp_write_config(dev, IT5570_SMFI_HLPCRAMBA + 1, h2ram_base[2]); + pnp_write_config(dev, IT5570_SMFI_HLPCRAMBA, h2ram_base[1]); + /* H2RAM-HLPC[24] */ + pnp_write_config(dev, IT5570_SMFI_HLPCRAMBA_24, h2ram_base[3] & 1); + + pnp_exit_conf_mode(dev); + + /* Set H2RAM window 0 size to 1K */ + i2ec_direct_write(IT5570_SMFI_HRAMW0AAS, + i2ec_direct_read(IT5570_SMFI_HRAMW0AAS) | H2RAM_WINDOW_1024B); + /* Set H2RAM through LPC Memory cycle, enable window 0 */ + i2ec_direct_write(IT5570_SMFI_HRAMWC, + (i2ec_direct_read(IT5570_SMFI_HRAMWC) & 0xef) | 1); +} + +static bool is_curve_valid(struct ec_clevo_it5570_fan_curve curve) +{ + int i; + + /* + * Fan curve speeds have to be non-decreasing. + * Fan curve temperatures have to be increasing (to avoid division by 0). + * This also covers the case when the curve is all zeroes (i.e. not configured). + */ + + for (i = 1; i < IT5570_FAN_CURVE_LEN; ++i) + if ( curve.speed[i] < curve.speed[i-1] + || curve.temperature[i] <= curve.temperature[i-1]) + return false; + + return true; +} + +static void write_it5570_fan_curve(struct ec_clevo_it5570_fan_curve curve, int fan) +{ + uint16_t ramp; + int j; + char fieldname[5]; + + /* Curve points */ + for (j = 0; j < 4; ++j) { + snprintf(fieldname, 5, "P%dF%d", j+1, fan+1); + acpigen_write_store_int_to_namestr(curve.temperature[j], fieldname); + snprintf(fieldname, 5, "P%dD%d", j+1, fan+1); + acpigen_write_store_int_to_namestr(curve.speed[j] * 255 / 100, fieldname); + } + + /* Ramps */ + for (j = 0; j < 3; ++j) { + snprintf(fieldname, 5, "SH%d%d", fan+1, j+1); + ramp = (float)(curve.speed[j+1] - curve.speed[j]) + / (float)(curve.temperature[j+1] - curve.temperature[j]) + * 2.55 * 16.0; + acpigen_write_store_int_to_namestr(ramp >> 8, fieldname); + snprintf(fieldname, 5, "SL%d%d", fan+1, j+1); + acpigen_write_store_int_to_namestr(ramp & 0xFF, fieldname); + } +} + +static void clevo_it5570_ec_init(struct device *dev) +{ + if (!dev->enabled) + return; + + printk(BIOS_SPEW, "Clevo IT5570 EC init\n"); + + struct device sio_smfi = { + .path.type = DEVICE_PATH_PNP, + .path.pnp.port = 0x2e, + .path.pnp.device = IT5570_SMFI_LDN, + }; + sio_smfi.ops->ops_pnp_mode = &pnp_conf_mode_870155_aa; + + it5570_set_h2ram_base(&sio_smfi, CONFIG_EC_CLEVO_IT5570_RAM_BASE & 0xfffff000); + + pc_keyboard_init(NO_AUX_DEVICE); +} + +static void clevo_it5570_ec_resource(struct device *dev, int index, size_t base, size_t size) +{ + struct resource *res = new_resource(dev, index); + res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + res->base = base; + res->size = size; +} + +static void clevo_it5570_ec_read_resources(struct device *dev) +{ + /* H2RAM resource */ + clevo_it5570_ec_resource(dev, 0, CONFIG_EC_CLEVO_IT5570_RAM_BASE & 0xffff0000, 64*KiB); +} + +static void clevo_it5570_ec_fill_ssdt_generator(const struct device *dev) +{ + const struct ec_clevo_it5570_config *config = config_of(dev); + struct opregion opreg; + void *region_ptr; + size_t ucsi_alloc_region_len; + uint8_t i; + + /* UCSI */ + ucsi_alloc_region_len = ucsi_region_len < UCSI_MIN_ALLOC_REGION_LEN ? + UCSI_MIN_ALLOC_REGION_LEN : ucsi_region_len; + region_ptr = cbmem_add(CBMEM_ID_ACPI_UCSI, ucsi_alloc_region_len); + if (!region_ptr) + return; + memset(region_ptr, 0, ucsi_alloc_region_len); + + opreg.name = "UCSM"; + opreg.regionspace = SYSTEMMEMORY; + opreg.regionoffset = (uintptr_t)region_ptr; + opreg.regionlen = ucsi_region_len; + + acpigen_write_scope(acpi_device_path_join(dev, "UCSI")); + acpigen_write_name_integer("_ADR", 0); + acpigen_write_name("_CRS"); + acpigen_write_resourcetemplate_header(); + acpigen_write_mem32fixed(1, (uintptr_t)region_ptr, ucsi_region_len); + acpigen_write_resourcetemplate_footer(); + acpigen_write_opregion(&opreg); + acpigen_write_field(opreg.name, ucsi_region_fields, ucsi_region_len, + FIELD_ANYACC | FIELD_LOCK | FIELD_PRESERVE); + acpigen_pop_len(); /* Scope */ + + /* Fan curve */ + /* have the function exist even if the fan curve isn't enabled in devicetree */ + acpigen_write_scope(acpi_device_path(dev)); + acpigen_write_method("SFCV", 0); + if (config->fan_mode == FAN_MODE_CUSTOM) { + if (!is_curve_valid(config->fans[0].curve)) { + printk (BIOS_ERR, "EC: Fan 0 curve invalid. Check your devicetree.cb.\n"); + acpigen_pop_len(); /* Method */ + acpigen_pop_len(); /* Scope */ + return; + } + + for (i = 0; i < IT5570_FAN_CNT; ++i) { + if (!is_curve_valid(config->fans[i].curve)) { + printk (BIOS_WARNING, "EC: Fan %d curve invalid. Using fan 0 curve.\n", i); + write_it5570_fan_curve(config->fans[0].curve, i); + } else { + write_it5570_fan_curve(config->fans[i].curve, i); + } + } + + /* Enable custom fan mode */ + acpigen_write_store_int_to_namestr(0x04, "FDAT"); + acpigen_write_store_int_to_namestr(0xD7, "FCMD"); + } + acpigen_pop_len(); /* Method */ + acpigen_pop_len(); /* Scope */ +} + +static const char *clevo_it5570_ec_acpi_name(const struct device *dev) +{ + return "EC0"; +} + +static struct device_operations ops = { + .init = clevo_it5570_ec_init, + .read_resources = clevo_it5570_ec_read_resources, + .set_resources = noop_set_resources, + .acpi_fill_ssdt = clevo_it5570_ec_fill_ssdt_generator, + .acpi_name = clevo_it5570_ec_acpi_name, +}; + +static struct pnp_info info[] = { + { NULL, 0, 0, 0, } +}; + +static void clevo_it5570_ec_enable_dev(struct device *dev) +{ + pnp_enable_devices(dev, &ops, ARRAY_SIZE(info), info); +} + +struct chip_operations ec_clevo_it5570_ops = { + CHIP_NAME("Clevo ITE IT5570 EC") + .enable_dev = clevo_it5570_ec_enable_dev, +}; diff --git a/src/ec/clevo/it5570/chip.h b/src/ec/clevo/it5570/chip.h new file mode 100644 index 0000000..af34b32 --- /dev/null +++ b/src/ec/clevo/it5570/chip.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef EC_CLEVO_IT5570_CHIP_H +#define EC_CLEVO_IT5570_CHIP_H + +#include <acpi/acpi_device.h> + +#define IT5570_FAN_CURVE_LEN 0x4 /* Number of fan curve points */ +#define IT5570_FAN_CNT 0x3 /* Number of configurable fans */ + +enum ec_clevo_it5570_fan_mode { + FAN_MODE_AUTO = 0, + FAN_MODE_CUSTOM, +}; + +struct ec_clevo_it5570_fan_curve { + u8 temperature[IT5570_FAN_CURVE_LEN]; + u8 speed[IT5570_FAN_CURVE_LEN]; +}; + +struct ec_clevo_it5570_fan_config { + struct ec_clevo_it5570_fan_curve curve; +}; + +struct ec_clevo_it5570_config { + enum ec_clevo_it5570_fan_mode fan_mode; + struct ec_clevo_it5570_fan_config fans[IT5570_FAN_CNT]; +}; + +#endif /* EC_CLEVO_IT5570_CHIP_H */ diff --git a/src/ec/clevo/it5570/ec.c b/src/ec/clevo/it5570/ec.c new file mode 100644 index 0000000..d2e58f1 --- /dev/null +++ b/src/ec/clevo/it5570/ec.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <console/console.h> +#include <cpu/x86/smm.h> +#include <ec/acpi/ec.h> + +#include "ec.h" + +#define CLEVO_EC_CMD_ENABLE_ACPI_MODE 0x90 +#define CLEVO_EC_CMD_DISABLE_ACPI_MODE 0x91 + +void clevo_it5570_ec_smi_apmc(int apmc) +{ + switch (apmc) { + case APM_CNT_ACPI_ENABLE: + send_ec_command(CLEVO_EC_CMD_ENABLE_ACPI_MODE); + send_ec_command(0x98); + ec_clr_bit(0xe8, 2); + break; + case APM_CNT_ACPI_DISABLE: + send_ec_command(CLEVO_EC_CMD_DISABLE_ACPI_MODE); + break; + default: + break; + } + +} diff --git a/src/ec/clevo/it5570/ec.h b/src/ec/clevo/it5570/ec.h new file mode 100644 index 0000000..be0927a --- /dev/null +++ b/src/ec/clevo/it5570/ec.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +void clevo_it5570_ec_smi_apmc(int apmc);