soc/amd: add ACPI code for I3C controller

Add the I3C controllers to the ACPI tables. Most of the ACPI code needed
for that is added to the DSDT, since everything, but the enable status
of the I3C MMIO devices is known at build-time. To handle the I3C
controller enable status, each ACPI device contains the STAT name with
the value of 0 in the DSDT and when the device is enabled this STAT name
will be overridden in the SSDT.

TEST=OS loads the I3C kernel modules on amd/birman_plus.

Change-Id: I309d54c81056486573c32d4da54de61b36b5c378
Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/87282
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Maximilian Brune <maximilian.brune@9elements.com>
This commit is contained in:
Felix Held 2025-04-11 18:06:02 +02:00
commit c195859748
5 changed files with 848 additions and 0 deletions

View file

@ -1,6 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpigen.h>
#include <amdblocks/i2c.h>
#include <console/console.h>
#include <device/device.h>
#include <types.h>
#if CONFIG(HAVE_ACPI_TABLES)
static const char *i3c_acpi_name(const struct device *dev)
{
size_t i;
size_t num_ctrlrs;
const struct soc_i3c_ctrlr_info *ctrlr = soc_get_i3c_ctrlr_info(&num_ctrlrs);
if (!(uintptr_t)dev->path.mmio.addr) {
printk(BIOS_ERR, "NULL MMIO address at %s\n", __func__);
return NULL;
}
for (i = 0; i < num_ctrlrs; i++) {
if ((uintptr_t)dev->path.mmio.addr == ctrlr[i].bar)
return ctrlr[i].acpi_name;
}
printk(BIOS_ERR, "%s: Could not find %lu\n", __func__, (uintptr_t)dev->path.mmio.addr);
return NULL;
}
static void i3c_acpi_fill_ssdt(const struct device *dev)
{
acpigen_write_scope(acpi_device_path(dev));
acpigen_write_store_int_to_namestr(acpi_device_status(dev), "STAT");
acpigen_pop_len(); /* Scope */
}
#endif
static void i3c_read_resources(struct device *dev)
{
@ -10,4 +42,8 @@ static void i3c_read_resources(struct device *dev)
struct device_operations soc_amd_i3c_mmio_ops = {
.read_resources = i3c_read_resources,
.set_resources = noop_set_resources,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_name = i3c_acpi_name,
.acpi_fill_ssdt = i3c_acpi_fill_ssdt,
#endif
};

View file

@ -392,6 +392,187 @@ Device (I2C5)
AOAC_DEVICE(FCH_AOAC_DEV_I2C5, 0)
}
Device (I3C0) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x0)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II20
} Else {
IRQN = PI20
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C0, 0)
}
Device (I3C1) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x1)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II21
} Else {
IRQN = PI21
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C1, 0)
}
Device (I3C2) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x2)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II22
} Else {
IRQN = PI22
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C2, 0)
}
Device (I3C3)
{
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x3)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II23
} Else {
IRQN = PI23
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C3, 0)
}
Device (MISC)
{
Name (_HID, "AMD0040")

View file

@ -3,6 +3,7 @@
/* TODO: Update for Glinda */
#include <soc/amd/common/acpi/aoac.asl>
#include <soc/amd_pci_int_defs.h>
#include <soc/aoac_defs.h>
#include <soc/gpio.h>
#include <soc/iomap.h>
@ -405,6 +406,274 @@ Device (I2C3)
#endif
}
Device (I3C0) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI5017" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI5017")
} Else {
Return ("AMDI0016")
}
}
Name (_CID, "MIPI0100")
Name (_UID, 0x0)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II20
} Else {
IRQN = PI20
}
If (IRQN == PIRQ_NC) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method(_DSD, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Extension
Package () {
"mipi-i3c-ctrlr-0-subproperties", CTR0,
}
})
}
Method(CTR0, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
}
})
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C0, 0)
}
Device (I3C1) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI5017" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI5017")
} Else {
Return ("AMDI0016")
}
}
Name (_CID, "MIPI0100")
Name (_UID, 0x1)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II21
} Else {
IRQN = PI21
}
If (IRQN == PIRQ_NC) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method(_DSD, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Extension
Package () {
"mipi-i3c-ctrlr-0-subproperties", CTR0,
}
})
}
Method(CTR0, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
}
})
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C1, 0)
}
Device (I3C2) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI5017" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI5017")
} Else {
Return ("AMDI0016")
}
}
Name (_CID, "MIPI0100")
Name (_UID, 0x2)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II22
} Else {
IRQN = PI22
}
If (IRQN == PIRQ_NC) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method(_DSD, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Extension
Package () {
"mipi-i3c-ctrlr-0-subproperties", CTR0,
}
})
}
Method(CTR0, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
}
})
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C2, 0)
}
Device (I3C3)
{
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI5017" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI5017")
} Else {
Return ("AMDI0016")
}
}
Name (_CID, "MIPI0100")
Name (_UID, 0x3)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II23
} Else {
IRQN = PI23
}
If (IRQN == PIRQ_NC) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
Method(_DSD, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
},
ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), // Hierarchical Extension
Package () {
"mipi-i3c-ctrlr-0-subproperties", CTR0,
}
})
}
Method(CTR0, 0, Serialized){
Return(Package() {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
"mipi-i3c-sw-interface-revision", 0x10000, // 1.0
}
})
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C3, 0)
}
Device (MISC)
{
Name (_HID, "AMD0040")

View file

@ -402,6 +402,187 @@ Device (I2C3)
#endif
}
Device (I3C0) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x0)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II20
} Else {
IRQN = PI20
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C0, 0)
}
Device (I3C1) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x1)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II21
} Else {
IRQN = PI21
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C1, 0)
}
Device (I3C2) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x2)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II22
} Else {
IRQN = PI22
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C2, 0)
}
Device (I3C3)
{
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x3)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II23
} Else {
IRQN = PI23
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C3, 0)
}
Device (MISC)
{
Name (_HID, "AMD0040")

View file

@ -402,6 +402,187 @@ Device (I2C3)
#endif
}
Device (I3C0) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x0)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II20
} Else {
IRQN = PI20
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C0_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C0, 0)
}
Device (I3C1) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x1)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II21
} Else {
IRQN = PI21
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C1_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C1, 0)
}
Device (I3C2) {
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x2)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II22
} Else {
IRQN = PI22
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C2_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C2, 0)
}
Device (I3C3)
{
Name (STAT, 0x0)
/* Only return I3C controller HID "AMDI0015" when device is enabled in devicetree */
Method (_HID, 0x0) {
If (STAT) {
Return ("AMDI0015")
} Else {
Return ("AMDI0016")
}
}
Name (_UID, 0x3)
Method (_CRS, 0) {
Local0 = ResourceTemplate() {
Interrupt (
ResourceConsumer,
Edge,
ActiveHigh,
Exclusive, , , IRQR)
{ 0 }
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
}
CreateDWordField (Local0, IRQR._INT, IRQN)
If (PICM) {
IRQN = II23
} Else {
IRQN = PI23
}
If (IRQN == 0x1f) {
Return (ResourceTemplate() {
Memory32Fixed (ReadWrite, APU_I3C3_BASE, 0x1000)
})
} Else {
Return (Local0)
}
}
Method (_STA, 0x0, NotSerialized)
{
Return (STAT)
}
AOAC_DEVICE(FCH_AOAC_DEV_I3C3, 0)
}
Device (MISC)
{
Name (_HID, "AMD0040")