summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/superio/common/ssdt.md29
-rw-r--r--src/superio/common/generic.c140
-rw-r--r--src/superio/common/ssdt.c26
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 */
}