superio/common: Add more ACPI methods

* Make use of introduced SSDT config mode access
* Make use of introduced SSDT mutex
* Provide ACPI functions to safely access SIO config space
* Implement method to query LDN enable state
* Implement method to set LDN enable state
* Use introduced functions to implement _DIS and _STA in the device
* Update documentation

Tested on Aspeed AST2500 and Linux 5.2.
Manually verified ACPI code that generates no errors in Linux.

Change-Id: I520b29de925f368cd71ff8f1f58d2d57d72eff8d
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/37640
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
Patrick Rudolph 2019-12-10 14:12:03 +01:00 committed by Felix Held
parent 7db16ddc88
commit 95bff2e17e
3 changed files with 190 additions and 5 deletions

View File

@ -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

View File

@ -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 */
}

View File

@ -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 */
}