From 2727adbeeab36269c083fa7dd653d52cd176344e Mon Sep 17 00:00:00 2001 From: Felix Held Date: Sun, 16 Feb 2025 22:30:43 +0100 Subject: [PATCH] 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/86466 Tested-by: build bot (Jenkins) Reviewed-by: Matt DeVillier --- src/soc/amd/cezanne/acpi.c | 185 ++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/src/soc/amd/cezanne/acpi.c b/src/soc/amd/cezanne/acpi.c index 140c1af9b4..b54b88b2e8 100644 --- a/src/soc/amd/cezanne/acpi.c +++ b/src/soc/amd/cezanne/acpi.c @@ -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(); }