soc/amd/cezanne/acpi: Add ACP MSG0 method

Add the MSG0 method to the ACP's SSDT entry, so that the ACP driver can
talk to a two different mailbox interfaces via this ACPI MSG0 method
interface. This is used by some drivers to configure the ACP's clock
source and to notify the PSP that the audio DSP firmware has been loaded
so that the PSP can validate the firmware and set the qualifier bit to
enable running it.

TEST=The AML code sequence written by this decompiles to the expected
ASL code and the driver is able to initialize the ACP correctly by
calling the MSG0 method twice with different parameters.

Change-Id: I34f641fbfe40b5df7f0ff2fc173510c5cf2a7f61
Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/86466
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Matt DeVillier <matt.devillier@gmail.com>
This commit is contained in:
Felix Held 2025-02-16 22:30:43 +01:00
commit 2727adbeea

View file

@ -106,10 +106,145 @@ static void acp_soc_write_smn_access_methods(void)
acpigen_write_method_end();
}
/* write value of ACPI variable into SMN register */
static void acp_soc_write_smn_register_write(uint8_t op, uint32_t smn_address)
{
acpigen_emit_namestring("^SMNW");
acpigen_write_integer(smn_address);
acpigen_emit_byte(op);
}
/* read SMN register and store value into ACPI variable */
static void acp_soc_write_smn_register_read(uint32_t smn_address, uint8_t op)
{
acpigen_write_store();
acpigen_emit_namestring("^SMNR");
acpigen_write_integer(smn_address);
acpigen_emit_byte(op);
}
static void acp_soc_write_mailbox_access(void)
{
acp_soc_write_smn_register_write(ARG0_OP, 0x00058A74);
acp_soc_write_smn_register_write(ARG1_OP, 0x00058A54);
acp_soc_write_smn_register_write(ARG2_OP, 0x00058A14);
acp_soc_write_smn_register_read(0x00058A74, LOCAL0_OP);
/* While (LEqual (Local0, 0)) */
acpigen_emit_byte(WHILE_OP);
acpigen_write_len_f();
acpigen_emit_byte(LEQUAL_OP);
acpigen_emit_byte(LOCAL0_OP);
acpigen_emit_byte(ZERO_OP);
acp_soc_write_smn_register_read(0x00058A74, LOCAL0_OP);
acpigen_pop_len(); /* While */
acp_soc_write_smn_register_read(0x00058A54, LOCAL1_OP);
acpigen_write_return_op(LOCAL1_OP);
}
static void acp_soc_write_psp_mbox_buffer_field(void)
{
acpigen_write_name("MBOX");
acpigen_write_byte_buffer(NULL, 4);
acpigen_write_create_buffer_word_field("MBOX", 0, "STAT");
acpigen_write_create_buffer_byte_field("MBOX", 2, "CMDI");
acpigen_write_create_buffer_bit_field("MBOX", 31, "REDY");
}
static void acp_soc_write_psp_read_mbox_from_hw(void)
{
acp_soc_write_smn_register_read(0x03810570, LOCAL0_OP);
acpigen_write_store_op_to_namestr(LOCAL0_OP, "MBOX");
}
static void acp_soc_write_psp_write_mbox_to_hw(void)
{
acpigen_write_store_namestr_to_op("MBOX", LOCAL0_OP);
acp_soc_write_smn_register_write(LOCAL0_OP, 0x03810570);
}
static void acp_soc_write_psp_mailbox_access(void)
{
acp_soc_write_psp_mbox_buffer_field();
acp_soc_write_psp_read_mbox_from_hw();
/* While (LOr (LNotEqual (REDY, 0x1), LNotEqual (CMDI, 0x00))) */
acpigen_emit_byte(WHILE_OP);
acpigen_write_len_f();
acpigen_emit_byte(LOR_OP);
acpigen_emit_byte(LNOT_OP);
acpigen_emit_byte(LEQUAL_OP);
acpigen_emit_namestring("REDY");
acpigen_write_integer(1);
acpigen_emit_byte(LNOT_OP);
acpigen_emit_byte(LEQUAL_OP);
acpigen_emit_namestring("CMDI");
acpigen_write_integer(0);
acp_soc_write_psp_read_mbox_from_hw();
acpigen_pop_len(); /* While */
acpigen_write_store_int_to_op(0, LOCAL0_OP);
acpigen_write_store_op_to_namestr(LOCAL0_OP, "MBOX");
acpigen_write_store_int_to_namestr(0x33, "CMDI");
acp_soc_write_psp_write_mbox_to_hw();
acpigen_write_sleep(1);
acp_soc_write_psp_read_mbox_from_hw();
/* While (LNotEqual (CMDI, 0x00)) */
acpigen_emit_byte(WHILE_OP);
acpigen_write_len_f();
acpigen_emit_byte(LNOT_OP);
acpigen_emit_byte(LEQUAL_OP);
acpigen_emit_namestring("CMDI");
acpigen_write_integer(0);
acp_soc_write_psp_read_mbox_from_hw();
acpigen_pop_len(); /* While */
acpigen_write_return_op(LOCAL0_OP);
}
static void acp_soc_write_msg0_method(void)
{
acpigen_write_method_serialized("MSG0", 3);
/* If (ARG2 != 0x9) */
acpigen_write_if_lnotequal_op_int(ARG2_OP, 0x9);
acp_soc_write_mailbox_access();
acpigen_write_else();
acp_soc_write_psp_mailbox_access();
acpigen_write_if_end();
acpigen_write_method_end(); /* MSG0 */
}
void acp_soc_write_ssdt_entry(const struct device *dev)
{
/*
* SMN interface using the SMN OperationRegion on the host bridge
* SMN and mailbox interface using the SMN OperationRegion on the host bridge
*
* Provide both SMN read/write methods for direct SMN register access and the MSG0
* method which is used by some ACP drivers to access two different mailbox interfaces
* in the hardware. One mailbox interface is used to configure the ACP's clock source,
* the other one is used to notify the PSP that the DSP firmware has been loaded, so
* that the PSP can validate the firmware and set the qualifier bit to enable running
* it.
*
* Scope (\_SB.PCI0.GP41.ACPD)
* {
@ -124,11 +259,59 @@ void acp_soc_write_ssdt_entry(const struct device *dev)
* Store (Arg0, \_SB.PCI0.GNB.SMNA)
* Store (Arg1, \_SB.PCI0.GNB.SMND)
* }
*
* Method (MSG0, 3, Serialized)
* {
* If (LNotEqual (Arg2, 0x09))
* {
* ^SMNW (0x00058A74, Arg0)
* ^SMNW (0x00058A54, Arg1)
* ^SMNW (0x00058A14, Arg2)
* Store (^SMNR (0x00058A74), Local0)
* While (LEqual (Local0, Zero))
* {
* Store (^SMNR (0x00058A74), Local0)
* }
* Store (^SMNR (0x00058A54), Local1)
* Return (Local1)
* }
* Else
* {
* Name (MBOX, Buffer (0x04){})
* CreateWordField (MBOX, Zero, STAT)
* CreateByteField (MBOX, 0x02, CMDI)
* CreateBitField (MBOX, 0x1F, REDY)
* Store (^SMNR (0x03810570), Local0)
* Store (Local0, MBOX)
* While (LOr (LNotEqual (REDY, One), LNotEqual (CMDI, Zero)))
* {
* Store (^SMNR (0x03810570), Local0)
* Store (Local0, MBOX)
* }
* Store (Zero, Local0)
* Store (Local0, MBOX)
* Store (0x33, CMDI)
* Store (MBOX, Local0)
* ^SMNW (0x03810570, Local0)
* Sleep (One)
* Store (^SMNR (0x03810570), Local0)
* Store (Local0, MBOX)
* While (LNotEqual (CMDI, Zero))
* {
* Store (^SMNR (0x03810570), Local0)
* Store (Local0, MBOX)
* }
* Return (Local0)
* }
* }
* }
*/
acpigen_write_scope(acpi_device_path(dev));
acp_soc_write_smn_access_methods();
acp_soc_write_msg0_method();
acpigen_write_scope_end();
}