diff options
-rw-r--r-- | Documentation/superio/common/ssdt.md | 29 | ||||
-rw-r--r-- | src/superio/common/generic.c | 140 | ||||
-rw-r--r-- | src/superio/common/ssdt.c | 26 |
3 files changed, 190 insertions, 5 deletions
diff --git a/Documentation/superio/common/ssdt.md b/Documentation/superio/common/ssdt.md index f2bb3346a0..2f4049ef12 100644 --- a/Documentation/superio/common/ssdt.md +++ b/Documentation/superio/common/ssdt.md @@ -45,12 +45,33 @@ chip superio/common end ``` +## Automatically generated methods + +The following methods are generated for each SuperIO: +## AMTX() +Acquire the global mutex and enter config mode. +It's called this at the begining of an atomic operation to make sure +no other ACPI code messes with the config space while working on it. + +## RMTX() +Exit config mode and release the global mutex. +It's called at the end of an atomic operation. + +## SLDN(Arg0) +Selects the (virtual) LDN given as Arg0. +This method isn't guarded with the global mutex. + +## DLDN(Arg0) +Disables the (virtual) LDN given as Arg0. +This method aquires the global mutex. + +## QLDN(Arg0) +Queries the state of the (virtual) LDN given as Arg0. +This method quires the global mutex. + ## TODO 1) Add ACPI HIDs to every SuperIO driver -2) Don't guess ACPI HID of LDNs if it's known -3) Add "enter config" and "exit config" bytes -4) Generate support methods that allow +2) Generate support methods that allow * Setting resource settings at runtime * Getting resource settings at runtime - * Disabling LDNs at runtime diff --git a/src/superio/common/generic.c b/src/superio/common/generic.c index 7ac1f8374e..85b70df1b5 100644 --- a/src/superio/common/generic.c +++ b/src/superio/common/generic.c @@ -156,6 +156,146 @@ static void generic_ssdt(struct device *dev) acpigen_write_indexfield("INDX", "DATA", i, ARRAY_SIZE(i), FIELD_BYTEACC | FIELD_NOLOCK | FIELD_PRESERVE); + const char *mutex = "MTX0"; + + acpigen_write_mutex(mutex, 0); + /* Backup LDN */ + acpigen_write_name_integer("BLDN", 0); + + /* Acquire mutex - Enter config mode */ + acpigen_write_method("AMTX", 0); + { + acpigen_write_acquire(mutex, 0xffff); + + /* Pick one of the children as the generic SIO doesn't have config mode */ + if (dev->link_list && dev->link_list->children) + pnp_ssdt_enter_conf_mode(dev->link_list->children, "^INDX", "^DATA"); + + /* Backup LDN */ + acpigen_write_store(); + acpigen_emit_namestring("^LDN"); + acpigen_emit_namestring("^BLDN"); + } + acpigen_pop_len(); /* Method */ + + /* Release mutex - Exit config mode */ + acpigen_write_method("RMTX", 0); + { + /* Restore LDN */ + acpigen_write_store(); + acpigen_emit_namestring("^BLDN"); + acpigen_emit_namestring("^LDN"); + + /* Pick one of the children as the generic SIO doesn't have config mode */ + if (dev->link_list && dev->link_list->children) + pnp_ssdt_exit_conf_mode(dev->link_list->children, "^INDX", "^DATA"); + + acpigen_write_release(mutex); + } + acpigen_pop_len(); /* Method */ + + /* Select a LDN */ + acpigen_write_method("SLDN", 1); + { + /* Local0 = Arg0 & 0xff */ + acpigen_emit_byte(AND_OP); + acpigen_write_integer(0xff); + acpigen_emit_byte(ARG0_OP); + acpigen_emit_byte(LOCAL0_OP); + + /* LDN = LOCAL0_OP */ + acpigen_write_store(); + acpigen_emit_byte(LOCAL0_OP); + acpigen_emit_namestring("^LDN"); + } + acpigen_pop_len(); /* Method */ + + /* Disable a LDN/VLDN */ + acpigen_write_method("DLDN", 1); + { + /* AMTX() */ + acpigen_emit_namestring("AMTX"); + + /* SLDN (Local0) */ + acpigen_emit_namestring("SLDN"); + acpigen_emit_byte(ARG0_OP); + + /* Local0 = Arg0 >> 8 */ + acpigen_emit_byte(SHIFT_RIGHT_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_integer(8); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 = Local0 & 0x7 */ + acpigen_emit_byte(AND_OP); + acpigen_write_integer(0x7); + acpigen_emit_byte(LOCAL0_OP); + acpigen_emit_byte(LOCAL0_OP); + + for (int j = 0; j < 8; j++) { + char act[6] = "^ACT0"; + act[4] += j; + + /* If (Local0 == j) { */ + acpigen_write_if_lequal_op_int(LOCAL0_OP, j); + + /* ACT[j] = 0 */ + acpigen_write_store(); + acpigen_emit_byte(ZERO_OP); + acpigen_emit_namestring(act); + + acpigen_pop_len(); /* } */ + } + + /* RMTX() */ + acpigen_emit_namestring("RMTX"); + } + acpigen_pop_len(); /* Method */ + + /* Query LDN enable state. Returns 1 if LDN/VLDN is enabled. */ + acpigen_write_method("QLDN", 1); + { + acpigen_emit_namestring("AMTX"); + + /* SLDN (Local0) */ + acpigen_emit_namestring("SLDN"); + acpigen_emit_byte(ARG0_OP); + + /* Local0 = Arg0 >> 8 */ + acpigen_emit_byte(SHIFT_RIGHT_OP); + acpigen_emit_byte(ARG0_OP); + acpigen_write_integer(8); + acpigen_emit_byte(LOCAL0_OP); + + /* Local0 = Local0 & 0x7 */ + acpigen_emit_byte(AND_OP); + acpigen_write_integer(0x7); + acpigen_emit_byte(LOCAL0_OP); + acpigen_emit_byte(LOCAL0_OP); + + for (int j = 0; j < 8; j++) { + char act[6] = "^ACT0"; + act[4] += j; + /* If (Local0 == j) { */ + acpigen_write_if_lequal_op_int(LOCAL0_OP, j); + + /* Local1 = ACT[j] */ + acpigen_write_store(); + acpigen_emit_namestring(act); + acpigen_emit_byte(LOCAL1_OP); + + acpigen_pop_len(); /* } */ + } + + /* RMTX() */ + acpigen_emit_namestring("RMTX"); + + /* Return (Local1) */ + acpigen_emit_byte(RETURN_OP); + acpigen_emit_byte(LOCAL1_OP); + } + acpigen_pop_len(); /* Method */ + acpigen_pop_len(); /* Device */ acpigen_pop_len(); /* Scope */ } diff --git a/src/superio/common/ssdt.c b/src/superio/common/ssdt.c index a919aa5620..bc5d39460a 100644 --- a/src/superio/common/ssdt.c +++ b/src/superio/common/ssdt.c @@ -200,7 +200,24 @@ void superio_common_fill_ssdt_generator(struct device *dev) acpigen_write_name_byte("LDN", ldn); acpigen_write_name_byte("VLDN", vldn); - acpigen_write_STA(dev->enabled ? 0xf : 0); + acpigen_write_method("_STA", 0); + { + acpigen_write_store(); + acpigen_emit_namestring("^^QLDN"); + acpigen_write_integer(ldn); + acpigen_emit_byte(LOCAL0_OP); + + /* Multiply (Local0, 0xf, Local0) */ + acpigen_emit_byte(MULTIPLY_OP); + acpigen_emit_byte(LOCAL0_OP); + acpigen_write_integer(0xf); + acpigen_emit_byte(LOCAL0_OP); + + acpigen_emit_byte(RETURN_OP); + acpigen_emit_byte(LOCAL0_OP); + + } + acpigen_pop_len(); /* Method */ if (!dev->enabled) { acpigen_pop_len(); /* Device */ @@ -242,6 +259,13 @@ void superio_common_fill_ssdt_generator(struct device *dev) acpigen_write_name_string("_HID", hid); acpigen_write_name_string("_DDN", name_from_hid(hid)); + acpigen_write_method("_DIS", 0); + { + acpigen_emit_namestring("^^DLDN"); + acpigen_write_integer(ldn); + } + acpigen_pop_len(); /* Method */ + acpigen_pop_len(); /* Device */ acpigen_pop_len(); /* Scope */ } |