summaryrefslogtreecommitdiff
path: root/src/soc
diff options
context:
space:
mode:
authorMartin Roth <martin.roth@amd.corp-partner.google.com>2022-10-06 15:57:21 -0600
committerMartin Roth <martin.roth@amd.corp-partner.google.com>2022-10-10 21:48:30 +0000
commit1a3de8e5bcc5c83934fa2a690e125b843e8b01ab (patch)
tree0df3332114bde60848c018a9b5de245a9568ba4a /src/soc
parent134908381f2b25063558f2ce1414fa70243c9c55 (diff)
soc/amd/morgana: Add initial commit for new SoC
This is an initial framework for the Morgana SoC. TODOs have been added to the files for both customization and commonization. Signed-off-by: Martin Roth <martin.roth@amd.corp-partner.google.com> Change-Id: If92e129db10d41595e1dc18a7c1dfe99d57790cc Reviewed-on: https://review.coreboot.org/c/coreboot/+/68195 Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com> Reviewed-by: Marshall Dawson <marshalldawson3rd@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/amd/morgana/Kconfig516
-rw-r--r--src/soc/amd/morgana/Makefile.inc330
-rw-r--r--src/soc/amd/morgana/acpi.c370
-rw-r--r--src/soc/amd/morgana/acpi/globalnvs.asl22
-rw-r--r--src/soc/amd/morgana/acpi/mmio.asl390
-rw-r--r--src/soc/amd/morgana/acpi/pci0.asl86
-rw-r--r--src/soc/amd/morgana/acpi/pci_int_defs.asl71
-rw-r--r--src/soc/amd/morgana/acpi/soc.asl52
-rw-r--r--src/soc/amd/morgana/agesa_acpi.c28
-rw-r--r--src/soc/amd/morgana/aoac.c62
-rw-r--r--src/soc/amd/morgana/bootblock.c52
-rw-r--r--src/soc/amd/morgana/chip.c113
-rw-r--r--src/soc/amd/morgana/chip.h113
-rw-r--r--src/soc/amd/morgana/chipset.cb95
-rw-r--r--src/soc/amd/morgana/config.c12
-rw-r--r--src/soc/amd/morgana/cpu.c60
-rw-r--r--src/soc/amd/morgana/data_fabric.c153
-rw-r--r--src/soc/amd/morgana/early_fch.c82
-rw-r--r--src/soc/amd/morgana/espi_util.c22
-rw-r--r--src/soc/amd/morgana/fch.c230
-rw-r--r--src/soc/amd/morgana/fsp_m_params.c169
-rw-r--r--src/soc/amd/morgana/fsp_s_params.c43
-rw-r--r--src/soc/amd/morgana/fw.cfg38
-rw-r--r--src/soc/amd/morgana/gpio.c41
-rw-r--r--src/soc/amd/morgana/i2c.c59
-rw-r--r--src/soc/amd/morgana/include/soc/acpi.h23
-rw-r--r--src/soc/amd/morgana/include/soc/amd_pci_int_defs.h64
-rw-r--r--src/soc/amd/morgana/include/soc/aoac_defs.h25
-rw-r--r--src/soc/amd/morgana/include/soc/cpu.h8
-rw-r--r--src/soc/amd/morgana/include/soc/data_fabric.h19
-rw-r--r--src/soc/amd/morgana/include/soc/espi.h10
-rw-r--r--src/soc/amd/morgana/include/soc/gpio.h326
-rw-r--r--src/soc/amd/morgana/include/soc/i2c.h30
-rw-r--r--src/soc/amd/morgana/include/soc/iomap.h59
-rw-r--r--src/soc/amd/morgana/include/soc/lpc.h23
-rw-r--r--src/soc/amd/morgana/include/soc/msr.h48
-rw-r--r--src/soc/amd/morgana/include/soc/nvs.h29
-rw-r--r--src/soc/amd/morgana/include/soc/pci_devs.h135
-rw-r--r--src/soc/amd/morgana/include/soc/platform_descriptors.h19
-rw-r--r--src/soc/amd/morgana/include/soc/psp_transfer.h64
-rw-r--r--src/soc/amd/morgana/include/soc/psp_verstage_addr.h25
-rw-r--r--src/soc/amd/morgana/include/soc/smi.h191
-rw-r--r--src/soc/amd/morgana/include/soc/smu.h25
-rw-r--r--src/soc/amd/morgana/include/soc/southbridge.h127
-rw-r--r--src/soc/amd/morgana/include/soc/uart.h13
-rw-r--r--src/soc/amd/morgana/mca.c45
-rw-r--r--src/soc/amd/morgana/preload.c13
-rw-r--r--src/soc/amd/morgana/psp_verstage/Makefile.inc19
-rw-r--r--src/soc/amd/morgana/psp_verstage/chipset.c115
-rw-r--r--src/soc/amd/morgana/psp_verstage/svc.c218
-rw-r--r--src/soc/amd/morgana/psp_verstage/svc.h149
-rw-r--r--src/soc/amd/morgana/psp_verstage/uart.c13
-rw-r--r--src/soc/amd/morgana/reset.c29
-rw-r--r--src/soc/amd/morgana/romstage.c28
-rw-r--r--src/soc/amd/morgana/root_complex.c252
-rw-r--r--src/soc/amd/morgana/smihandler.c160
-rw-r--r--src/soc/amd/morgana/smu.c19
-rw-r--r--src/soc/amd/morgana/uart.c129
-rw-r--r--src/soc/amd/morgana/xhci.c67
59 files changed, 5728 insertions, 0 deletions
diff --git a/src/soc/amd/morgana/Kconfig b/src/soc/amd/morgana/Kconfig
new file mode 100644
index 0000000000..8c7d87c4d2
--- /dev/null
+++ b/src/soc/amd/morgana/Kconfig
@@ -0,0 +1,516 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# TODO: Evaluate what can be moved to a common directory
+# TODO: Update for Morgana
+
+config SOC_AMD_MORGANA
+ bool
+ help
+ AMD Morgana support
+
+if SOC_AMD_MORGANA
+
+config SOC_SPECIFIC_OPTIONS
+ def_bool y
+ select ACPI_SOC_NVS
+ select ARCH_BOOTBLOCK_X86_32
+ select ARCH_VERSTAGE_X86_32 if !VBOOT_STARTS_BEFORE_BOOTBLOCK
+ select ARCH_ROMSTAGE_X86_32
+ select ARCH_RAMSTAGE_X86_32
+ select ARCH_X86
+ select BOOT_DEVICE_SUPPORTS_WRITES if BOOT_DEVICE_SPI_FLASH
+ select DRIVERS_USB_ACPI
+ select DRIVERS_USB_PCI_XHCI
+ select FSP_COMPRESS_FSP_M_LZMA if !ASYNC_FILE_LOADING
+ select FSP_COMPRESS_FSP_M_LZ4 if ASYNC_FILE_LOADING
+ select FSP_COMPRESS_FSP_S_LZ4
+ select GENERIC_GPIO_LIB
+ select HAVE_ACPI_TABLES
+ select HAVE_CF9_RESET
+ select HAVE_EM100_SUPPORT
+ select HAVE_FSP_GOP
+ select HAVE_SMI_HANDLER
+ select IDT_IN_EVERY_STAGE
+ select PARALLEL_MP_AP_WORK
+ select PLATFORM_USES_FSP2_0
+ select PROVIDES_ROM_SHARING
+ select PSP_SUPPORTS_EFS2_RELATIVE_ADDR if VBOOT_STARTS_BEFORE_BOOTBLOCK
+ select PSP_VERSTAGE_CCP_DMA if VBOOT_STARTS_BEFORE_BOOTBLOCK
+ select RESET_VECTOR_IN_RAM
+ select RTC
+ select SOC_AMD_COMMON
+ select SOC_AMD_COMMON_BLOCK_ACP_GEN2
+ select SOC_AMD_COMMON_BLOCK_ACPI
+ select SOC_AMD_COMMON_BLOCK_ACPIMMIO
+ select SOC_AMD_COMMON_BLOCK_ACPI_ALIB
+ select SOC_AMD_COMMON_BLOCK_ACPI_CPPC
+ select SOC_AMD_COMMON_BLOCK_ACPI_GPIO
+ select SOC_AMD_COMMON_BLOCK_ACPI_IVRS
+ select SOC_AMD_COMMON_BLOCK_AOAC
+ select SOC_AMD_COMMON_BLOCK_APOB
+ select SOC_AMD_COMMON_BLOCK_APOB_HASH
+ select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS
+ select SOC_AMD_COMMON_BLOCK_DATA_FABRIC
+ select SOC_AMD_COMMON_BLOCK_ESPI_EXTENDED_DECODE_RANGES
+ select SOC_AMD_COMMON_BLOCK_GRAPHICS
+ select SOC_AMD_COMMON_BLOCK_HAS_ESPI
+ select SOC_AMD_COMMON_BLOCK_HAS_ESPI_ALERT_ENABLE
+ select SOC_AMD_COMMON_BLOCK_I2C
+ select SOC_AMD_COMMON_BLOCK_I23C_PAD_CTRL
+ select SOC_AMD_COMMON_BLOCK_IOMMU
+ select SOC_AMD_COMMON_BLOCK_LPC
+ select SOC_AMD_COMMON_BLOCK_MCAX
+ select SOC_AMD_COMMON_BLOCK_NONCAR
+ select SOC_AMD_COMMON_BLOCK_PCI
+ select SOC_AMD_COMMON_BLOCK_PCI_MMCONF
+ select SOC_AMD_COMMON_BLOCK_PCIE_GPP_DRIVER
+ select SOC_AMD_COMMON_BLOCK_PM
+ select SOC_AMD_COMMON_BLOCK_PM_CHIPSET_STATE_SAVE
+ select SOC_AMD_COMMON_BLOCK_PSP_GEN2
+ select SOC_AMD_COMMON_BLOCK_SMBUS
+ select SOC_AMD_COMMON_BLOCK_SMI
+ select SOC_AMD_COMMON_BLOCK_SMM
+ select SOC_AMD_COMMON_BLOCK_SMU
+ select SOC_AMD_COMMON_BLOCK_SPI
+ select SOC_AMD_COMMON_BLOCK_TSC_FAM17H_19H
+ select SOC_AMD_COMMON_BLOCK_UART
+ select SOC_AMD_COMMON_BLOCK_UCODE
+ select SOC_AMD_COMMON_FSP_CCX_CPPC_HOB
+ select SOC_AMD_COMMON_FSP_DMI_TABLES
+ select SOC_AMD_COMMON_FSP_PCI
+ select SSE2
+ select UDK_2017_BINDING
+ select USE_FSP_NOTIFY_PHASE_POST_PCI_ENUM
+ select USE_FSP_NOTIFY_PHASE_READY_TO_BOOT
+ select USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE
+ select VBOOT_DEFINE_WIDEVINE_COUNTERS if VBOOT_STARTS_BEFORE_BOOTBLOCK
+ select X86_AMD_FIXED_MTRRS
+ select X86_INIT_NEED_1_SIPI
+
+config ARCH_ALL_STAGES_X86
+ default n
+
+config CHIPSET_DEVICETREE
+ string
+ default "soc/amd/morgana/chipset.cb"
+
+config EARLY_RESERVED_DRAM_BASE
+ hex
+ default 0x2000000
+ help
+ This variable defines the base address of the DRAM which is reserved
+ for usage by coreboot in early stages (i.e. before ramstage is up).
+ This memory gets reserved in BIOS tables to ensure that the OS does
+ not use it, thus preventing corruption of OS memory in case of S3
+ resume.
+
+config EARLYRAM_BSP_STACK_SIZE
+ hex
+ default 0x1000
+
+config PSP_APOB_DRAM_ADDRESS
+ hex
+ default 0x2001000
+ help
+ Location in DRAM where the PSP will copy the AGESA PSP Output
+ Block.
+
+config PSP_APOB_DRAM_SIZE
+ hex
+ default 0x1E000
+
+config PSP_SHAREDMEM_BASE
+ hex
+ default 0x201F000 if VBOOT
+ default 0x0
+ help
+ This variable defines the base address in DRAM memory where PSP copies
+ the vboot workbuf. This is used in the linker script to have a static
+ allocation for the buffer as well as for adding relevant entries in
+ the BIOS directory table for the PSP.
+
+config PSP_SHAREDMEM_SIZE
+ hex
+ default 0x8000 if VBOOT
+ default 0x0
+ help
+ Sets the maximum size for the PSP to pass the vboot workbuf and
+ any logs or timestamps back to coreboot. This will be copied
+ into main memory by the PSP and will be available when the x86 is
+ started. The workbuf's base depends on the address of the reset
+ vector.
+
+config PRE_X86_CBMEM_CONSOLE_SIZE
+ hex
+ default 0x1600
+ help
+ Size of the CBMEM console used in PSP verstage.
+
+config PRERAM_CBMEM_CONSOLE_SIZE
+ hex
+ default 0x1600
+ help
+ Increase this value if preram cbmem console is getting truncated
+
+config CBFS_MCACHE_SIZE
+ hex
+ default 0x2000 if VBOOT_STARTS_BEFORE_BOOTBLOCK
+
+config C_ENV_BOOTBLOCK_SIZE
+ hex
+ default 0x10000
+ help
+ Sets the size of the bootblock stage that should be loaded in DRAM.
+ This variable controls the DRAM allocation size in linker script
+ for bootblock stage.
+
+config ROMSTAGE_ADDR
+ hex
+ default 0x2040000
+ help
+ Sets the address in DRAM where romstage should be loaded.
+
+config ROMSTAGE_SIZE
+ hex
+ default 0x80000
+ help
+ Sets the size of DRAM allocation for romstage in linker script.
+
+config FSP_M_ADDR
+ hex
+ default 0x20C0000
+ help
+ Sets the address in DRAM where FSP-M should be loaded. cbfstool
+ performs relocation of FSP-M to this address.
+
+config FSP_M_SIZE
+ hex
+ default 0xC0000
+ help
+ Sets the size of DRAM allocation for FSP-M in linker script.
+
+config FSP_TEMP_RAM_SIZE
+ hex
+ default 0x40000
+ help
+ The amount of coreboot-allocated heap and stack usage by the FSP.
+
+config VERSTAGE_ADDR
+ hex
+ depends on VBOOT_SEPARATE_VERSTAGE
+ default 0x2180000
+ help
+ Sets the address in DRAM where verstage should be loaded if running
+ as a separate stage on x86.
+
+config VERSTAGE_SIZE
+ hex
+ depends on VBOOT_SEPARATE_VERSTAGE
+ default 0x80000
+ help
+ Sets the size of DRAM allocation for verstage in linker script if
+ running as a separate stage on x86.
+
+config ASYNC_FILE_LOADING
+ bool "Loads files from SPI asynchronously"
+ select COOP_MULTITASKING
+ select SOC_AMD_COMMON_BLOCK_LPC_SPI_DMA
+ select CBFS_PRELOAD
+ help
+ When enabled, the platform will use the LPC SPI DMA controller to
+ asynchronously load contents from the SPI ROM. This will improve
+ boot time because the CPUs can be performing useful work while the
+ SPI contents are being preloaded.
+
+config CBFS_CACHE_SIZE
+ hex
+ default 0x40000 if CBFS_PRELOAD
+
+config RO_REGION_ONLY
+ string
+ depends on VBOOT_SLOTS_RW_AB || VBOOT_SLOTS_RW_A
+ default "apu/amdfw"
+
+config ECAM_MMCONF_BASE_ADDRESS
+ default 0xF8000000
+
+config ECAM_MMCONF_BUS_NUMBER
+ default 64
+
+config MAX_CPUS
+ int
+ default 8 if SOC_AMD_MORGANA
+ default 16
+ help
+ Maximum number of threads the platform can have.
+
+config CONSOLE_UART_BASE_ADDRESS
+ depends on CONSOLE_SERIAL && AMD_SOC_CONSOLE_UART
+ hex
+ default 0xfedc9000 if UART_FOR_CONSOLE = 0
+ default 0xfedca000 if UART_FOR_CONSOLE = 1
+ default 0xfedce000 if UART_FOR_CONSOLE = 2
+ default 0xfedcf000 if UART_FOR_CONSOLE = 3
+ default 0xfedd1000 if UART_FOR_CONSOLE = 4
+
+config SMM_TSEG_SIZE
+ hex
+ default 0x800000 if HAVE_SMI_HANDLER
+ default 0x0
+
+config SMM_RESERVED_SIZE
+ hex
+ default 0x180000
+
+config SMM_MODULE_STACK_SIZE
+ hex
+ default 0x800
+
+config ACPI_BERT
+ bool "Build ACPI BERT Table"
+ default y
+ depends on HAVE_ACPI_TABLES
+ help
+ Report Machine Check errors identified in POST to the OS in an
+ ACPI Boot Error Record Table.
+
+config ACPI_BERT_SIZE
+ hex
+ default 0x4000 if ACPI_BERT
+ default 0x0
+ help
+ Specify the amount of DRAM reserved for gathering the data used to
+ generate the ACPI table.
+
+config DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ
+ int
+ default 150
+
+config DISABLE_SPI_FLASH_ROM_SHARING
+ def_bool n
+ help
+ Instruct the chipset to not honor the EGPIO67_SPI_ROM_REQ pin
+ which indicates a board level ROM transaction request. This
+ removes arbitration with board and assumes the chipset controls
+ the SPI flash bus entirely.
+
+config DISABLE_KEYBOARD_RESET_PIN
+ bool
+ help
+ Instruct the SoC to not use the state of GPIO_129 as keyboard reset
+ signal. When this pin is used as GPIO and the keyboard reset
+ functionality isn't disabled, configuring it as an output and driving
+ it as 0 will cause a reset.
+
+config ACPI_SSDT_PSD_INDEPENDENT
+ bool "Allow core p-state independent transitions"
+ default y
+ help
+ AMD recommends the ACPI _PSD object to be configured to cause
+ cores to transition between p-states independently. A vendor may
+ choose to generate _PSD object to allow cores to transition together.
+
+menu "PSP Configuration Options"
+
+config AMD_FWM_POSITION_INDEX
+ int "Firmware Directory Table location (0 to 5)"
+ range 0 5
+ default 0 if BOARD_ROMSIZE_KB_512
+ default 1 if BOARD_ROMSIZE_KB_1024
+ default 2 if BOARD_ROMSIZE_KB_2048
+ default 3 if BOARD_ROMSIZE_KB_4096
+ default 4 if BOARD_ROMSIZE_KB_8192
+ default 5 if BOARD_ROMSIZE_KB_16384
+ help
+ Typically this is calculated by the ROM size, but there may
+ be situations where you want to put the firmware directory
+ table in a different location.
+ 0: 512 KB - 0xFFFA0000
+ 1: 1 MB - 0xFFF20000
+ 2: 2 MB - 0xFFE20000
+ 3: 4 MB - 0xFFC20000
+ 4: 8 MB - 0xFF820000
+ 5: 16 MB - 0xFF020000
+
+comment "AMD Firmware Directory Table set to location for 512KB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 0
+comment "AMD Firmware Directory Table set to location for 1MB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 1
+comment "AMD Firmware Directory Table set to location for 2MB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 2
+comment "AMD Firmware Directory Table set to location for 4MB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 3
+comment "AMD Firmware Directory Table set to location for 8MB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 4
+comment "AMD Firmware Directory Table set to location for 16MB ROM"
+ depends on AMD_FWM_POSITION_INDEX = 5
+
+config AMDFW_CONFIG_FILE
+ string "AMD PSP Firmware config file"
+ default "src/soc/amd/morgana/fw.cfg"
+ help
+ Specify the path/location of AMD PSP Firmware config file.
+
+config PSP_DISABLE_POSTCODES
+ bool "Disable PSP post codes"
+ help
+ Disables the output of port80 post codes from PSP.
+
+config PSP_POSTCODES_ON_ESPI
+ bool "Use eSPI bus for PSP post codes"
+ default y
+ depends on !PSP_DISABLE_POSTCODES
+ help
+ Select to send PSP port80 post codes on eSPI bus.
+ If not selected, PSP port80 codes will be sent on LPC bus.
+
+config PSP_LOAD_MP2_FW
+ bool
+ default n
+ help
+ Include the MP2 firmwares and configuration into the PSP build.
+
+ If unsure, answer 'n'
+
+config PSP_UNLOCK_SECURE_DEBUG
+ bool "Unlock secure debug"
+ default y
+ help
+ Select this item to enable secure debug options in PSP.
+
+config HAVE_PSP_WHITELIST_FILE
+ bool "Include a debug whitelist file in PSP build"
+ default n
+ help
+ Support secured unlock prior to reset using a whitelisted
+ serial number. This feature requires a signed whitelist image
+ and bootloader from AMD.
+
+ If unsure, answer 'n'
+
+config PSP_WHITELIST_FILE
+ string "Debug whitelist file path"
+ depends on HAVE_PSP_WHITELIST_FILE
+ default "site-local/3rdparty/amd_blobs/morgana/PSP/wtl-mrg.sbin"
+
+config HAVE_SPL_FILE
+ bool "Have a mainboard specific SPL table file"
+ default n
+ help
+ Have a mainboard specific Security Patch Level (SPL) table file. SPL file
+ is required to support PSP FW anti-rollback and needs to be created by AMD.
+ The default SPL file applies to all boards that use the concerned SoC and
+ is dropped under 3rdparty/blobs. The mainboard specific SPL file override
+ can be applied through SPL_TABLE_FILE config.
+
+ If unsure, answer 'n'
+
+config SPL_TABLE_FILE
+ string "SPL table file"
+ depends on HAVE_SPL_FILE
+ default "3rdparty/blobs/mainboard/\$(CONFIG_MAINBOARD_DIR)/TypeId0x55_SplTableBl_MRG.sbin"
+
+config HAVE_SPL_RW_AB_FILE
+ bool "Have a separate mainboard-specific SPL file in RW A/B partitions"
+ default n
+ depends on HAVE_SPL_FILE
+ depends on VBOOT_SLOTS_RW_AB
+ help
+ Have separate mainboard-specific Security Patch Level (SPL) table
+ file for the RW A/B FMAP partitions. See the help text of
+ HAVE_SPL_FILE for a more detailed description.
+
+config SPL_RW_AB_TABLE_FILE
+ string "Separate SPL table file for RW A/B partitions"
+ depends on HAVE_SPL_RW_AB_FILE
+ default "3rdparty/blobs/mainboard/\$(CONFIG_MAINBOARD_DIR)/TypeId0x55_SplTableBl_MRG.sbin"
+
+config PSP_SOFTFUSE_BITS
+ string "PSP Soft Fuse bits to enable"
+ default "34 28 6"
+ help
+ Space separated list of Soft Fuse bits to enable.
+ Bit 0: Enable secure debug (Set by PSP_UNLOCK_SECURE_DEBUG)
+ Bit 7: Disable PSP postcodes on Renoir and newer chips only
+ (Set by PSP_DISABLE_PORT80)
+ Bit 15: PSP debug output destination:
+ 0=SoC MMIO UART, 1=IO port 0x3F8
+ Bit 29: Disable MP2 firmware loading (Set by PSP_LOAD_MP2_FW)
+
+ See #55758 (NDA) for additional bit definitions.
+
+config PSP_VERSTAGE_FILE
+ string "Specify the PSP_verstage file path"
+ depends on VBOOT_STARTS_BEFORE_BOOTBLOCK
+ default "\$(obj)/psp_verstage.bin"
+ help
+ Add psp_verstage file to the build & PSP Directory Table
+
+config PSP_VERSTAGE_SIGNING_TOKEN
+ string "Specify the PSP_verstage Signature Token file path"
+ depends on VBOOT_STARTS_BEFORE_BOOTBLOCK
+ default ""
+ help
+ Add psp_verstage signature token to the build & PSP Directory Table
+
+endmenu
+
+config VBOOT
+ select VBOOT_VBNV_CMOS
+ select VBOOT_VBNV_CMOS_BACKUP_TO_FLASH
+
+config VBOOT_STARTS_BEFORE_BOOTBLOCK
+ def_bool n
+ depends on VBOOT
+ select ARCH_VERSTAGE_ARMV7
+ help
+ Runs verstage on the PSP. Only available on
+ certain ChromeOS branded parts from AMD.
+
+config VBOOT_HASH_BLOCK_SIZE
+ hex
+ default 0x9000
+ depends on VBOOT_STARTS_BEFORE_BOOTBLOCK
+ help
+ Because the bulk of the time in psp_verstage to hash the RO cbfs is
+ spent in the overhead of doing svc calls, increasing the hash block
+ size significantly cuts the verstage hashing time as seen below.
+
+ 4k takes 180ms
+ 16k takes 44ms
+ 32k takes 33.7ms
+ 36k takes 32.5ms
+ There's actually still room for an even bigger stack, but we've
+ reached a point of diminishing returns.
+
+config CMOS_RECOVERY_BYTE
+ hex
+ default 0x51
+ depends on VBOOT_STARTS_BEFORE_BOOTBLOCK
+ help
+ If the workbuf is not passed from the PSP to coreboot, set the
+ recovery flag and reboot. The PSP will read this byte, mark the
+ recovery request in VBNV, and reset the system into recovery mode.
+
+ This is the byte before the default first byte used by VBNV
+ (0x26 + 0x0E - 1)
+
+if VBOOT_SLOTS_RW_AB && VBOOT_STARTS_BEFORE_BOOTBLOCK
+
+config RWA_REGION_ONLY
+ string
+ default "apu/amdfw_a"
+ help
+ Add a space-delimited list of filenames that should only be in the
+ RW-A section.
+
+config RWB_REGION_ONLY
+ string
+ default "apu/amdfw_b"
+ help
+ Add a space-delimited list of filenames that should only be in the
+ RW-B section.
+
+endif # VBOOT_SLOTS_RW_AB && VBOOT_STARTS_BEFORE_BOOTBLOCK
+
+endif # SOC_AMD_REMBRANDT_BASE
diff --git a/src/soc/amd/morgana/Makefile.inc b/src/soc/amd/morgana/Makefile.inc
new file mode 100644
index 0000000000..6c80d237ba
--- /dev/null
+++ b/src/soc/amd/morgana/Makefile.inc
@@ -0,0 +1,330 @@
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TODO: Move as much as possible to common
+# TODO: Update for Morgana
+
+ifeq ($(CONFIG_SOC_AMD_MORGANA),y)
+
+subdirs-$(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK) += psp_verstage
+
+# Beware that all-y also adds the compilation unit to verstage on PSP
+all-y += config.c
+all-y += aoac.c
+
+bootblock-y += bootblock.c
+bootblock-y += early_fch.c
+bootblock-y += espi_util.c
+bootblock-y += gpio.c
+bootblock-y += i2c.c
+bootblock-y += reset.c
+bootblock-y += uart.c
+
+verstage-y += i2c.c
+verstage-y += espi_util.c
+verstage_x86-y += gpio.c
+verstage_x86-y += reset.c
+verstage_x86-y += uart.c
+
+romstage-y += fsp_m_params.c
+romstage-y += gpio.c
+romstage-y += i2c.c
+romstage-y += reset.c
+romstage-y += romstage.c
+romstage-y += uart.c
+
+ramstage-y += acpi.c
+ramstage-y += agesa_acpi.c
+ramstage-y += chip.c
+ramstage-y += cpu.c
+ramstage-y += data_fabric.c
+ramstage-y += fch.c
+ramstage-y += fsp_s_params.c
+ramstage-y += gpio.c
+ramstage-y += i2c.c
+ramstage-y += mca.c
+ramstage-y += preload.c
+ramstage-y += reset.c
+ramstage-y += root_complex.c
+ramstage-y += uart.c
+ramstage-y += xhci.c
+
+smm-y += gpio.c
+smm-y += smihandler.c
+smm-y += smu.c
+smm-$(CONFIG_DEBUG_SMI) += uart.c
+
+CPPFLAGS_common += -I$(src)/soc/amd/morgana/include
+CPPFLAGS_common += -I$(src)/soc/amd/morgana/acpi
+CPPFLAGS_common += -I$(src)/vendorcode/amd/fsp/morgana
+CPPFLAGS_common += -I$(src)/vendorcode/amd/fsp/common
+
+MAINBOARD_BLOBS_DIR:=$(top)/3rdparty/blobs/mainboard/$(MAINBOARDDIR)
+
+# ROMSIG Normally At ROMBASE + 0x20000
+# Overridden by CONFIG_AMD_FWM_POSITION_INDEX
+# +-----------+---------------+----------------+------------+
+# |0x55AA55AA | | | |
+# +-----------+---------------+----------------+------------+
+# | | PSPDIR ADDR | BIOSDIR ADDR |
+# +-----------+---------------+----------------+
+
+$(if $(CONFIG_AMD_FWM_POSITION_INDEX), ,\
+ $(error Invalid AMD firmware position index. Check if the board sets a valid ROM size))
+
+MORGANA_FWM_POSITION=$(call int-add, \
+ $(call int-subtract, 0xffffffff \
+ $(call int-shift-left, \
+ 0x80000 $(CONFIG_AMD_FWM_POSITION_INDEX))) 0x20000 1)
+
+# 0x40 accounts for the cbfs_file struct + filename + metadata structs, aligned to 64 bytes
+# Building the cbfs image will fail if the offset isn't large enough
+AMD_FW_AB_POSITION := 0x40
+
+MORGANA_FW_A_POSITION=$(call int-add, \
+ $(shell awk '$$2 == "FMAP_SECTION_FW_MAIN_A_START" {print $$3}' $(obj)/fmap_config.h) \
+ $(AMD_FW_AB_POSITION))
+
+MORGANA_FW_B_POSITION=$(call int-add, \
+ $(shell awk '$$2 == "FMAP_SECTION_FW_MAIN_B_START" {print $$3}' $(obj)/fmap_config.h) \
+ $(AMD_FW_AB_POSITION))
+#
+# PSP Directory Table items
+#
+# Certain ordering requirements apply, however these are ensured by amdfwtool.
+# For more information see "AMD Platform Security Processor BIOS Architecture
+# Design Guide for AMD Family 17h Processors" (PID #55758, NDA only).
+#
+
+ifeq ($(CONFIG_PSP_DISABLE_POSTCODES),y)
+PSP_SOFTFUSE_BITS += 7
+endif
+
+ifeq ($(CONFIG_PSP_UNLOCK_SECURE_DEBUG),y)
+# Enable secure debug unlock
+PSP_SOFTFUSE_BITS += 0
+OPT_TOKEN_UNLOCK="--token-unlock"
+endif
+
+ifeq ($(CONFIG_PSP_LOAD_MP2_FW),y)
+OPT_PSP_LOAD_MP2_FW="--load-mp2-fw"
+else
+# Disable MP2 firmware loading
+PSP_SOFTFUSE_BITS += 29
+endif
+
+# Use additional Soft Fuse bits specified in Kconfig
+PSP_SOFTFUSE_BITS += $(call strip_quotes, $(CONFIG_PSP_SOFTFUSE_BITS))
+
+# type = 0x3a
+ifeq ($(CONFIG_HAVE_PSP_WHITELIST_FILE),y)
+PSP_WHITELIST_FILE=$(CONFIG_PSP_WHITELIST_FILE)
+endif
+
+# type = 0x55
+ifeq ($(CONFIG_HAVE_SPL_FILE),y)
+SPL_TABLE_FILE=$(CONFIG_SPL_TABLE_FILE)
+ifeq ($(CONFIG_HAVE_SPL_RW_AB_FILE),y)
+SPL_RW_AB_TABLE_FILE=$(CONFIG_SPL_RW_AB_TABLE_FILE)
+else
+SPL_RW_AB_TABLE_FILE=$(CONFIG_SPL_TABLE_FILE)
+endif
+endif
+
+#
+# BIOS Directory Table items - proper ordering is managed by amdfwtool
+#
+
+# type = 0x60
+PSP_APCB_FILES=$(APCB_SOURCES) $(APCB_SOURCES_RECOVERY)
+
+# type = 0x61
+PSP_APOB_BASE=$(CONFIG_PSP_APOB_DRAM_ADDRESS)
+
+# type = 0x62
+PSP_BIOSBIN_FILE=$(obj)/amd_biospsp.img
+PSP_ELF_FILE=$(objcbfs)/bootblock.elf
+PSP_BIOSBIN_SIZE=$(shell $(READELF_bootblock) -l $(PSP_ELF_FILE) | grep LOAD | awk '{print $$5}')
+PSP_BIOSBIN_DEST=$(shell $(READELF_bootblock) -l $(PSP_ELF_FILE) | grep LOAD | awk '{print $$3}')
+
+# type = 0x63 - construct APOB NV base/size from flash map
+# The flashmap section used for this is expected to be named RW_MRC_CACHE
+APOB_NV_SIZE=$(shell awk '$$2 == "FMAP_SECTION_RW_MRC_CACHE_SIZE" {print $$3}' $(obj)/fmap_config.h)
+APOB_NV_BASE=$(shell awk '$$2 == "FMAP_SECTION_RW_MRC_CACHE_START" {print $$3}' $(obj)/fmap_config.h)
+
+ifeq ($(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK),y)
+# type = 0x6B - PSP Shared memory location
+ifneq ($(CONFIG_PSP_SHAREDMEM_SIZE),0x0)
+PSP_SHAREDMEM_SIZE=$(CONFIG_PSP_SHAREDMEM_SIZE)
+PSP_SHAREDMEM_BASE=$(shell awk '$$3 == "_psp_sharedmem_dram" {printf "0x" $$1}' $(objcbfs)/bootblock.map)
+endif
+
+# type = 0x52 - PSP Bootloader Userspace Application (verstage)
+PSP_VERSTAGE_FILE=$(call strip_quotes,$(CONFIG_PSP_VERSTAGE_FILE))
+PSP_VERSTAGE_SIG_FILE=$(call strip_quotes,$(CONFIG_PSP_VERSTAGE_SIGNING_TOKEN))
+endif # CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK
+
+ifeq ($(CONFIG_SEPARATE_SIGNED_PSPFW),y)
+SIGNED_AMDFW_A_POSITION=$(call int-subtract, \
+ $(shell awk '$$2 == "FMAP_SECTION_SIGNED_AMDFW_A_START" {print $$3}' $(obj)/fmap_config.h) \
+ $(shell awk '$$2 == "FMAP_SECTION_FLASH_START" {print $$3}' $(obj)/fmap_config.h))
+SIGNED_AMDFW_B_POSITION=$(call int-subtract, \
+ $(shell awk '$$2 == "FMAP_SECTION_SIGNED_AMDFW_B_START" {print $$3}' $(obj)/fmap_config.h) \
+ $(shell awk '$$2 == "FMAP_SECTION_FLASH_START" {print $$3}' $(obj)/fmap_config.h))
+SIGNED_AMDFW_A_FILE=$(obj)/amdfw_a.rom.signed
+SIGNED_AMDFW_B_FILE=$(obj)/amdfw_b.rom.signed
+endif # CONFIG_SEPARATE_SIGNED_PSPFW
+
+# Helper function to return a value with given bit set
+# Soft Fuse type = 0xb - See #55758 (NDA) for bit definitions.
+set-bit=$(call int-shift-left, 1 $(call _toint,$1))
+PSP_SOFTFUSE=$(shell A=$(call int-add, \
+ $(foreach bit,$(PSP_SOFTFUSE_BITS),$(call set-bit,$(bit)))); printf "0x%x" $$A)
+
+#
+# Build the arguments to amdfwtool (order is unimportant). Missing file names
+# result in empty OPT_ variables, i.e. the argument is not passed to amdfwtool.
+#
+
+add_opt_prefix=$(if $(call strip_quotes, $(1)), $(2) $(call strip_quotes, $(1)), )
+
+OPT_VERSTAGE_FILE=$(call add_opt_prefix, $(PSP_VERSTAGE_FILE), --verstage)
+OPT_VERSTAGE_SIG_FILE=$(call add_opt_prefix, $(PSP_VERSTAGE_SIG_FILE), --verstage_sig)
+
+OPT_PSP_APCB_FILES= $(if $(APCB_SOURCES), --instance 0 --apcb $(APCB_SOURCES)) \
+ $(if $(APCB_SOURCES_RECOVERY), --instance 10 --apcb $(APCB_SOURCES_RECOVERY)) \
+ $(if $(APCB_SOURCES_68), --instance 18 --apcb $(APCB_SOURCES_68))
+
+OPT_APOB_ADDR=$(call add_opt_prefix, $(PSP_APOB_BASE), --apob-base)
+OPT_PSP_BIOSBIN_FILE=$(call add_opt_prefix, $(PSP_BIOSBIN_FILE), --bios-bin)
+OPT_PSP_BIOSBIN_DEST=$(call add_opt_prefix, $(PSP_BIOSBIN_DEST), --bios-bin-dest)
+OPT_PSP_BIOSBIN_SIZE=$(call add_opt_prefix, $(PSP_BIOSBIN_SIZE), --bios-uncomp-size)
+
+OPT_PSP_SHAREDMEM_BASE=$(call add_opt_prefix, $(PSP_SHAREDMEM_BASE), --sharedmem)
+OPT_PSP_SHAREDMEM_SIZE=$(call add_opt_prefix, $(PSP_SHAREDMEM_SIZE), --sharedmem-size)
+OPT_APOB_NV_SIZE=$(call add_opt_prefix, $(APOB_NV_SIZE), --apob-nv-size)
+OPT_APOB_NV_BASE=$(call add_opt_prefix, $(APOB_NV_BASE),--apob-nv-base)
+OPT_EFS_SPI_READ_MODE=$(call add_opt_prefix, $(CONFIG_EFS_SPI_READ_MODE), --spi-read-mode)
+OPT_EFS_SPI_SPEED=$(call add_opt_prefix, $(CONFIG_EFS_SPI_SPEED), --spi-speed)
+OPT_EFS_SPI_MICRON_FLAG=$(call add_opt_prefix, $(CONFIG_EFS_SPI_MICRON_FLAG), --spi-micron-flag)
+
+OPT_SIGNED_AMDFW_A_POSITION=$(call add_opt_prefix, $(SIGNED_AMDFW_A_POSITION), --signed-addr)
+OPT_SIGNED_AMDFW_A_FILE=$(call add_opt_prefix, $(SIGNED_AMDFW_A_FILE), --signed-output)
+OPT_SIGNED_AMDFW_B_POSITION=$(call add_opt_prefix, $(SIGNED_AMDFW_B_POSITION), --signed-addr)
+OPT_SIGNED_AMDFW_B_FILE=$(call add_opt_prefix, $(SIGNED_AMDFW_B_FILE), --signed-output)
+
+OPT_PSP_SOFTFUSE=$(call add_opt_prefix, $(PSP_SOFTFUSE), --soft-fuse)
+
+OPT_WHITELIST_FILE=$(call add_opt_prefix, $(PSP_WHITELIST_FILE), --whitelist)
+OPT_SPL_TABLE_FILE=$(call add_opt_prefix, $(SPL_TABLE_FILE), --spl-table)
+OPT_SPL_RW_AB_TABLE_FILE=$(call add_opt_prefix, $(SPL_RW_AB_TABLE_FILE), --spl-table)
+
+# If vboot uses 2 RW slots, then 2 copies of PSP binaries are redundant
+OPT_RECOVERY_AB_SINGLE_COPY=$(if $(CONFIG_VBOOT_SLOTS_RW_AB), --recovery-ab-single-copy)
+
+AMDFW_COMMON_ARGS=$(OPT_PSP_APCB_FILES) \
+ $(OPT_APOB_ADDR) \
+ $(OPT_PSP_BIOSBIN_FILE) \
+ $(OPT_PSP_BIOSBIN_DEST) \
+ $(OPT_PSP_BIOSBIN_SIZE) \
+ $(OPT_PSP_SOFTFUSE) \
+ $(OPT_PSP_LOAD_MP2_FW) \
+ --use-pspsecureos \
+ --load-s0i3 \
+ --combo-capable \
+ $(OPT_TOKEN_UNLOCK) \
+ $(OPT_WHITELIST_FILE) \
+ $(OPT_PSP_SHAREDMEM_BASE) \
+ $(OPT_PSP_SHAREDMEM_SIZE) \
+ $(OPT_EFS_SPI_READ_MODE) \
+ $(OPT_EFS_SPI_SPEED) \
+ $(OPT_EFS_SPI_MICRON_FLAG) \
+ --config $(CONFIG_AMDFW_CONFIG_FILE) \
+ --soc-name "Morgana" \
+ --flashsize $(CONFIG_ROM_SIZE) \
+ $(OPT_RECOVERY_AB_SINGLE_COPY)
+
+$(obj)/amdfw.rom: $(call strip_quotes, $(PSP_BIOSBIN_FILE)) \
+ $(PSP_VERSTAGE_FILE) \
+ $(PSP_VERSTAGE_SIG_FILE) \
+ $$(PSP_APCB_FILES) \
+ $(DEP_FILES) \
+ $(AMDFWTOOL) \
+ $(obj)/fmap_config.h \
+ $(objcbfs)/bootblock.elf # this target also creates the .map file
+ $(if $(PSP_APCB_FILES), ,$(error APCB_SOURCES is not set))
+ rm -f $@
+ @printf " AMDFWTOOL $(subst $(obj)/,,$(@))\n"
+ $(AMDFWTOOL) \
+ $(AMDFW_COMMON_ARGS) \
+ $(OPT_APOB_NV_SIZE) \
+ $(OPT_APOB_NV_BASE) \
+ $(OPT_VERSTAGE_FILE) \
+ $(OPT_VERSTAGE_SIG_FILE) \
+ $(OPT_SPL_TABLE_FILE) \
+ --location $(shell printf "%#x" $(MORGANA_FWM_POSITION)) \
+ --output $@
+
+$(PSP_BIOSBIN_FILE): $(PSP_ELF_FILE) $(AMDCOMPRESS)
+ rm -f $@
+ @printf " AMDCOMPRS $(subst $(obj)/,,$(@))\n"
+ $(AMDCOMPRESS) --infile $(PSP_ELF_FILE) --outfile $@ --compress \
+ --maxsize $(PSP_BIOSBIN_SIZE)
+
+$(obj)/amdfw_a.rom: $(obj)/amdfw.rom
+ rm -f $@
+ @printf " AMDFWTOOL $(subst $(obj)/,,$(@))\n"
+ $(AMDFWTOOL) \
+ $(AMDFW_COMMON_ARGS) \
+ $(OPT_APOB_NV_SIZE) \
+ $(OPT_APOB_NV_BASE) \
+ $(OPT_SPL_RW_AB_TABLE_FILE) \
+ $(OPT_SIGNED_AMDFW_A_POSITION) \
+ $(OPT_SIGNED_AMDFW_A_FILE) \
+ --location $(shell printf "%#x" $(MORGANA_FW_A_POSITION)) \
+ --anywhere \
+ --output $@
+
+$(obj)/amdfw_b.rom: $(obj)/amdfw.rom
+ rm -f $@
+ @printf " AMDFWTOOL $(subst $(obj)/,,$(@))\n"
+ $(AMDFWTOOL) \
+ $(AMDFW_COMMON_ARGS) \
+ $(OPT_APOB_NV_SIZE) \
+ $(OPT_APOB_NV_BASE) \
+ $(OPT_SPL_RW_AB_TABLE_FILE) \
+ $(OPT_SIGNED_AMDFW_B_POSITION) \
+ $(OPT_SIGNED_AMDFW_B_FILE) \
+ --location $(shell printf "%#x" $(MORGANA_FW_B_POSITION)) \
+ --anywhere \
+ --output $@
+
+
+cbfs-files-y += apu/amdfw
+apu/amdfw-file := $(obj)/amdfw.rom
+apu/amdfw-position := $(MORGANA_FWM_POSITION)
+apu/amdfw-type := raw
+
+ifeq ($(CONFIG_VBOOT_SLOTS_RW_AB)$(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK),yy)
+cbfs-files-y += apu/amdfw_a
+apu/amdfw_a-file := $(obj)/amdfw_a.rom
+apu/amdfw_a-position := $(AMD_FW_AB_POSITION)
+apu/amdfw_a-type := raw
+
+cbfs-files-y += apu/amdfw_b
+apu/amdfw_b-file := $(obj)/amdfw_b.rom
+apu/amdfw_b-position := $(AMD_FW_AB_POSITION)
+apu/amdfw_b-type := raw
+
+ifeq ($(CONFIG_SEPARATE_SIGNED_PSPFW),y)
+build_complete:: $(obj)/amdfw_a.rom $(obj)/amdfw_b.rom
+ @printf " Adding Signed ROM and HASH\n"
+ $(CBFSTOOL) $(obj)/coreboot.rom write -u -r SIGNED_AMDFW_A -i 0 -f $(obj)/amdfw_a.rom.signed
+ $(CBFSTOOL) $(obj)/coreboot.rom write -u -r SIGNED_AMDFW_B -i 0 -f $(obj)/amdfw_b.rom.signed
+ $(CBFSTOOL) $(obj)/coreboot.rom add -r FW_MAIN_A -f $(obj)/amdfw_a.rom.signed.hash \
+ -n apu/amdfw_a_hash -t raw
+ $(CBFSTOOL) $(obj)/coreboot.rom add -r FW_MAIN_B -f $(obj)/amdfw_b.rom.signed.hash \
+ -n apu/amdfw_b_hash -t raw
+endif # CONFIG_SEPARATE_SIGNED_PSPFW
+endif
+
+endif # ($(CONFIG_SOC_AMD_MORGANA),y)
diff --git a/src/soc/amd/morgana/acpi.c b/src/soc/amd/morgana/acpi.c
new file mode 100644
index 0000000000..f3825f0419
--- /dev/null
+++ b/src/soc/amd/morgana/acpi.c
@@ -0,0 +1,370 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+/* TODO: See what can be made common */
+
+/* ACPI - create the Fixed ACPI Description Tables (FADT) */
+
+#include <acpi/acpi.h>
+#include <acpi/acpigen.h>
+#include <amdblocks/acpi.h>
+#include <amdblocks/cppc.h>
+#include <amdblocks/cpu.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/ioapic.h>
+#include <arch/ioapic.h>
+#include <arch/smp/mpspec.h>
+#include <console/console.h>
+#include <cpu/amd/cpuid.h>
+#include <cpu/amd/msr.h>
+#include <cpu/x86/smm.h>
+#include <soc/acpi.h>
+#include <soc/iomap.h>
+#include <soc/msr.h>
+#include <types.h>
+#include "chip.h"
+
+unsigned long acpi_fill_madt(unsigned long current)
+{
+ /* create all subtables for processors */
+ current = acpi_create_madt_lapics(current);
+
+ current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
+ FCH_IOAPIC_ID, IO_APIC_ADDR, 0);
+
+ current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *)current,
+ GNB_IOAPIC_ID, GNB_IO_APIC_ADDR, IO_APIC_INTERRUPTS);
+
+ /* PIT is connected to legacy IRQ 0, but IOAPIC GSI 2 */
+ current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)current,
+ MP_BUS_ISA, 0, 2,
+ MP_IRQ_TRIGGER_DEFAULT | MP_IRQ_POLARITY_DEFAULT);
+ /* SCI IRQ type override */
+ current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)current,
+ MP_BUS_ISA, ACPI_SCI_IRQ, ACPI_SCI_IRQ,
+ MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_LOW);
+ current = acpi_fill_madt_irqoverride(current);
+
+ /* create all subtables for processors */
+ current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current,
+ ACPI_MADT_LAPIC_NMI_ALL_PROCESSORS,
+ MP_IRQ_TRIGGER_EDGE | MP_IRQ_POLARITY_HIGH,
+ 1 /* 1: LINT1 connect to NMI */);
+
+ return current;
+}
+
+/*
+ * Reference section 5.2.9 Fixed ACPI Description Table (FADT)
+ * in the ACPI 3.0b specification.
+ */
+void acpi_fill_fadt(acpi_fadt_t *fadt)
+{
+ const struct soc_amd_morgana_config *cfg = config_of_soc();
+
+ printk(BIOS_DEBUG, "pm_base: 0x%04x\n", ACPI_IO_BASE);
+
+ fadt->sci_int = ACPI_SCI_IRQ;
+
+ if (permanent_smi_handler()) {
+ fadt->smi_cmd = APM_CNT;
+ fadt->acpi_enable = APM_CNT_ACPI_ENABLE;
+ fadt->acpi_disable = APM_CNT_ACPI_DISABLE;
+ }
+
+ fadt->pstate_cnt = 0;
+
+ fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK;
+ fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK;
+ fadt->pm_tmr_blk = ACPI_PM_TMR_BLK;
+ fadt->gpe0_blk = ACPI_GPE0_BLK;
+
+ fadt->pm1_evt_len = 4; /* 32 bits */
+ fadt->pm1_cnt_len = 2; /* 16 bits */
+ fadt->pm_tmr_len = 4; /* 32 bits */
+ fadt->gpe0_blk_len = 8; /* 64 bits */
+
+ fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
+ fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
+ fadt->duty_offset = 0; /* Not supported */
+ fadt->duty_width = 0; /* Not supported */
+ fadt->day_alrm = RTC_DATE_ALARM;
+ fadt->mon_alrm = 0;
+ fadt->century = RTC_ALT_CENTURY;
+ fadt->iapc_boot_arch = cfg->common_config.fadt_boot_arch; /* legacy free default */
+ fadt->flags |= ACPI_FADT_WBINVD | /* See table 5-34 ACPI 6.3 spec */
+ ACPI_FADT_C1_SUPPORTED |
+ ACPI_FADT_S4_RTC_WAKE |
+ ACPI_FADT_32BIT_TIMER |
+ ACPI_FADT_PCI_EXPRESS_WAKE |
+ ACPI_FADT_PLATFORM_CLOCK |
+ ACPI_FADT_S4_RTC_VALID |
+ ACPI_FADT_REMOTE_POWER_ON;
+ if (cfg->s0ix_enable)
+ fadt->flags |= ACPI_FADT_LOW_PWR_IDLE_S0;
+
+ fadt->flags |= cfg->common_config.fadt_flags; /* additional board-specific flags */
+
+ fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1a_evt_blk.bit_width = 32;
+ fadt->x_pm1a_evt_blk.bit_offset = 0;
+ fadt->x_pm1a_evt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
+ fadt->x_pm1a_evt_blk.addrl = ACPI_PM_EVT_BLK;
+ fadt->x_pm1a_evt_blk.addrh = 0x0;
+
+ fadt->x_pm1a_cnt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm1a_cnt_blk.bit_width = 16;
+ fadt->x_pm1a_cnt_blk.bit_offset = 0;
+ fadt->x_pm1a_cnt_blk.access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
+ fadt->x_pm1a_cnt_blk.addrl = ACPI_PM1_CNT_BLK;
+ fadt->x_pm1a_cnt_blk.addrh = 0x0;
+
+ fadt->x_pm_tmr_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_pm_tmr_blk.bit_width = 32;
+ fadt->x_pm_tmr_blk.bit_offset = 0;
+ fadt->x_pm_tmr_blk.access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+ fadt->x_pm_tmr_blk.addrl = ACPI_PM_TMR_BLK;
+ fadt->x_pm_tmr_blk.addrh = 0x0;
+
+ fadt->x_gpe0_blk.space_id = ACPI_ADDRESS_SPACE_IO;
+ fadt->x_gpe0_blk.bit_width = 64;
+ fadt->x_gpe0_blk.bit_offset = 0;
+ fadt->x_gpe0_blk.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
+ fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK;
+ fadt->x_gpe0_blk.addrh = 0x0;
+}
+
+static uint32_t get_pstate_core_freq(msr_t pstate_def)
+{
+ uint32_t core_freq, core_freq_mul, core_freq_div;
+ bool valid_freq_divisor;
+
+ /* Core frequency multiplier */
+ core_freq_mul = pstate_def.lo & PSTATE_DEF_LO_FREQ_MUL_MASK;
+
+ /* Core frequency divisor ID */
+ core_freq_div =
+ (pstate_def.lo & PSTATE_DEF_LO_FREQ_DIV_MASK) >> PSTATE_DEF_LO_FREQ_DIV_SHIFT;
+
+ if (core_freq_div == 0) {
+ return 0;
+ } else if ((core_freq_div >= PSTATE_DEF_LO_FREQ_DIV_MIN)
+ && (core_freq_div <= PSTATE_DEF_LO_EIGHTH_STEP_MAX)) {
+ /* Allow 1/8 integer steps for this range */
+ valid_freq_divisor = 1;
+ } else if ((core_freq_div > PSTATE_DEF_LO_EIGHTH_STEP_MAX)
+ && (core_freq_div <= PSTATE_DEF_LO_FREQ_DIV_MAX) && !(core_freq_div & 0x1)) {
+ /* Only allow 1/4 integer steps for this range */
+ valid_freq_divisor = 1;
+ } else {
+ valid_freq_divisor = 0;
+ }
+
+ if (valid_freq_divisor) {
+ /* 25 * core_freq_mul / (core_freq_div / 8) */
+ core_freq =
+ ((PSTATE_DEF_LO_CORE_FREQ_BASE * core_freq_mul * 8) / (core_freq_div));
+ } else {
+ printk(BIOS_WARNING, "Undefined core_freq_div %x used. Force to 1.\n",
+ core_freq_div);
+ core_freq = (PSTATE_DEF_LO_CORE_FREQ_BASE * core_freq_mul);
+ }
+ return core_freq;
+}
+
+static uint32_t get_pstate_core_power(msr_t pstate_def)
+{
+ uint32_t voltage_in_uvolts, core_vid, current_value_amps, current_divisor, power_in_mw;
+
+ /* Core voltage ID */
+ core_vid =
+ (pstate_def.lo & PSTATE_DEF_LO_CORE_VID_MASK) >> PSTATE_DEF_LO_CORE_VID_SHIFT;
+
+ /* Current value in amps */
+ current_value_amps =
+ (pstate_def.lo & PSTATE_DEF_LO_CUR_VAL_MASK) >> PSTATE_DEF_LO_CUR_VAL_SHIFT;
+
+ /* Current divisor */
+ current_divisor =
+ (pstate_def.lo & PSTATE_DEF_LO_CUR_DIV_MASK) >> PSTATE_DEF_LO_CUR_DIV_SHIFT;
+
+ /* Voltage */
+ if (core_vid == 0x00) {
+ /* Voltage off for VID code 0x00 */
+ voltage_in_uvolts = 0;
+ } else {
+ voltage_in_uvolts =
+ SERIAL_VID_BASE_MICROVOLTS + (SERIAL_VID_DECODE_MICROVOLTS * core_vid);
+ }
+
+ /* Power in mW */
+ power_in_mw = (voltage_in_uvolts) / 10 * current_value_amps;
+
+ switch (current_divisor) {
+ case 0:
+ power_in_mw = power_in_mw / 100L;
+ break;
+ case 1:
+ power_in_mw = power_in_mw / 1000L;
+ break;
+ case 2:
+ power_in_mw = power_in_mw / 10000L;
+ break;
+ case 3:
+ /* current_divisor is set to an undefined value.*/
+ printk(BIOS_WARNING, "Undefined current_divisor set for enabled P-state .\n");
+ power_in_mw = 0;
+ break;
+ }
+
+ return power_in_mw;
+}
+
+/*
+ * Populate structure describing enabled p-states and return count of enabled p-states.
+ */
+static size_t get_pstate_info(struct acpi_sw_pstate *pstate_values,
+ struct acpi_xpss_sw_pstate *pstate_xpss_values)
+{
+ msr_t pstate_def;
+ size_t pstate_count, pstate;
+ uint32_t pstate_enable, max_pstate;
+
+ pstate_count = 0;
+ max_pstate = (rdmsr(PS_LIM_REG).lo & PS_LIM_MAX_VAL_MASK) >> PS_MAX_VAL_SHFT;
+
+ for (pstate = 0; pstate <= max_pstate; pstate++) {
+ pstate_def = rdmsr(PSTATE_0_MSR + pstate);
+
+ pstate_enable = (pstate_def.hi & PSTATE_DEF_HI_ENABLE_MASK)
+ >> PSTATE_DEF_HI_ENABLE_SHIFT;
+ if (!pstate_enable)
+ continue;
+
+ pstate_values[pstate_count].core_freq = get_pstate_core_freq(pstate_def);
+ pstate_values[pstate_count].power = get_pstate_core_power(pstate_def);
+ pstate_values[pstate_count].transition_latency = 0;
+ pstate_values[pstate_count].bus_master_latency = 0;
+ pstate_values[pstate_count].control_value = pstate;
+ pstate_values[pstate_count].status_value = pstate;
+
+ pstate_xpss_values[pstate_count].core_freq =
+ (uint64_t)pstate_values[pstate_count].core_freq;
+ pstate_xpss_values[pstate_count].power =
+ (uint64_t)pstate_values[pstate_count].power;
+ pstate_xpss_values[pstate_count].transition_latency = 0;
+ pstate_xpss_values[pstate_count].bus_master_latency = 0;
+ pstate_xpss_values[pstate_count].control_value = (uint64_t)pstate;
+ pstate_xpss_values[pstate_count].status_value = (uint64_t)pstate;
+ pstate_count++;
+ }
+
+ return pstate_count;
+}
+
+void generate_cpu_entries(const struct device *device)
+{
+ int logical_cores;
+ size_t pstate_count, cpu, proc_blk_len;
+ struct acpi_sw_pstate pstate_values[MAX_PSTATES] = { {0} };
+ struct acpi_xpss_sw_pstate pstate_xpss_values[MAX_PSTATES] = { {0} };
+ uint32_t threads_per_core, proc_blk_addr;
+ uint32_t cstate_base_address =
+ rdmsr(MSR_CSTATE_ADDRESS).lo & MSR_CSTATE_ADDRESS_MASK;
+
+ const acpi_addr_t perf_ctrl = {
+ .space_id = ACPI_ADDRESS_SPACE_FIXED,
+ .bit_width = 64,
+ .addrl = PS_CTL_REG,
+ };
+ const acpi_addr_t perf_sts = {
+ .space_id = ACPI_ADDRESS_SPACE_FIXED,
+ .bit_width = 64,
+ .addrl = PS_STS_REG,
+ };
+
+ const acpi_cstate_t cstate_info[] = {
+ [0] = {
+ .ctype = 1,
+ .latency = 1,
+ .power = 0,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_FIXED,
+ .bit_width = 2,
+ .bit_offset = 2,
+ .addrl = 0,
+ .addrh = 0,
+ },
+ },
+ [1] = {
+ .ctype = 2,
+ .latency = 0x12,
+ .power = 0,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_IO,
+ .bit_width = 8,
+ .bit_offset = 0,
+ .addrl = cstate_base_address + 1,
+ .addrh = 0,
+ .access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS,
+ },
+ },
+ [2] = {
+ .ctype = 3,
+ .latency = 350,
+ .power = 0,
+ .resource = {
+ .space_id = ACPI_ADDRESS_SPACE_IO,
+ .bit_width = 8,
+ .bit_offset = 0,
+ .addrl = cstate_base_address + 2,
+ .addrh = 0,
+ .access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS,
+ },
+ },
+ };
+
+ threads_per_core = get_threads_per_core();
+ pstate_count = get_pstate_info(pstate_values, pstate_xpss_values);
+ logical_cores = get_cpu_count();
+
+ for (cpu = 0; cpu < logical_cores; cpu++) {
+
+ if (cpu == 0) {
+ /* BSP values for \_SB.Pxxx */
+ proc_blk_len = 6;
+ proc_blk_addr = ACPI_GPE0_BLK;
+ } else {
+ /* AP values for \_SB.Pxxx */
+ proc_blk_addr = 0;
+ proc_blk_len = 0;
+ }
+
+ acpigen_write_processor(cpu, proc_blk_addr, proc_blk_len);
+
+ acpigen_write_pct_package(&perf_ctrl, &perf_sts);
+
+ acpigen_write_pss_object(pstate_values, pstate_count);
+
+ acpigen_write_xpss_object(pstate_xpss_values, pstate_count);
+
+ if (CONFIG(ACPI_SSDT_PSD_INDEPENDENT))
+ acpigen_write_PSD_package(cpu / threads_per_core, threads_per_core,
+ HW_ALL);
+ else
+ acpigen_write_PSD_package(0, logical_cores, SW_ALL);
+
+ acpigen_write_PPC(0);
+
+ acpigen_write_CST_package(cstate_info, ARRAY_SIZE(cstate_info));
+
+ acpigen_write_CSD_package(cpu / threads_per_core, threads_per_core,
+ CSD_HW_ALL, 0);
+
+ generate_cppc_entries(cpu);
+
+ acpigen_pop_len();
+ }
+
+ acpigen_write_processor_package("PPKG", 0, logical_cores);
+}
diff --git a/src/soc/amd/morgana/acpi/globalnvs.asl b/src/soc/amd/morgana/acpi/globalnvs.asl
new file mode 100644
index 0000000000..55fbabbb1c
--- /dev/null
+++ b/src/soc/amd/morgana/acpi/globalnvs.asl
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Check if this is still correct */
+
+/*
+ * NOTE: The layout of the GNVS structure below must match the layout in
+ * soc/amd/morgana/include/soc/nvs.h !!!
+ */
+
+Field (GNVS, ByteAcc, NoLock, Preserve)
+{
+ /* Miscellaneous */
+ , 8, // 0x00 - Processor Count
+ LIDS, 8, // 0x01 - LID State
+ , 8, // 0x02 - AC Power State
+ CBMC, 32, // 0x03 - 0x06 - coreboot Memory Console
+ PM1I, 64, // 0x07 - 0x0e - System Wake Source - PM1 Index
+ GPEI, 64, // 0x0f - 0x16 - GPE Wake Source
+ TMPS, 8, // 0x17 - Temperature Sensor ID
+ TCRT, 8, // 0x18 - Critical Threshold
+ TPSV, 8, // 0x19 - Passive Threshold
+}
diff --git a/src/soc/amd/morgana/acpi/mmio.asl b/src/soc/amd/morgana/acpi/mmio.asl
new file mode 100644
index 0000000000..51a7cbd41c
--- /dev/null
+++ b/src/soc/amd/morgana/acpi/mmio.asl
@@ -0,0 +1,390 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <soc/amd/common/acpi/aoac.asl>
+#include <soc/aoac_defs.h>
+#include <soc/gpio.h>
+#include <soc/iomap.h>
+#include <amdblocks/acpimmio_map.h>
+
+Device (AAHB)
+{
+ Name (_HID, "AAHB0000")
+ Name (_UID, 0x0)
+ Name (_CRS, ResourceTemplate()
+ {
+ Memory32Fixed (ReadWrite, ALINK_AHB_ADDRESS, 0x2000)
+ })
+
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+}
+
+Device (GPIO)
+{
+ Name (_HID, GPIO_DEVICE_NAME)
+ Name (_CID, GPIO_DEVICE_NAME)
+ Name (_UID, 0)
+ Name (_DDN, GPIO_DEVICE_DESC)
+
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Level,
+ ActiveLow,
+ Shared, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, ACPIMMIO_GPIO0_BASE, 0x400)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IGPI
+ } Else {
+ IRQN = PGPI
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, ACPIMMIO_GPIO0_BASE, 0x400)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+}
+
+Device (FUR0)
+{
+ Name (_HID, "AMDI0020")
+ Name (_UID, 0x0)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_UART0_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IUA0
+ } Else {
+ IRQN = PUA0
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_UART0_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_UART0, 0)
+}
+
+Device (FUR1) {
+ Name (_HID, "AMDI0020")
+ Name (_UID, 0x1)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_UART1_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IUA1
+ } Else {
+ IRQN = PUA1
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_UART1_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_UART1, 0)
+}
+
+Device (FUR2) {
+ Name (_HID, "AMDI0020")
+ Name (_UID, 0x2)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_UART2_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IUA2
+ } Else {
+ IRQN = PUA2
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_UART2_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_UART2, 0)
+}
+
+Device (FUR3) {
+ Name (_HID, "AMDI0020")
+ Name (_UID, 0x3)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_UART3_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IUA3
+ } Else {
+ IRQN = PUA3
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_UART3_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_UART3, 0)
+}
+
+Device (FUR4) {
+ Name (_HID, "AMDI0020")
+ Name (_UID, 0x4)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_UART4_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = IUA4
+ } Else {
+ IRQN = PUA4
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_UART4_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_UART4, 0)
+}
+
+Device (I2C0) {
+ Name (_HID, "AMDI0010")
+ Name (_UID, 0x0)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_I2C0_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = II20
+ } Else {
+ IRQN = PI20
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_I2C0_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_I2C0, 0)
+}
+
+Device (I2C1) {
+ Name (_HID, "AMDI0010")
+ Name (_UID, 0x1)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_I2C1_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = II21
+ } Else {
+ IRQN = PI21
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_I2C1_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_I2C1, 0)
+}
+
+Device (I2C2) {
+ Name (_HID, "AMDI0010")
+ Name (_UID, 0x2)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_I2C2_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = II22
+ } Else {
+ IRQN = PI22
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_I2C2_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_I2C2, 0)
+}
+
+Device (I2C3)
+{
+#if CONFIG(SOC_AMD_COMMON_BLOCK_I2C3_TPM_SHARED_WITH_PSP)
+ Name (_HID, "AMDI0019")
+#else
+ Name (_HID, "AMDI0010")
+#endif
+ Name (_UID, 0x3)
+ Method (_CRS, 0) {
+ Local0 = ResourceTemplate() {
+ Interrupt (
+ ResourceConsumer,
+ Edge,
+ ActiveHigh,
+ Exclusive, , , IRQR)
+ { 0 }
+ Memory32Fixed (ReadWrite, APU_I2C3_BASE, 0x1000)
+ }
+ CreateDWordField (Local0, IRQR._INT, IRQN)
+ If (PICM) {
+ IRQN = II23
+ } Else {
+ IRQN = PI23
+ }
+ If (IRQN == 0x1f) {
+ Return (ResourceTemplate() {
+ Memory32Fixed (ReadWrite, APU_I2C3_BASE, 0x1000)
+ })
+ } Else {
+ Return (Local0)
+ }
+ }
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+
+/* If this device is shared with PSP, then PSP takes care of power management */
+#if !CONFIG(SOC_AMD_COMMON_BLOCK_I2C3_TPM_SHARED_WITH_PSP)
+ AOAC_DEVICE(FCH_AOAC_DEV_I2C3, 0)
+#endif
+}
+
+Device (MISC)
+{
+ Name (_HID, "AMD0040")
+ Name (_UID, 0x3)
+ Name (_CRS, ResourceTemplate() {
+ Memory32Fixed (ReadWrite, ACPIMMIO_MISC_BASE, 0x100)
+ })
+ Name (_DSD, Package ()
+ {
+ ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () { "is-rv", 1 },
+ },
+ })
+ Method (_STA, 0x0, NotSerialized)
+ {
+ Return (0x0F)
+ }
+}
diff --git a/src/soc/amd/morgana/acpi/pci0.asl b/src/soc/amd/morgana/acpi/pci0.asl
new file mode 100644
index 0000000000..7ccb00519f
--- /dev/null
+++ b/src/soc/amd/morgana/acpi/pci0.asl
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+Device(PCI0) {
+ Name(_HID, EISAID("PNP0A08")) /* PCI Express Root Bridge */
+ Name(_CID, EISAID("PNP0A03")) /* PCI Root Bridge */
+ External(TOM1, IntObj) /* Generated by root_complex.c */
+
+ Method(_BBN, 0, NotSerialized) {
+ Return(Zero) /* Bus number = 0 */
+ }
+
+ Method(_STA, 0, NotSerialized) {
+ Return(0x0B) /* Status is visible */
+ }
+
+ /* Operating System Capabilities Method */
+ Method(_OSC, 4) {
+ CreateDWordField(Arg3, 0, CDW1) /* Capabilities dword 1 */
+
+ /* Check for proper PCI/PCIe UUID */
+ If (Arg0 == ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")) {
+ /* Let OS control everything */
+ Return (Arg3)
+ } Else {
+ CDW1 |= 4 /* Unrecognized UUID */
+ Return (Arg3)
+ }
+ }
+ Name(CRES, ResourceTemplate() {
+ WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
+ 0x0000, /* address granularity */
+ 0x0000, /* range minimum */
+ 0x00ff, /* range maximum */
+ 0x0000, /* translation */
+ 0x0100, /* length */
+ ,, PSB0) /* ResourceSourceIndex, ResourceSource, DescriptorName */
+
+ IO(Decode16, 0x0cf8, 0x0cf8, 1, 8)
+
+ WORDIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, /* address granularity */
+ 0x0000, /* range minimum */
+ 0x0cf7, /* range maximum */
+ 0x0000, /* translation */
+ 0x0cf8 /* length */
+ )
+
+ WORDIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
+ 0x0000, /* address granularity */
+ 0x0d00, /* range minimum */
+ 0xffff, /* range maximum */
+ 0x0000, /* translation */
+ 0xf300 /* length */
+ )
+
+ Memory32Fixed(READONLY, 0x000a0000, 0x00020000, VGAM) /* VGA memory space */
+ Memory32Fixed(READONLY, 0x000c0000, 0x00020000, EMM1) /* Assume C0000-E0000 empty */
+
+ /* memory space for PCI BARs below 4GB */
+ Memory32Fixed(ReadOnly, 0x00000000, 0x00000000, MMIO)
+ })
+
+ Method(_CRS, 0) {
+ CreateDWordField(CRES, ^MMIO._BAS, MM1B)
+ CreateDWordField(CRES, ^MMIO._LEN, MM1L)
+
+ /* Declare memory between TOM1 and MMCONF as available for PCI MMIO. */
+ MM1B = TOM1
+ Local0 = CONFIG_ECAM_MMCONF_BASE_ADDRESS
+ Local0 -= TOM1
+ MM1L = Local0
+
+ CreateWordField(CRES, ^PSB0._MAX, BMAX)
+ CreateWordField(CRES, ^PSB0._LEN, BLEN)
+ BMAX = CONFIG_ECAM_MMCONF_BUS_NUMBER - 1
+ BLEN = CONFIG_ECAM_MMCONF_BUS_NUMBER
+
+ Return(CRES) /* note to change the Name buffer */
+ } /* end of Method(_SB.PCI0._CRS) */
+
+ /* 0:14.3 - LPC */
+ #include <soc/amd/common/acpi/lpc.asl>
+
+} /* End PCI0 scope */
diff --git a/src/soc/amd/morgana/acpi/pci_int_defs.asl b/src/soc/amd/morgana/acpi/pci_int_defs.asl
new file mode 100644
index 0000000000..efdce0b5f8
--- /dev/null
+++ b/src/soc/amd/morgana/acpi/pci_int_defs.asl
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+/* PCI IRQ mapping registers, C00h-C01h. */
+OperationRegion(PRQM, SystemIO, 0x00000c00, 0x00000002)
+ Field(PRQM, ByteAcc, NoLock, Preserve) {
+ PRQI, 0x00000008,
+ PRQD, 0x00000008, /* Offset: 1h */
+}
+/*
+ * All PIC indexes are prefixed with P.
+ * All IO-APIC indexes are prefixed with I.
+ */
+IndexField(PRQI, PRQD, ByteAcc, NoLock, Preserve) {
+ PIRA, 0x00000008, /* Index 0: INTA */
+ PIRB, 0x00000008, /* Index 1: INTB */
+ PIRC, 0x00000008, /* Index 2: INTC */
+ PIRD, 0x00000008, /* Index 3: INTD */
+ PIRE, 0x00000008, /* Index 4: INTE */
+ PIRF, 0x00000008, /* Index 5: INTF */
+ PIRG, 0x00000008, /* Index 6: INTG */
+ PIRH, 0x00000008, /* Index 7: INTH */
+
+ Offset (0x43),
+ PMMC, 0x00000008, /* Index 0x43: eMMC */
+
+ Offset (0x62),
+ PGPI, 0x00000008, /* Index 0x62: GPIO */
+
+ Offset (0x70),
+ PI20, 0x00000008, /* Index 0x70: I2C0 */
+ PI21, 0x00000008, /* Index 0x71: I2C1 */
+ PI22, 0x00000008, /* Index 0x72: I2C2 */
+ PI23, 0x00000008, /* Index 0x73: I2C3 */
+ PUA0, 0x00000008, /* Index 0x74: UART0 */
+ PUA1, 0x00000008, /* Index 0x75: UART1 */
+ PI24, 0x00000008, /* Index 0x76: I2C4 */
+ PUA4, 0x00000008, /* Index 0x77: UART4 */
+ PUA2, 0x00000008, /* Index 0x78: UART2 */
+ PUA3, 0x00000008, /* Index 0x79: UART3 */
+
+ /* IO-APIC IRQs */
+ Offset (0x80),
+ IORA, 0x00000008, /* Index 0x80: INTA */
+ IORB, 0x00000008, /* Index 0x81: INTB */
+ IORC, 0x00000008, /* Index 0x82: INTC */
+ IORD, 0x00000008, /* Index 0x83: INTD */
+ IORE, 0x00000008, /* Index 0x84: INTE */
+ IORF, 0x00000008, /* Index 0x85: INTF */
+ IORG, 0x00000008, /* Index 0x86: INTG */
+ IORH, 0x00000008, /* Index 0x87: INTH */
+
+ Offset (0xC3),
+ IMMC, 0x00000008, /* Index 0xC3: eMMC */
+
+ Offset (0xE2),
+ IGPI, 0x00000008, /* Index 0xE2: GPIO */
+
+ Offset (0xF0),
+ II20, 0x00000008, /* Index 0xF0: I2C0 */
+ II21, 0x00000008, /* Index 0xF1: I2C1 */
+ II22, 0x00000008, /* Index 0xF2: I2C2 */
+ II23, 0x00000008, /* Index 0xF3: I2C3 */
+ IUA0, 0x00000008, /* Index 0xF4: UART0 */
+ IUA1, 0x00000008, /* Index 0xF5: UART1 */
+ II24, 0x00000008, /* Index 0xF6: I2C4 */
+ IUA4, 0x00000008, /* Index 0xF7: UART4 */
+ IUA2, 0x00000008, /* Index 0xF8: UART2 */
+ IUA3, 0x00000008, /* Index 0xF9: UART3 */
+}
diff --git a/src/soc/amd/morgana/acpi/soc.asl b/src/soc/amd/morgana/acpi/soc.asl
new file mode 100644
index 0000000000..df9911c961
--- /dev/null
+++ b/src/soc/amd/morgana/acpi/soc.asl
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include "globalnvs.asl"
+
+Scope(\_SB) {
+ /* global utility methods expected within the \_SB scope */
+ #include <arch/x86/acpi/globutil.asl>
+
+ #include <soc/amd/common/acpi/gpio_bank_lib.asl>
+
+ #include <soc/amd/common/acpi/osc.asl>
+
+ #include "pci_int_defs.asl"
+
+ #include <soc/amd/common/acpi/pci_int.asl>
+
+ #include "mmio.asl"
+
+ #include "pci0.asl"
+} /* End \_SB scope */
+
+#include <soc/amd/common/acpi/alib.asl>
+
+#include <soc/amd/common/acpi/platform.asl>
+
+#include <soc/amd/common/acpi/sleepstates.asl>
+
+#include <soc/amd/common/acpi/upep.asl>
+
+#if CONFIG(SOC_AMD_COMMON_BLOCK_ACPI_DPTC)
+#include <soc/amd/common/acpi/dptc.asl>
+#endif
+
+/* Enable DPTC interface with AMD ALIB */
+External(\_SB.DPTC, MethodObj)
+
+/*
+ * Platform Notify
+ *
+ * This is called by soc/amd/common/acpi/platform.asl.
+ */
+Method (PNOT)
+{
+ /* Report AC/DC state to ALIB using WAL1() */
+ \WAL1 ()
+
+ If (CondRefOf (\_SB.DPTC)) {
+ \_SB.DPTC()
+ }
+}
diff --git a/src/soc/amd/morgana/agesa_acpi.c b/src/soc/amd/morgana/agesa_acpi.c
new file mode 100644
index 0000000000..78c0e4cdf3
--- /dev/null
+++ b/src/soc/amd/morgana/agesa_acpi.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Make common? */
+
+#include <acpi/acpi.h>
+#include <amdblocks/acpi.h>
+#include <device/device.h>
+#include <FspGuids.h>
+#include <soc/acpi.h>
+#include <types.h>
+
+uintptr_t agesa_write_acpi_tables(const struct device *device, uintptr_t current,
+ acpi_rsdp_t *rsdp)
+{
+ acpi_ivrs_t *ivrs;
+
+ /* add ALIB SSDT from HOB */
+ current = add_agesa_fsp_acpi_table(AMD_FSP_ACPI_ALIB_HOB_GUID, "ALIB", rsdp, current);
+
+ /* IVRS */
+ current = ALIGN(current, 8);
+ ivrs = (acpi_ivrs_t *)current;
+ acpi_create_ivrs(ivrs, acpi_fill_ivrs);
+ current += ivrs->header.length;
+ acpi_add_table(rsdp, ivrs);
+
+ return current;
+}
diff --git a/src/soc/amd/morgana/aoac.c b/src/soc/amd/morgana/aoac.c
new file mode 100644
index 0000000000..d4f96df849
--- /dev/null
+++ b/src/soc/amd/morgana/aoac.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <stdint.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/aoac.h>
+#include <soc/aoac_defs.h>
+#include <soc/southbridge.h>
+#include <delay.h>
+
+#define FCH_AOAC_UART_FOR_CONSOLE \
+ (CONFIG_UART_FOR_CONSOLE == 0 ? FCH_AOAC_DEV_UART0 \
+ : CONFIG_UART_FOR_CONSOLE == 1 ? FCH_AOAC_DEV_UART1 \
+ : CONFIG_UART_FOR_CONSOLE == 2 ? FCH_AOAC_DEV_UART2 \
+ : CONFIG_UART_FOR_CONSOLE == 3 ? FCH_AOAC_DEV_UART3 \
+ : CONFIG_UART_FOR_CONSOLE == 4 ? FCH_AOAC_DEV_UART4 \
+ : -1)
+#if CONFIG(AMD_SOC_CONSOLE_UART) && FCH_AOAC_UART_FOR_CONSOLE == -1
+# error Unsupported UART_FOR_CONSOLE chosen
+#endif
+
+/*
+ * Table of devices that need their AOAC registers enabled and waited
+ * upon (usually about .55 milliseconds). Instead of individual delays
+ * waiting for each device to become available, a single delay will be
+ * executed. The console UART is handled separately from this table.
+ *
+ * TODO: Find out which I2C controllers we really need to enable here.
+ */
+const static unsigned int aoac_devs[] = {
+ FCH_AOAC_DEV_AMBA,
+ FCH_AOAC_DEV_I2C0,
+ FCH_AOAC_DEV_I2C1,
+ FCH_AOAC_DEV_I2C2,
+ FCH_AOAC_DEV_I2C3,
+ FCH_AOAC_DEV_ESPI,
+};
+
+void wait_for_aoac_enabled(unsigned int dev)
+{
+ while (!is_aoac_device_enabled(dev))
+ udelay(100);
+}
+
+void enable_aoac_devices(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(aoac_devs); i++)
+ power_on_aoac_device(aoac_devs[i]);
+
+ if (CONFIG(AMD_SOC_CONSOLE_UART))
+ power_on_aoac_device(FCH_AOAC_UART_FOR_CONSOLE);
+
+ /* Wait for AOAC devices to indicate power and clock OK */
+ for (i = 0; i < ARRAY_SIZE(aoac_devs); i++)
+ wait_for_aoac_enabled(aoac_devs[i]);
+
+ if (CONFIG(AMD_SOC_CONSOLE_UART))
+ wait_for_aoac_enabled(FCH_AOAC_UART_FOR_CONSOLE);
+}
diff --git a/src/soc/amd/morgana/bootblock.c b/src/soc/amd/morgana/bootblock.c
new file mode 100644
index 0000000000..57fac992f6
--- /dev/null
+++ b/src/soc/amd/morgana/bootblock.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/amd_pci_mmconf.h>
+#include <amdblocks/cpu.h>
+#include <bootblock_common.h>
+#include <console/console.h>
+#include <cpu/x86/tsc.h>
+#include <soc/southbridge.h>
+#include <soc/psp_transfer.h>
+#include <stdint.h>
+
+asmlinkage void bootblock_c_entry(uint64_t base_timestamp)
+{
+ early_cache_setup();
+ write_resume_eip();
+ enable_pci_mmconf();
+
+ /*
+ * base_timestamp is raw tsc value. We need to divide by tsc_freq_mhz
+ * to get micro-seconds granularity.
+ */
+ base_timestamp /= tsc_freq_mhz();
+
+ if (CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK))
+ boot_with_psp_timestamp(base_timestamp);
+
+ /*
+ * if VBOOT_STARTS_BEFORE_BOOTBLOCK is not selected or
+ * previous step did nothing, proceed with normal bootblock main.
+ */
+ bootblock_main_with_basetime(base_timestamp);
+}
+
+void bootblock_soc_early_init(void)
+{
+ fch_pre_init();
+}
+
+void bootblock_soc_init(void)
+{
+ u32 val = cpuid_eax(1);
+ printk(BIOS_DEBUG, "Family_Model: %08x\n", val);
+
+ if (CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK)) {
+ verify_psp_transfer_buf();
+ show_psp_transfer_info();
+ }
+
+ fch_early_init();
+}
diff --git a/src/soc/amd/morgana/chip.c b/src/soc/amd/morgana/chip.c
new file mode 100644
index 0000000000..2b97c6cc74
--- /dev/null
+++ b/src/soc/amd/morgana/chip.c
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/aoac.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <fsp/api.h>
+#include <soc/acpi.h>
+#include <soc/aoac_defs.h>
+#include <soc/cpu.h>
+#include <soc/data_fabric.h>
+#include <soc/pci_devs.h>
+#include <soc/southbridge.h>
+#include <types.h>
+#include "chip.h"
+
+/* Supplied by i2c.c */
+extern struct device_operations soc_amd_i2c_mmio_ops;
+/* Supplied by uart.c */
+extern struct device_operations morgana_uart_mmio_ops;
+
+struct device_operations cpu_bus_ops = {
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+ .init = mp_cpu_bus_init,
+ .acpi_fill_ssdt = generate_cpu_entries,
+};
+
+static const char *soc_acpi_name(const struct device *dev)
+{
+ if (dev->path.type == DEVICE_PATH_DOMAIN)
+ return "PCI0";
+
+ if (dev->path.type != DEVICE_PATH_PCI)
+ return NULL;
+
+ printk(BIOS_WARNING, "Unknown PCI device: dev: %d, fn: %d\n",
+ PCI_SLOT(dev->path.pci.devfn), PCI_FUNC(dev->path.pci.devfn));
+ return NULL;
+};
+
+static struct device_operations pci_domain_ops = {
+ .read_resources = pci_domain_read_resources,
+ .set_resources = pci_domain_set_resources,
+ .scan_bus = pci_domain_scan_bus,
+ .acpi_name = soc_acpi_name,
+};
+
+static void set_mmio_dev_ops(struct device *dev)
+{
+ switch (dev->path.mmio.addr) {
+ case APU_I2C0_BASE:
+ case APU_I2C1_BASE:
+ case APU_I2C2_BASE:
+ case APU_I2C3_BASE:
+ dev->ops = &soc_amd_i2c_mmio_ops;
+ break;
+ case APU_UART0_BASE:
+ case APU_UART1_BASE:
+ case APU_UART2_BASE:
+ case APU_UART3_BASE:
+ case APU_UART4_BASE:
+ dev->ops = &morgana_uart_mmio_ops;
+ break;
+ case APU_EMMC_BASE:
+ if (!dev->enabled)
+ power_off_aoac_device(FCH_AOAC_DEV_EMMC);
+ break;
+ }
+}
+
+static void enable_dev(struct device *dev)
+{
+ /* Set the operations if it is a special bus type */
+ switch (dev->path.type) {
+ case DEVICE_PATH_DOMAIN:
+ dev->ops = &pci_domain_ops;
+ break;
+ case DEVICE_PATH_CPU_CLUSTER:
+ dev->ops = &cpu_bus_ops;
+ break;
+ case DEVICE_PATH_MMIO:
+ set_mmio_dev_ops(dev);
+ break;
+ default:
+ break;
+ }
+}
+
+static void soc_init(void *chip_info)
+{
+ default_dev_ops_root.write_acpi_tables = agesa_write_acpi_tables;
+
+ fsp_silicon_init();
+
+ data_fabric_set_mmio_np();
+
+ fch_init(chip_info);
+}
+
+static void soc_final(void *chip_info)
+{
+ fch_final(chip_info);
+}
+
+struct chip_operations soc_amd_morgana_ops = {
+ CHIP_NAME("AMD Morgana SoC")
+ .enable_dev = enable_dev,
+ .init = soc_init,
+ .final = soc_final
+};
diff --git a/src/soc/amd/morgana/chip.h b/src/soc/amd/morgana/chip.h
new file mode 100644
index 0000000000..8875c5e83d
--- /dev/null
+++ b/src/soc/amd/morgana/chip.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef MORGANA_CHIP_H
+#define MORGANA_CHIP_H
+
+#include <amdblocks/chip.h>
+#include <amdblocks/i2c.h>
+#include <gpio.h>
+#include <soc/i2c.h>
+#include <soc/southbridge.h>
+#include <drivers/i2c/designware/dw_i2c.h>
+#include <types.h>
+#include <vendorcode/amd/fsp/morgana/FspUsb.h>
+
+struct soc_amd_morgana_config {
+ struct soc_amd_common_config common_config;
+ u8 i2c_scl_reset;
+ struct dw_i2c_bus_config i2c[I2C_CTRLR_COUNT];
+ struct i2c_pad_control i2c_pad[I2C_CTRLR_COUNT];
+
+ /* Enable S0iX support */
+ bool s0ix_enable;
+
+ enum {
+ DOWNCORE_AUTO = 0,
+ DOWNCORE_1 = 1, /* Run with 1 physical core */
+ DOWNCORE_2 = 3, /* Run with 2 physical cores */
+ DOWNCORE_3 = 4, /* Run with 3 physical cores */
+ DOWNCORE_4 = 6, /* Run with 4 physical cores */
+ DOWNCORE_5 = 8, /* Run with 5 physical cores */
+ DOWNCORE_6 = 9, /* Run with 6 physical cores */
+ DOWNCORE_7 = 10, /* Run with 7 physical cores */
+ } downcore_mode;
+ bool disable_smt; /* disable second thread on all physical cores */
+
+ uint8_t stt_control;
+ uint8_t stt_pcb_sensor_count;
+ uint16_t stt_min_limit;
+ uint16_t stt_m1;
+ uint16_t stt_m2;
+ uint16_t stt_m3;
+ uint16_t stt_m4;
+ uint16_t stt_m5;
+ uint16_t stt_m6;
+ uint16_t stt_c_apu;
+ uint16_t stt_c_gpu;
+ uint16_t stt_c_hs2;
+ uint16_t stt_alpha_apu;
+ uint16_t stt_alpha_gpu;
+ uint16_t stt_alpha_hs2;
+ uint16_t stt_skin_temp_apu;
+ uint16_t stt_skin_temp_gpu;
+ uint16_t stt_skin_temp_hs2;
+ uint16_t stt_error_coeff;
+ uint16_t stt_error_rate_coefficient;
+
+ /* Default */
+ uint8_t stapm_boost;
+ uint32_t stapm_time_constant_s;
+ uint32_t apu_only_sppt_limit;
+ uint32_t sustained_power_limit_mW;
+ uint32_t fast_ppt_limit_mW;
+ uint32_t slow_ppt_limit_mW;
+ uint32_t slow_ppt_time_constant_s;
+ uint32_t thermctl_limit_degreeC;
+ uint32_t vrm_current_limit_mA;
+ uint32_t vrm_maximum_current_limit_mA;
+ uint32_t vrm_soc_current_limit_mA;
+ /* Throttle (e.g., Low/No Battery) */
+ uint32_t vrm_current_limit_throttle_mA;
+ uint32_t vrm_maximum_current_limit_throttle_mA;
+ uint32_t vrm_soc_current_limit_throttle_mA;
+
+ uint8_t smartshift_enable;
+
+ uint8_t system_configuration;
+
+ uint8_t cppc_ctrl;
+ uint8_t cppc_perf_limit_max_range;
+ uint8_t cppc_perf_limit_min_range;
+ uint8_t cppc_epp_max_range;
+ uint8_t cppc_epp_min_range;
+ uint8_t cppc_preferred_cores;
+
+ /* telemetry settings */
+ uint32_t telemetry_vddcrvddfull_scale_current_mA;
+ uint32_t telemetry_vddcrvddoffset;
+ uint32_t telemetry_vddcrsocfull_scale_current_mA;
+ uint32_t telemetry_vddcrsocoffset;
+
+ /* The array index is the general purpose PCIe clock output number. Values in here
+ aren't the values written to the register to have the default to be always on. */
+ enum {
+ GPP_CLK_ON, /* GPP clock always on; default */
+ GPP_CLK_REQ, /* GPP clock controlled by corresponding #CLK_REQx pin */
+ GPP_CLK_OFF, /* GPP clk off */
+ } gpp_clk_config[GPP_CLK_OUTPUT_AVAILABLE];
+
+ /* performance policy for the PCIe links: power consumption vs. link speed */
+ enum {
+ DXIO_PSPP_DISABLED = 0,
+ DXIO_PSPP_PERFORMANCE,
+ DXIO_PSPP_BALANCED,
+ DXIO_PSPP_POWERSAVE,
+ } pspp_policy;
+
+ uint8_t usb_phy_custom;
+ struct usb_phy_config usb_phy;
+};
+
+#endif /* MORGANA_CHIP_H */
diff --git a/src/soc/amd/morgana/chipset.cb b/src/soc/amd/morgana/chipset.cb
new file mode 100644
index 0000000000..fe072a217e
--- /dev/null
+++ b/src/soc/amd/morgana/chipset.cb
@@ -0,0 +1,95 @@
+# TODO: Update for Morgana
+
+chip soc/amd/morgana
+ device cpu_cluster 0 on
+ end
+ device domain 0 on
+ device pci 00.0 alias gnb on end
+ device pci 00.2 alias iommu off end
+
+ device pci 01.0 on end # Dummy Host Bridge
+
+ device pci 02.0 on end # Dummy Host Bridge, do not disable
+ device pci 02.1 alias gpp_bridge_0 off end
+ device pci 02.2 alias gpp_bridge_1 off end
+ device pci 02.3 alias gpp_bridge_2 off end
+ device pci 02.4 alias gpp_bridge_3 off end
+ device pci 02.5 alias gpp_bridge_4 off end
+ device pci 02.6 alias gpp_bridge_5 off end
+
+ device pci 08.0 on end # Dummy Host Bridge, do not disable
+ device pci 08.1 alias gpp_bridge_a off # Internal GPP Bridge 0 to Bus A
+ device pci 0.0 alias gfx off end # Internal GPU (GFX)
+ device pci 0.1 alias gfx_hda off end # Display HD Audio Controller (GFXAZ)
+ device pci 0.2 alias crypto off end # Crypto Coprocessor
+ device pci 0.3 alias xhci_0 off
+ chip drivers/usb/acpi
+ register "type" = "UPC_TYPE_HUB"
+ device usb 0.0 alias xhci_0_root_hub off
+ chip drivers/usb/acpi
+ device usb 3.0 alias usb3_port0 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.0 alias usb2_port0 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.1 alias usb2_port1 off end
+ end
+ end
+ end
+ end
+ device pci 0.4 alias xhci_1 off
+ chip drivers/usb/acpi
+ register "type" = "UPC_TYPE_HUB"
+ device usb 0.0 alias xhci_1_root_hub off
+ chip drivers/usb/acpi
+ device usb 3.0 alias usb3_port2 off end
+ end
+ chip drivers/usb/acpi
+ device usb 3.1 alias usb3_port3 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.0 alias usb2_port2 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.1 alias usb2_port3 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.2 alias usb2_port4 off end
+ end
+ end
+ end
+ end
+ device pci 0.5 alias acp off end # Audio Processor (ACP)
+ device pci 0.6 alias hda off end # Audio Processor HD Audio Controller (main AZ)
+ device pci 0.7 alias mp2 off end # Sensor Fusion Hub (MP2)
+ end
+ device pci 08.2 alias gpp_bridge_b off end # Internal GPP Bridge 1 to Bus B
+ device pci 08.3 alias gpp_bridge_c off # Internal GPP Bridge 2 to Bus C
+ device pci 0.0 alias xhci_2 off end # Might also be a dummy device with different PCI DID
+ end
+
+ device pci 14.0 alias smbus on end # primary FCH function
+ device pci 14.3 alias lpc_bridge on end
+
+ device pci 18.0 alias data_fabric_0 on end
+ device pci 18.1 alias data_fabric_1 on end
+ device pci 18.2 alias data_fabric_2 on end
+ device pci 18.3 alias data_fabric_3 on end
+ device pci 18.4 alias data_fabric_4 on end
+ device pci 18.5 alias data_fabric_5 on end
+ device pci 18.6 alias data_fabric_6 on end
+ device pci 18.7 alias data_fabric_7 on end
+ end
+
+ device mmio 0xfedc2000 alias i2c_0 off end
+ device mmio 0xfedc3000 alias i2c_1 off end
+ device mmio 0xfedc4000 alias i2c_2 off end
+ device mmio 0xfedc5000 alias i2c_3 off end
+ device mmio 0xfedc9000 alias uart_0 off end
+ device mmio 0xfedca000 alias uart_1 off end
+ device mmio 0xfedce000 alias uart_2 off end
+ device mmio 0xfedcf000 alias uart_3 off end
+ device mmio 0xfedd1000 alias uart_4 off end
+ device mmio 0xfedd5000 alias emmc off end
+end
diff --git a/src/soc/amd/morgana/config.c b/src/soc/amd/morgana/config.c
new file mode 100644
index 0000000000..161d86cd49
--- /dev/null
+++ b/src/soc/amd/morgana/config.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <amdblocks/chip.h>
+#include <device/device.h>
+#include "chip.h"
+
+const struct soc_amd_common_config *soc_get_common_config(void)
+{
+ /* config_of_soc calls die() internally if cfg was NULL, so no need to re-check */
+ const struct soc_amd_morgana_config *cfg = config_of_soc();
+ return &cfg->common_config;
+}
diff --git a/src/soc/amd/morgana/cpu.c b/src/soc/amd/morgana/cpu.c
new file mode 100644
index 0000000000..fe5a1b8ae7
--- /dev/null
+++ b/src/soc/amd/morgana/cpu.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <acpi/acpi.h>
+#include <amdblocks/cpu.h>
+#include <amdblocks/iomap.h>
+#include <amdblocks/mca.h>
+#include <console/console.h>
+#include <cpu/amd/microcode.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/mp.h>
+#include <cpu/x86/mtrr.h>
+#include <acpi/acpi.h>
+#include <device/device.h>
+#include <soc/cpu.h>
+#include <soc/iomap.h>
+
+_Static_assert(CONFIG_MAX_CPUS == 8, "Do not override MAX_CPUS. To reduce the number of "
+ "available cores, use the downcore_mode and disable_smt devicetree settings instead.");
+
+/* MP and SMM loading initialization */
+
+void mp_init_cpus(struct bus *cpu_bus)
+{
+ extern const struct mp_ops amd_mp_ops_with_smm;
+ if (mp_init_with_smm(cpu_bus, &amd_mp_ops_with_smm) != CB_SUCCESS)
+ die_with_post_code(POST_HW_INIT_FAILURE,
+ "mp_init_with_smm failed. Halting.\n");
+
+ /* pre_mp_init made the flash not cacheable. Reset to WP for performance. */
+ mtrr_use_temp_range(FLASH_BELOW_4GB_MAPPING_REGION_BASE,
+ FLASH_BELOW_4GB_MAPPING_REGION_SIZE, MTRR_TYPE_WRPROT);
+
+ /* SMMINFO only needs to be set up when booting from S5 */
+ if (!acpi_is_wakeup_s3())
+ apm_control(APM_CNT_SMMINFO);
+}
+
+static void zen_2_3_init(struct device *dev)
+{
+ check_mca();
+ set_cstate_io_addr();
+
+ amd_update_microcode_from_cbfs();
+}
+
+static struct device_operations cpu_dev_ops = {
+ .init = zen_2_3_init,
+};
+
+static struct cpu_device_id cpu_table[] = {
+ { X86_VENDOR_AMD, MORGANA_A0_CPUID}, /* TODO: Update for Morgana */
+ { 0, 0 },
+};
+
+static const struct cpu_driver zen_2_3 __cpu_driver = {
+ .ops = &cpu_dev_ops,
+ .id_table = cpu_table,
+};
diff --git a/src/soc/amd/morgana/data_fabric.c b/src/soc/amd/morgana/data_fabric.c
new file mode 100644
index 0000000000..0249b8a426
--- /dev/null
+++ b/src/soc/amd/morgana/data_fabric.c
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <acpi/acpi_device.h>
+#include <amdblocks/data_fabric.h>
+#include <arch/hpet.h>
+#include <console/console.h>
+#include <cpu/x86/lapic_def.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <soc/data_fabric.h>
+#include <soc/iomap.h>
+#include <types.h>
+
+void data_fabric_set_mmio_np(void)
+{
+ /*
+ * Mark region from HPET-LAPIC or 0xfed00000-0xfee00000-1 as NP.
+ *
+ * AGESA has already programmed the NB MMIO routing, however nothing
+ * is yet marked as non-posted.
+ *
+ * If there exists an overlapping routing base/limit pair, trim its
+ * base or limit to avoid the new NP region. If any pair exists
+ * completely within HPET-LAPIC range, remove it. If any pair surrounds
+ * HPET-LAPIC, it must be split into two regions.
+ *
+ * TODO(b/156296146): Remove the settings from AGESA and allow coreboot
+ * to own everything. If not practical, consider erasing all settings
+ * and have coreboot reprogram them. At that time, make the source
+ * below more flexible.
+ * * Note that the code relies on the granularity of the HPET and
+ * LAPIC addresses being sufficiently large that the shifted limits
+ * +/-1 are always equivalent to the non-shifted values +/-1.
+ */
+
+ unsigned int i;
+ int reg;
+ uint32_t base, limit, ctrl;
+ const uint32_t np_bot = HPET_BASE_ADDRESS >> D18F0_MMIO_SHIFT;
+ const uint32_t np_top = (LAPIC_DEFAULT_BASE - 1) >> D18F0_MMIO_SHIFT;
+
+ data_fabric_print_mmio_conf();
+
+ for (i = 0; i < NUM_NB_MMIO_REGS; i++) {
+ /* Adjust all registers that overlap */
+ ctrl = data_fabric_broadcast_read32(0, NB_MMIO_CONTROL(i));
+ if (!(ctrl & (DF_MMIO_WE | DF_MMIO_RE)))
+ continue; /* not enabled */
+
+ base = data_fabric_broadcast_read32(0, NB_MMIO_BASE(i));
+ limit = data_fabric_broadcast_read32(0, NB_MMIO_LIMIT(i));
+
+ if (base > np_top || limit < np_bot)
+ continue; /* no overlap at all */
+
+ if (base >= np_bot && limit <= np_top) {
+ data_fabric_disable_mmio_reg(i); /* 100% within, so remove */
+ continue;
+ }
+
+ if (base < np_bot && limit > np_top) {
+ /* Split the configured region */
+ data_fabric_broadcast_write32(0, NB_MMIO_LIMIT(i), np_bot - 1);
+ reg = data_fabric_find_unused_mmio_reg();
+ if (reg < 0) {
+ /* Although a pair could be freed later, this condition is
+ * very unusual and deserves analysis. Flag an error and
+ * leave the topmost part unconfigured. */
+ printk(BIOS_ERR,
+ "Error: Not enough NB MMIO routing registers\n");
+ continue;
+ }
+ data_fabric_broadcast_write32(0, NB_MMIO_BASE(reg), np_top + 1);
+ data_fabric_broadcast_write32(0, NB_MMIO_LIMIT(reg), limit);
+ data_fabric_broadcast_write32(0, NB_MMIO_CONTROL(reg), ctrl);
+ continue;
+ }
+
+ /* If still here, adjust only the base or limit */
+ if (base <= np_bot)
+ data_fabric_broadcast_write32(0, NB_MMIO_LIMIT(i), np_bot - 1);
+ else
+ data_fabric_broadcast_write32(0, NB_MMIO_BASE(i), np_top + 1);
+ }
+
+ reg = data_fabric_find_unused_mmio_reg();
+ if (reg < 0) {
+ printk(BIOS_ERR, "Error: cannot configure region as NP\n");
+ return;
+ }
+
+ data_fabric_broadcast_write32(0, NB_MMIO_BASE(reg), np_bot);
+ data_fabric_broadcast_write32(0, NB_MMIO_LIMIT(reg), np_top);
+ data_fabric_broadcast_write32(0, NB_MMIO_CONTROL(reg),
+ (IOMS0_FABRIC_ID << DF_MMIO_DST_FABRIC_ID_SHIFT) | DF_MMIO_NP
+ | DF_MMIO_WE | DF_MMIO_RE);
+
+ data_fabric_print_mmio_conf();
+}
+
+static const char *data_fabric_acpi_name(const struct device *dev)
+{
+ switch (dev->device) {
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF0:
+ return "DFD0";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF1:
+ return "DFD1";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF2:
+ return "DFD2";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF3:
+ return "DFD3";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF4:
+ return "DFD4";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF5:
+ return "DFD5";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF6:
+ return "DFD6";
+ case PCI_DID_AMD_FAM17H_MODELA0H_DF7:
+ return "DFD7";
+ default:
+ printk(BIOS_ERR, "%s: Unhandled device id 0x%x\n", __func__, dev->device);
+ }
+
+ return NULL;
+}
+
+static struct device_operations data_fabric_ops = {
+ .read_resources = noop_read_resources,
+ .set_resources = noop_set_resources,
+ .acpi_name = data_fabric_acpi_name,
+ .acpi_fill_ssdt = acpi_device_write_pci_dev,
+};
+
+static const unsigned short pci_device_ids[] = {
+ PCI_DID_AMD_FAM17H_MODELA0H_DF0, /* TODO: Update for Morgana */
+ PCI_DID_AMD_FAM17H_MODELA0H_DF1,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF2,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF3,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF4,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF5,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF6,
+ PCI_DID_AMD_FAM17H_MODELA0H_DF7,
+ 0
+};
+
+static const struct pci_driver data_fabric_driver __pci_driver = {
+ .ops = &data_fabric_ops,
+ .vendor = PCI_VID_AMD,
+ .devices = pci_device_ids,
+};
diff --git a/src/soc/amd/morgana/early_fch.c b/src/soc/amd/morgana/early_fch.c
new file mode 100644
index 0000000000..f6ccf554ef
--- /dev/null
+++ b/src/soc/amd/morgana/early_fch.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/espi.h>
+#include <amdblocks/i2c.h>
+#include <amdblocks/lpc.h>
+#include <amdblocks/pmlib.h>
+#include <amdblocks/smbus.h>
+#include <soc/i2c.h>
+#include <soc/southbridge.h>
+#include <soc/uart.h>
+
+#include "chip.h"
+
+/* Table to switch SCL pins to outputs to initially reset the I2C peripherals */
+static const struct soc_i2c_scl_pin i2c_scl_pins[] = {
+ I2C_RESET_SCL_PIN(I2C0_SCL_PIN, GPIO_I2C0_SCL),
+ I2C_RESET_SCL_PIN(I2C1_SCL_PIN, GPIO_I2C1_SCL),
+ I2C_RESET_SCL_PIN(I2C2_SCL_PIN, GPIO_I2C2_SCL),
+ I2C_RESET_SCL_PIN(I2C3_SCL_PIN, GPIO_I2C3_SCL),
+};
+
+static void reset_i2c_peripherals(void)
+{
+ const struct soc_amd_morgana_config *cfg = config_of_soc();
+ struct soc_i2c_peripheral_reset_info reset_info;
+
+ reset_info.i2c_scl_reset_mask = cfg->i2c_scl_reset & GPIO_I2C_MASK;
+ reset_info.i2c_scl = i2c_scl_pins;
+ reset_info.num_pins = ARRAY_SIZE(i2c_scl_pins);
+ sb_reset_i2c_peripherals(&reset_info);
+}
+
+/* Before console init */
+void fch_pre_init(void)
+{
+ /* Enable_acpimmio_decode_pm04 to enable the ACPIMMIO decode which is needed to access
+ the GPIO registers. */
+ enable_acpimmio_decode_pm04();
+ /* Setup SPI base by calling lpc_early_init before setting up eSPI. */
+ lpc_early_init();
+
+ /* Setup eSPI to enable port80 routing if the board is using eSPI and the eSPI
+ interface hasn't already been set up in verstage on PSP */
+ if (CONFIG(SOC_AMD_COMMON_BLOCK_USE_ESPI) && !CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK))
+ configure_espi_with_mb_hook();
+
+ fch_spi_early_init();
+ fch_smbus_init();
+ fch_enable_cf9_io();
+ fch_enable_legacy_io();
+ fch_disable_legacy_dma_io();
+ enable_aoac_devices();
+
+ /*
+ * On reset Range_0 defaults to enabled. We want to start with a clean
+ * slate to not have things unexpectedly enabled.
+ */
+ clear_uart_legacy_config();
+
+ if (CONFIG(AMD_SOC_CONSOLE_UART))
+ set_uart_config(CONFIG_UART_FOR_CONSOLE);
+
+ /* disable the keyboard reset function before mainboard GPIO setup */
+ if (CONFIG(DISABLE_KEYBOARD_RESET_PIN))
+ fch_disable_kb_rst();
+}
+
+/* After console init */
+void fch_early_init(void)
+{
+ reset_i2c_peripherals();
+ pm_set_power_failure_state();
+ fch_print_pmxc0_status();
+ i2c_soc_early_init();
+ show_spi_speeds_and_modes();
+
+ if (CONFIG(DISABLE_SPI_FLASH_ROM_SHARING))
+ lpc_disable_spi_rom_sharing();
+}
diff --git a/src/soc/amd/morgana/espi_util.c b/src/soc/amd/morgana/espi_util.c
new file mode 100644
index 0000000000..1d0fc1731a
--- /dev/null
+++ b/src/soc/amd/morgana/espi_util.c
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/spi.h>
+#include <soc/espi.h>
+#include <types.h>
+
+#define ESPI_CNTRL_REGISTER 0x10
+#define LOCK_SPIX10_BIT2 BIT(3)
+#define ESPI_MUX_SPI1 BIT(2)
+#define ROM_ADDR_WR_PROT BIT(1)
+#define DIS_ESPI_MASCTL_REG_WR BIT(0)
+
+void espi_switch_to_spi1_pads(void)
+{
+ uint8_t reg = spi_read8(ESPI_CNTRL_REGISTER);
+
+ reg |= ESPI_MUX_SPI1;
+
+ spi_write8(ESPI_CNTRL_REGISTER, reg);
+}
diff --git a/src/soc/amd/morgana/fch.c b/src/soc/amd/morgana/fch.c
new file mode 100644
index 0000000000..f9f4649438
--- /dev/null
+++ b/src/soc/amd/morgana/fch.c
@@ -0,0 +1,230 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/acpi.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/amd_pci_util.h>
+#include <amdblocks/gpio.h>
+#include <amdblocks/smi.h>
+#include <assert.h>
+#include <bootstate.h>
+#include <cpu/x86/smm.h>
+#include <amdblocks/i2c.h>
+#include <soc/amd_pci_int_defs.h>
+#include <soc/iomap.h>
+#include <soc/i2c.h>
+#include <soc/smi.h>
+#include <soc/southbridge.h>
+#include "chip.h"
+
+/*
+ * Table of APIC register index and associated IRQ name. Using IDX_XXX_NAME
+ * provides a visible association with the index, therefore helping
+ * maintainability of table. If a new index/name is defined in
+ * amd_pci_int_defs.h, just add the pair at the end of this table.
+ * Order is not important.
+ */
+const static struct irq_idx_name irq_association[] = {
+ { PIRQ_A, "INTA#" },
+ { PIRQ_B, "INTB#" },
+ { PIRQ_C, "INTC#" },
+ { PIRQ_D, "INTD#" },
+ { PIRQ_E, "INTE#" },
+ { PIRQ_F, "INTF#/GENINT2" },
+ { PIRQ_G, "INTG#" },
+ { PIRQ_H, "INTH#" },
+ { PIRQ_MISC, "Misc" },
+ { PIRQ_MISC0, "Misc0" },
+ { PIRQ_HPET_L, "HPET_L" },
+ { PIRQ_HPET_H, "HPET_H" },
+ { PIRQ_SIRQA, "Ser IRQ INTA" },
+ { PIRQ_SIRQB, "Ser IRQ INTB" },
+ { PIRQ_SIRQC, "Ser IRQ INTC" },
+ { PIRQ_SIRQD, "Ser IRQ INTD" },
+ { PIRQ_SCI, "SCI" },
+ { PIRQ_SMBUS, "SMBUS" },
+ { PIRQ_ASF, "ASF" },
+ { PIRQ_PMON, "PerMon" },
+ { PIRQ_SD, "SD" },
+ { PIRQ_SDIO, "SDIO" },
+ { PIRQ_CIR, "CIR" },
+ { PIRQ_GPIOA, "GPIOa" },
+ { PIRQ_GPIOB, "GPIOb" },
+ { PIRQ_GPIOC, "GPIOc" },
+ { PIRQ_EMMC, "eMMC" },
+ { PIRQ_GPP0, "GPP0" },
+ { PIRQ_GPP1, "GPP1" },
+ { PIRQ_GPP2, "GPP2" },
+ { PIRQ_GPP3, "GPP3" },
+ { PIRQ_GPIO, "GPIO" },
+ { PIRQ_I2C0, "I2C0" },
+ { PIRQ_I2C1, "I2C1" },
+ { PIRQ_I2C2, "I2C2" },
+ { PIRQ_I2C3, "I2C3" },
+ { PIRQ_UART0, "UART0" },
+ { PIRQ_UART1, "UART1" },
+ { PIRQ_I2C4, "I2C4" },
+ { PIRQ_UART4, "UART4" },
+ { PIRQ_UART2, "UART2" },
+ { PIRQ_UART3, "UART3" },
+};
+
+const struct irq_idx_name *sb_get_apic_reg_association(size_t *size)
+{
+ *size = ARRAY_SIZE(irq_association);
+ return irq_association;
+}
+
+static void fch_clk_output_48Mhz(void)
+{
+ uint32_t ctrl = misc_read32(MISC_CLK_CNTL0);
+ /* Enable BP_X48M0 Clock Output */
+ ctrl |= BP_X48M0_OUTPUT_EN;
+ /* Disable clock output in S0i3 */
+ ctrl |= BP_X48M0_S0I3_DIS;
+ misc_write32(MISC_CLK_CNTL0, ctrl);
+}
+
+static void fch_init_acpi_ports(void)
+{
+ u32 reg;
+
+ /* We use some of these ports in SMM regardless of whether or not
+ * ACPI tables are generated. Enable these ports indiscriminately.
+ */
+
+ pm_write16(PM_EVT_BLK, ACPI_PM_EVT_BLK);
+ pm_write16(PM1_CNT_BLK, ACPI_PM1_CNT_BLK);
+ pm_write16(PM_TMR_BLK, ACPI_PM_TMR_BLK);
+ pm_write16(PM_GPE0_BLK, ACPI_GPE0_BLK);
+
+ if (CONFIG(HAVE_SMI_HANDLER)) {
+ /* APMC - SMI Command Port */
+ pm_write16(PM_ACPI_SMI_CMD, APM_CNT);
+ configure_smi(SMITYPE_SMI_CMD_PORT, SMI_MODE_SMI);
+
+ /* SMI on SlpTyp requires sending SMI before completion
+ response of the I/O write. */
+ reg = pm_read32(PM_PCI_CTRL);
+ reg |= FORCE_SLPSTATE_RETRY;
+ pm_write32(PM_PCI_CTRL, reg);
+
+ /* Disable SlpTyp feature */
+ reg = pm_read8(PM_RST_CTRL1);
+ reg &= ~SLPTYPE_CONTROL_EN;
+ pm_write8(PM_RST_CTRL1, reg);
+
+ configure_smi(SMITYPE_SLP_TYP, SMI_MODE_SMI);
+ } else {
+ pm_write16(PM_ACPI_SMI_CMD, 0);
+ }
+
+ /* Decode ACPI registers and enable standard features */
+ pm_write8(PM_ACPI_CONF, PM_ACPI_DECODE_STD |
+ PM_ACPI_GLOBAL_EN |
+ PM_ACPI_RTC_EN_EN |
+ PM_ACPI_TIMER_EN_EN);
+}
+
+/* configure the general purpose PCIe clock outputs according to the devicetree settings */
+static void gpp_clk_setup(void)
+{
+ const struct soc_amd_morgana_config *cfg = config_of_soc();
+
+ /* look-up table to be able to iterate over the PCIe clock output settings */
+ const uint8_t gpp_clk_shift_lut[GPP_CLK_OUTPUT_COUNT] = {
+ GPP_CLK0_REQ_SHIFT,
+ GPP_CLK1_REQ_SHIFT,
+ GPP_CLK2_REQ_SHIFT,
+ GPP_CLK3_REQ_SHIFT,
+ GPP_CLK4_REQ_SHIFT,
+ GPP_CLK5_REQ_SHIFT,
+ GPP_CLK6_REQ_SHIFT,
+ };
+
+ uint32_t gpp_clk_ctl = misc_read32(GPP_CLK_CNTRL);
+
+ for (int i = 0; i < GPP_CLK_OUTPUT_COUNT; i++) {
+ gpp_clk_ctl &= ~GPP_CLK_REQ_MASK(gpp_clk_shift_lut[i]);
+ /*
+ * The remapping of values is done so that the default of the enum used for the
+ * devicetree settings is the clock being enabled, so that a missing devicetree
+ * configuration for this will result in an always active clock and not an
+ * inactive PCIe clock output. Only the configuration for the clock outputs
+ * available on the package is provided via the devicetree; the rest is
+ * switched off unconditionally.
+ */
+ switch (i < GPP_CLK_OUTPUT_AVAILABLE ? cfg->gpp_clk_config[i] : GPP_CLK_OFF) {
+ case GPP_CLK_REQ:
+ gpp_clk_ctl |= GPP_CLK_REQ_EXT(gpp_clk_shift_lut[i]);
+ break;
+ case GPP_CLK_OFF:
+ gpp_clk_ctl |= GPP_CLK_REQ_OFF(gpp_clk_shift_lut[i]);
+ break;
+ case GPP_CLK_ON:
+ default:
+ gpp_clk_ctl |= GPP_CLK_REQ_ON(gpp_clk_shift_lut[i]);
+ }
+ }
+
+ misc_write32(GPP_CLK_CNTRL, gpp_clk_ctl);
+}
+
+static void cgpll_clock_gate_init(void)
+{
+ uint32_t t;
+
+ t = misc_read32(MISC_CLKGATEDCNTL);
+ t |= ALINKCLK_GATEOFFEN;
+ t |= BLINKCLK_GATEOFFEN;
+ t |= XTAL_PAD_S0I3_TURNOFF_EN;
+ t |= XTAL_PAD_S3_TURNOFF_EN;
+ t |= XTAL_PAD_S5_TURNOFF_EN;
+ misc_write32(MISC_CLKGATEDCNTL, t);
+
+ t = misc_read32(MISC_CGPLL_CONFIGURATION0);
+ t |= USB_PHY_CMCLK_S3_DIS;
+ t |= USB_PHY_CMCLK_S0I3_DIS;
+ t |= USB_PHY_CMCLK_S5_DIS;
+ misc_write32(MISC_CGPLL_CONFIGURATION0, t);
+
+ t = pm_read32(PM_ISACONTROL);
+ t |= ABCLKGATEEN;
+ pm_write32(PM_ISACONTROL, t);
+}
+
+void fch_init(void *chip_info)
+{
+ i2c_soc_init();
+ fch_init_acpi_ports();
+
+ acpi_pm_gpe_add_events_print_events();
+ gpio_add_events();
+
+ gpp_clk_setup();
+ fch_clk_output_48Mhz();
+ cgpll_clock_gate_init();
+}
+
+void fch_final(void *chip_info)
+{
+}
+
+static void set_pci_irqs(void *unused)
+{
+ /* Write PCI_INTR regs 0xC00/0xC01 */
+ write_pci_int_table();
+
+ /* pirq_data is consumed by `write_pci_cfg_irqs` */
+ populate_pirq_data();
+
+ /* Write IRQs for all devicetree enabled devices */
+ write_pci_cfg_irqs();
+}
+
+/*
+ * Hook this function into the PCI state machine
+ * on entry into BS_DEV_ENABLE.
+ */
+BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, set_pci_irqs, NULL);
diff --git a/src/soc/amd/morgana/fsp_m_params.c b/src/soc/amd/morgana/fsp_m_params.c
new file mode 100644
index 0000000000..e1e8c26caa
--- /dev/null
+++ b/src/soc/amd/morgana/fsp_m_params.c
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+/* TODO: See what can be moved to common */
+
+#include <amdblocks/apob_cache.h>
+#include <amdblocks/ioapic.h>
+#include <amdblocks/memmap.h>
+#include <assert.h>
+#include <console/uart.h>
+#include <device/device.h>
+#include <fsp/api.h>
+#include <soc/platform_descriptors.h>
+#include <soc/pci_devs.h>
+#include <string.h>
+#include <types.h>
+#include <vendorcode/amd/fsp/morgana/FspUsb.h>
+#include "chip.h"
+
+__weak void mb_pre_fspm(FSP_M_CONFIG *mcfg)
+{
+}
+
+static void fill_dxio_descriptors(FSP_M_CONFIG *mcfg,
+ const fsp_dxio_descriptor *descs, size_t num)
+{
+ size_t i;
+
+ ASSERT_MSG(num <= FSPM_UPD_DXIO_DESCRIPTOR_COUNT,
+ "Too many DXIO descriptors provided.");
+
+ for (i = 0; i < num; i++) {
+ memcpy(mcfg->dxio_descriptor[i], &descs[i], sizeof(mcfg->dxio_descriptor[0]));
+ }
+}
+
+static void fill_ddi_descriptors(FSP_M_CONFIG *mcfg,
+ const fsp_ddi_descriptor *descs, size_t num)
+{
+ size_t i;
+
+ ASSERT_MSG(num <= FSPM_UPD_DDI_DESCRIPTOR_COUNT,
+ "Too many DDI descriptors provided.");
+
+ for (i = 0; i < num; i++) {
+ memcpy(&mcfg->ddi_descriptor[i], &descs[i], sizeof(mcfg->ddi_descriptor[0]));
+ }
+}
+
+static void fsp_fill_pcie_ddi_descriptors(FSP_M_CONFIG *mcfg)
+{
+ const fsp_dxio_descriptor *fsp_dxio = NULL;
+ const fsp_ddi_descriptor *fsp_ddi = NULL;
+ size_t num_dxio = 0;
+ size_t num_ddi = 0;
+
+ mainboard_get_dxio_ddi_descriptors(&fsp_dxio, &num_dxio,
+ &fsp_ddi, &num_ddi);
+ fill_dxio_descriptors(mcfg, fsp_dxio, num_dxio);
+ fill_ddi_descriptors(mcfg, fsp_ddi, num_ddi);
+}
+
+static void fsp_assign_ioapic_upds(FSP_M_CONFIG *mcfg)
+{
+ mcfg->gnb_ioapic_base = GNB_IO_APIC_ADDR;
+ mcfg->gnb_ioapic_id = GNB_IOAPIC_ID;
+ mcfg->fch_ioapic_id = FCH_IOAPIC_ID;
+}
+
+void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version)
+{
+ FSP_M_CONFIG *mcfg = &mupd->FspmConfig;
+ const struct soc_amd_morgana_config *config = config_of_soc();
+
+ mupd->FspmArchUpd.NvsBufferPtr = (uintptr_t)soc_fill_apob_cache();
+
+ mcfg->pci_express_base_addr = CONFIG_ECAM_MMCONF_BASE_ADDRESS;
+ mcfg->tseg_size = CONFIG_SMM_TSEG_SIZE;
+ mcfg->serial_port_base = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
+ mcfg->serial_port_use_mmio = CONFIG(DRIVERS_UART_8250MEM);
+ mcfg->serial_port_baudrate = get_uart_baudrate();
+ mcfg->serial_port_refclk = uart_platform_refclk();
+
+ /* 0 is default */
+ mcfg->ccx_down_core_mode = config->downcore_mode;
+ mcfg->ccx_disable_smt = config->disable_smt;
+
+ /* when stt_control isn't 1, FSP will ignore the other stt values */
+ mcfg->stt_control = config->stt_control;
+ mcfg->stt_pcb_sensor_count = config->stt_pcb_sensor_count;
+ mcfg->stt_min_limit = config->stt_min_limit;
+ mcfg->stt_m1 = config->stt_m1;
+ mcfg->stt_m2 = config->stt_m2;
+ mcfg->stt_m3 = config->stt_m3;
+ mcfg->stt_m4 = config->stt_m4;
+ mcfg->stt_m5 = config->stt_m5;
+ mcfg->stt_m6 = config->stt_m6;
+ mcfg->stt_c_apu = config->stt_c_apu;
+ mcfg->stt_c_gpu = config->stt_c_gpu;
+ mcfg->stt_c_hs2 = config->stt_c_hs2;
+ mcfg->stt_alpha_apu = config->stt_alpha_apu;
+ mcfg->stt_alpha_gpu = config->stt_alpha_gpu;
+ mcfg->stt_alpha_hs2 = config->stt_alpha_hs2;
+ mcfg->stt_skin_temp_apu = config->stt_skin_temp_apu;
+ mcfg->stt_skin_temp_gpu = config->stt_skin_temp_gpu;
+ mcfg->stt_skin_temp_hs2 = config->stt_skin_temp_hs2;
+ mcfg->stt_error_coeff = config->stt_error_coeff;
+ mcfg->stt_error_rate_coefficient = config->stt_error_rate_coefficient;
+
+ /* all following fields being 0 is a valid config */
+ mcfg->stapm_boost = config->stapm_boost;
+ mcfg->stapm_time_constant = config->stapm_time_constant_s;
+ mcfg->apu_only_sppt_limit = config->apu_only_sppt_limit;
+ mcfg->sustained_power_limit = config->sustained_power_limit_mW;
+ mcfg->fast_ppt_limit = config->fast_ppt_limit_mW;
+ mcfg->slow_ppt_limit = config->slow_ppt_limit_mW;
+ mcfg->slow_ppt_time_constant = config->slow_ppt_time_constant_s;
+ mcfg->thermctl_limit = config->thermctl_limit_degreeC;
+
+ /* 0 is default */
+ mcfg->smartshift_enable = config->smartshift_enable;
+
+ /* 0 is default */
+ mcfg->system_configuration = config->system_configuration;
+
+ /* when cppc_ctrl is 0 the other values won't be used */
+ mcfg->cppc_ctrl = config->cppc_ctrl;
+ mcfg->cppc_perf_limit_max_range = config->cppc_perf_limit_max_range;
+ mcfg->cppc_perf_limit_min_range = config->cppc_perf_limit_min_range;
+ mcfg->cppc_epp_max_range = config->cppc_epp_max_range;
+ mcfg->cppc_epp_min_range = config->cppc_epp_min_range;
+ mcfg->cppc_preferred_cores = config->cppc_preferred_cores;
+
+ /* S0i3 enable */
+ mcfg->s0i3_enable = config->s0ix_enable;
+ mcfg->iommu_support = is_devfn_enabled(IOMMU_DEVFN);
+
+ /* voltage regulator telemetry settings */
+ mcfg->telemetry_vddcrvddfull_scale_current =
+ config->telemetry_vddcrvddfull_scale_current_mA;
+ mcfg->telemetry_vddcrvddoffset =
+ config->telemetry_vddcrvddoffset;
+ mcfg->telemetry_vddcrsocfull_scale_current =
+ config->telemetry_vddcrsocfull_scale_current_mA;
+ mcfg->telemetry_vddcrsocOffset =
+ config->telemetry_vddcrsocoffset;
+
+ /* PCIe power vs. speed */
+ mcfg->pspp_policy = config->pspp_policy;
+
+ mcfg->enable_nb_azalia = is_dev_enabled(DEV_PTR(gfx_hda));
+ mcfg->hda_enable = is_dev_enabled(DEV_PTR(hda));
+
+ if (config->usb_phy_custom) {
+ /* devicetree config is const, use local copy */
+ static struct usb_phy_config lcl_usb_phy;
+ lcl_usb_phy = config->usb_phy;
+ mcfg->usb_phy = &lcl_usb_phy;
+ mcfg->usb_phy->Version_Major = FSP_USB_STRUCT_MAJOR_VERSION;
+ mcfg->usb_phy->Version_Minor = FSP_USB_STRUCT_MINOR_VERSION;
+ mcfg->usb_phy->TableLength = sizeof(struct usb_phy_config);
+ } else {
+ mcfg->usb_phy = NULL;
+ }
+
+ fsp_fill_pcie_ddi_descriptors(mcfg);
+ fsp_assign_ioapic_upds(mcfg);
+ mb_pre_fspm(mcfg);
+}
diff --git a/src/soc/amd/morgana/fsp_s_params.c b/src/soc/amd/morgana/fsp_s_params.c
new file mode 100644
index 0000000000..a68647cb1c
--- /dev/null
+++ b/src/soc/amd/morgana/fsp_s_params.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <acpi/acpi.h>
+#include <amdblocks/apob_cache.h>
+#include <device/pci.h>
+#include <fsp/api.h>
+#include <program_loading.h>
+
+static void fsp_assign_vbios_upds(FSP_S_CONFIG *scfg)
+{
+ scfg->vbios_buffer = CONFIG(RUN_FSP_GOP) ? PCI_VGA_RAM_IMAGE_START : 0;
+}
+
+void platform_fsp_silicon_init_params_cb(FSPS_UPD *supd)
+{
+ FSP_S_CONFIG *scfg = &supd->FspsConfig;
+
+ fsp_assign_vbios_upds(scfg);
+
+ /*
+ * At this point FSP-S has been loaded into RAM. If we were to start loading the APOB
+ * before FSP-S was loaded, we would introduce contention onto the SPI bus and
+ * slow down the FSP-S read from SPI. Since FSP-S takes a while to execute and performs
+ * no SPI operations, we can read the APOB while FSP-S executes.
+ */
+ start_apob_cache_read();
+ /*
+ * We enqueue the payload to be loaded after the APOB. This might cause a bit of
+ * bus contention when loading uCode and OPROMs, but since those calls happen at
+ * different points in the boot state machine it's a little harder to sequence all the
+ * async loading correctly. So in order to keep the complexity down, we enqueue the
+ * payload preload here. The end goal will be to add uCode and OPROM preloading
+ * before the payload so that the sequencing is correct.
+ *
+ * While FSP-S is executing, it's not currently possible to enqueue other transactions
+ * because FSP-S doesn't call `thread_yield()`. So the payload will start loading
+ * right after FSP-S completes.
+ */
+ if (!acpi_is_wakeup_s3())
+ payload_preload();
+}
diff --git a/src/soc/amd/morgana/fw.cfg b/src/soc/amd/morgana/fw.cfg
new file mode 100644
index 0000000000..055aa9c15e
--- /dev/null
+++ b/src/soc/amd/morgana/fw.cfg
@@ -0,0 +1,38 @@
+# PSP fw config file
+
+FIRMWARE_LOCATION 3rdparty/amd_blobs/morgana/psp
+
+# type file
+AMD_PUBKEY_FILE TypeId0x00_Root.tkn
+PSPBTLDR_AB_STAGE1_FILE TypeId0x01_PspBootLoader1.sbin
+PSPSECUREOS_FILE TypeId0x02_PspOS.sbin
+PSP_SMUFW1_SUB0_FILE TypeId0x08_SmuFirmware.sbin
+PSPSECUREDEBUG_FILE TypeId0x09_SDU.stkn
+PSPTRUSTLETS_FILE TypeId0x0C_FtpmDrv.csbin
+PSP_SMUFW2_SUB0_FILE TypeId0x12_SmuFirmware2.sbin
+PSP_SEC_DEBUG_FILE TypeId0x13_PspEarlyUnlock.sbin
+PSP_HW_IPCFG_FILE TypeId0x20_HwIpCfg.sbin
+PSP_IKEK_FILE TypeId0x21_PspiKek.bin
+PSP_SECG0_FILE TypeId0x24_SecPolicy.sbin
+PSP_MP2FW0_FILE TypeId0x25_Mp2Fw.sbin
+AMD_DRIVER_ENTRIES TypeId0x28_PspSystemDriver.sbin
+PSP_S0I3_FILE TypeId0x2D_AgesaRunTimeDrv.sbin
+PSP_ABL0_FILE TypeId0x30_AgesaBootloaderU_LPDDR5.sbin
+VBIOS_BTLOADER_FILE TypeId0x3C_VbiosBootLoader.sbin
+SECURE_POLICY_L1_FILE TypeId0x45_SecPolicytOS.sbin
+UNIFIEDUSB_FILE TypeId0x44_UnifiedUsb.sbin
+KEYDBBL_FILE TypeId0x50_KeyDbBl.sbin
+KEYDB_TOS_FILE TypeId0x51_KeyDbTos.sbin
+SPL_TABLE_FILE TypeId0x55_SplTableBl.sbin
+MSMU_FILE TypeId0x5A_Msmu.sbin
+SPIROM_CONFIG_FILE TypeId0x5C_SpiRomConfig_Dual66.sbin
+DMCUB_FILE TypeId0x71_DmcubFw.sbin
+PSPBTLDR_AB_FILE TypeId0x73_PspBootLoader2.sbin
+TA_IKEK_FILE TypeId0x8D_IkekTa.bin
+
+# BDT
+PSP_PMUI_FILE_SUB0_INS1 TypeId0x64_Appb_Lpddr5Imem1.csbin
+PSP_PMUD_FILE_SUB0_INS1 TypeId0x65_Appb_Lpddr5Dmem1.csbin
+PSP_PMUI_FILE_SUB0_INS2 TypeId0x64_Appb_Lpddr5Imem2.csbin
+PSP_PMUD_FILE_SUB0_INS2 TypeId0x65_Appb_Lpddr5Dmem2.csbin
+PSP_MP2CFG_FILE TypeId0x6a_Mp2FwConfig.sbin
diff --git a/src/soc/amd/morgana/gpio.c b/src/soc/amd/morgana/gpio.c
new file mode 100644
index 0000000000..873d333bca
--- /dev/null
+++ b/src/soc/amd/morgana/gpio.c
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/gpio.h>
+#include <soc/gpio.h>
+#include <types.h>
+
+/* see the IOMUX function table for the mapping from GPIO number to GEVENT number */
+static const struct soc_amd_event gpio_event_table[] = {
+ { GPIO_0, GEVENT_21 }, /* GPIO0 may only be used as PWR_BTN_L in ACPI */
+ { GPIO_1, GEVENT_19 },
+ { GPIO_2, GEVENT_8 },
+ { GPIO_3, GEVENT_2 },
+ { GPIO_4, GEVENT_4 },
+ { GPIO_5, GEVENT_7 },
+ { GPIO_6, GEVENT_10 },
+ { GPIO_7, GEVENT_11 },
+ { GPIO_8, GEVENT_23 },
+ { GPIO_9, GEVENT_22 },
+ { GPIO_11, GEVENT_5 },
+ { GPIO_16, GEVENT_12 },
+ { GPIO_17, GEVENT_13 },
+ { GPIO_18, GEVENT_14 },
+ { GPIO_22, GEVENT_3 },
+ { GPIO_23, GEVENT_16 },
+ { GPIO_24, GEVENT_15 },
+ { GPIO_29, GEVENT_9 },
+ { GPIO_32, GEVENT_17 },
+ { GPIO_40, GEVENT_20 },
+ { GPIO_84, GEVENT_18 },
+ { GPIO_89, GEVENT_0 },
+ { GPIO_90, GEVENT_1 },
+ { GPIO_91, GEVENT_6 },
+};
+
+void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items)
+{
+ *table = gpio_event_table;
+ *items = ARRAY_SIZE(gpio_event_table);
+}
diff --git a/src/soc/amd/morgana/i2c.c b/src/soc/amd/morgana/i2c.c
new file mode 100644
index 0000000000..23a38ba54d
--- /dev/null
+++ b/src/soc/amd/morgana/i2c.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/i2c.h>
+#include <console/console.h>
+#include <soc/i2c.h>
+#include <soc/southbridge.h>
+#include "chip.h"
+
+#if ENV_X86
+static const struct soc_i2c_ctrlr_info i2c_ctrlr[I2C_CTRLR_COUNT] = {
+ { I2C_MASTER_MODE, APU_I2C0_BASE, "I2C0" },
+ { I2C_MASTER_MODE, APU_I2C1_BASE, "I2C1" },
+ { I2C_MASTER_MODE, APU_I2C2_BASE, "I2C2" },
+ { I2C_MASTER_MODE, APU_I2C3_BASE, "I2C3" }
+};
+#else
+static struct soc_i2c_ctrlr_info i2c_ctrlr[I2C_CTRLR_COUNT] = {
+ { I2C_MASTER_MODE, 0, "" },
+ { I2C_MASTER_MODE, 0, "" },
+ { I2C_MASTER_MODE, 0, "" },
+ { I2C_MASTER_MODE, 0, "" }
+};
+
+void i2c_set_bar(unsigned int bus, uintptr_t bar)
+{
+ if (bus >= ARRAY_SIZE(i2c_ctrlr)) {
+ printk(BIOS_ERR, "Error: i2c index out of bounds: %u.", bus);
+ return;
+ }
+
+ i2c_ctrlr[bus].bar = bar;
+}
+#endif
+
+void soc_i2c_misc_init(unsigned int bus, const struct dw_i2c_bus_config *cfg)
+{
+ const struct soc_amd_morgana_config *config = config_of_soc();
+
+ if (bus >= ARRAY_SIZE(config->i2c_pad))
+ return;
+
+ fch_i23c_pad_init(bus, cfg->speed, &config->i2c_pad[bus]);
+}
+
+const struct soc_i2c_ctrlr_info *soc_get_i2c_ctrlr_info(size_t *num_ctrlrs)
+{
+ *num_ctrlrs = ARRAY_SIZE(i2c_ctrlr);
+ return i2c_ctrlr;
+}
+
+const struct dw_i2c_bus_config *soc_get_i2c_bus_config(size_t *num_buses)
+{
+ const struct soc_amd_morgana_config *config = config_of_soc();
+
+ *num_buses = ARRAY_SIZE(config->i2c);
+ return config->i2c;
+}
diff --git a/src/soc/amd/morgana/include/soc/acpi.h b/src/soc/amd/morgana/include/soc/acpi.h
new file mode 100644
index 0000000000..132bac45c1
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/acpi.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Move to common */
+
+#ifndef AMD_MORGANA_ACPI_H
+#define AMD_MORGANA_ACPI_H
+
+#include <acpi/acpi.h>
+#include <amdblocks/acpi.h>
+#include <device/device.h>
+#include <stdint.h>
+
+#define ACPI_SCI_IRQ 9
+
+/* RTC Registers */
+#define RTC_DATE_ALARM 0x0d
+#define RTC_ALT_CENTURY 0x32
+#define RTC_CENTURY 0x48
+
+uintptr_t agesa_write_acpi_tables(const struct device *device, uintptr_t current,
+ acpi_rsdp_t *rsdp);
+
+#endif /* AMD_MORGANA_ACPI_H */
diff --git a/src/soc/amd/morgana/include/soc/amd_pci_int_defs.h b/src/soc/amd/morgana/include/soc/amd_pci_int_defs.h
new file mode 100644
index 0000000000..2835c09e69
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/amd_pci_int_defs.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_AMD_PCI_INT_DEFS_H
+#define AMD_MORGANA_AMD_PCI_INT_DEFS_H
+
+/*
+ * PIRQ and device routing - these define the index into the
+ * FCH PCI_INTR 0xC00/0xC01 interrupt routing table.
+ */
+
+#define PIRQ_NC 0x1f /* Not Used */
+#define PIRQ_A 0x00 /* INT A */
+#define PIRQ_B 0x01 /* INT B */
+#define PIRQ_C 0x02 /* INT C */
+#define PIRQ_D 0x03 /* INT D */
+#define PIRQ_E 0x04 /* INT E */
+#define PIRQ_F 0x05 /* INT F */
+#define PIRQ_G 0x06 /* INT G */
+#define PIRQ_H 0x07 /* INT H */
+#define PIRQ_MISC 0x08 /* Miscellaneous IRQ Settings */
+#define PIRQ_MISC0 0x09 /* Miscellaneous0 IRQ Settings */
+#define PIRQ_HPET_L 0x0a /* HPET TMR{0..2}_CONF_CAP_H[0:7] */
+#define PIRQ_HPET_H 0x0b /* HPET TMR{0..2}_CONF_CAP_H[15:8] */
+#define PIRQ_SIRQA 0x0c /* Serial IRQ INTA */
+#define PIRQ_SIRQB 0x0d /* Serial IRQ INTB */
+#define PIRQ_SIRQC 0x0e /* Serial IRQ INTC */
+#define PIRQ_SIRQD 0x0f /* Serial IRQ INTD */
+#define PIRQ_SCI 0x10 /* SCI IRQ */
+#define PIRQ_SMBUS 0x11 /* SMBUS */
+#define PIRQ_ASF 0x12 /* ASF */
+/* 0x13-0x15 reserved */
+#define PIRQ_PMON 0x16 /* Performance Monitor */
+#define PIRQ_SD 0x17 /* SD */
+/* 0x18-0x19 reserved */
+#define PIRQ_SDIO 0x1a /* SDIO */
+/* 0x1b-0x1f reserved */
+#define PIRQ_CIR 0x20 /* CIR, no IRQ connected */
+#define PIRQ_GPIOA 0x21 /* GPIOa from PAD_FANIN0 */
+#define PIRQ_GPIOB 0x22 /* GPIOb from PAD_FANOUT0 */
+#define PIRQ_GPIOC 0x23 /* GPIOc no IRQ connected */
+/* 0x24-0x42 reserved */
+#define PIRQ_EMMC 0x43 /* eMMC */
+/* 0x44-0x4f reserved */
+#define PIRQ_GPP0 0x50 /* GPPInt0 */
+#define PIRQ_GPP1 0x51 /* GPPInt1 */
+#define PIRQ_GPP2 0x52 /* GPPInt2 */
+#define PIRQ_GPP3 0x53 /* GPPInt3 */
+/* 0x54-0x61 reserved */
+#define PIRQ_GPIO 0x62 /* GPIO Controller Interrupt */
+/* 0x63-0x6f reserved */
+#define PIRQ_I2C0 0x70 /* I2C0 */
+#define PIRQ_I2C1 0x71 /* I2C1 */
+#define PIRQ_I2C2 0x72 /* I2C2 */
+#define PIRQ_I2C3 0x73 /* I2C3 */
+#define PIRQ_UART0 0x74 /* UART0 */
+#define PIRQ_UART1 0x75 /* UART1 */
+#define PIRQ_I2C4 0x76 /* I2C4 */
+#define PIRQ_UART4 0x77 /* UART4 */
+#define PIRQ_UART2 0x78 /* UART2 */
+#define PIRQ_UART3 0x79 /* UART3 */
+
+#endif /* AMD_MORGANA_AMD_PCI_INT_DEFS_H */
diff --git a/src/soc/amd/morgana/include/soc/aoac_defs.h b/src/soc/amd/morgana/include/soc/aoac_defs.h
new file mode 100644
index 0000000000..c52f502a83
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/aoac_defs.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_AOAC_DEFS_H
+#define AMD_MORGANA_AOAC_DEFS_H
+
+/* FCH AOAC device offsets for AOAC_DEV_D3_CTL/AOAC_DEV_D3_STATE */
+#define FCH_AOAC_DEV_CLK_GEN 0
+#define FCH_AOAC_DEV_I2C0 5
+#define FCH_AOAC_DEV_I2C1 6
+#define FCH_AOAC_DEV_I2C2 7
+#define FCH_AOAC_DEV_I2C3 8
+#define FCH_AOAC_DEV_I2C4 9
+#define FCH_AOAC_DEV_I2C5 10
+#define FCH_AOAC_DEV_UART0 11
+#define FCH_AOAC_DEV_UART1 12
+#define FCH_AOAC_DEV_UART2 16
+#define FCH_AOAC_DEV_AMBA 17
+#define FCH_AOAC_DEV_UART4 20
+#define FCH_AOAC_DEV_UART3 26
+#define FCH_AOAC_DEV_ESPI 27
+#define FCH_AOAC_DEV_EMMC 28
+
+#endif /* AMD_MORGANA_AOAC_DEFS_H */
diff --git a/src/soc/amd/morgana/include/soc/cpu.h b/src/soc/amd/morgana/include/soc/cpu.h
new file mode 100644
index 0000000000..ac85861dca
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/cpu.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef AMD_MORGANA_CPU_H
+#define AMD_MORGANA_CPU_H
+
+#define MORGANA_A0_CPUID 0x008a0f00 /* TODO: Update for Morgana */
+
+#endif /* AMD_MORGANA_CPU_H */
diff --git a/src/soc/amd/morgana/include/soc/data_fabric.h b/src/soc/amd/morgana/include/soc/data_fabric.h
new file mode 100644
index 0000000000..eba4cd8b98
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/data_fabric.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_DATA_FABRIC_H
+#define AMD_MORGANA_DATA_FABRIC_H
+
+#include <types.h>
+
+/* SoC-specific bits in D18F0_MMIO_CTRL0 */
+#define DF_MMIO_NP BIT(16)
+
+#define IOMS0_FABRIC_ID 9
+
+#define NUM_NB_MMIO_REGS 8
+
+void data_fabric_set_mmio_np(void);
+
+#endif /* AMD_MORGANA_DATA_FABRIC_H */
diff --git a/src/soc/amd/morgana/include/soc/espi.h b/src/soc/amd/morgana/include/soc/espi.h
new file mode 100644
index 0000000000..d8217c6eab
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/espi.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_ESPI_H
+#define AMD_MORGANA_ESPI_H
+
+void espi_switch_to_spi1_pads(void);
+
+#endif /* AMD_MORGANA_ESPI_H */
diff --git a/src/soc/amd/morgana/include/soc/gpio.h b/src/soc/amd/morgana/include/soc/gpio.h
new file mode 100644
index 0000000000..87db27d5d1
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/gpio.h
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_GPIO_H
+#define AMD_MORGANA_GPIO_H
+
+#define GPIO_DEVICE_NAME "AMD0030"
+#define GPIO_DEVICE_DESC "GPIO Controller"
+
+#ifndef __ACPI__
+#include <soc/iomap.h>
+#include <amdblocks/gpio.h>
+#endif /* !__ACPI__ */
+
+#include <amdblocks/gpio_defs.h>
+
+/* The following sections describe only the GPIOs defined for this SOC */
+
+#define SOC_GPIO_TOTAL_PINS 158
+
+/* Bank 0: GPIO_0 - GPIO_63 */
+#define GPIO_0 0
+#define GPIO_1 1
+#define GPIO_2 2
+#define GPIO_3 3
+#define GPIO_4 4
+#define GPIO_5 5
+#define GPIO_6 6
+#define GPIO_7 7
+#define GPIO_8 8
+#define GPIO_9 9
+#define GPIO_10 10
+#define GPIO_11 11
+#define GPIO_12 12
+#define GPIO_13 13
+#define GPIO_14 14
+#define GPIO_16 16
+#define GPIO_17 17
+#define GPIO_18 18
+#define GPIO_19 19
+#define GPIO_20 20
+#define GPIO_21 21
+#define GPIO_22 22
+#define GPIO_23 23
+#define GPIO_24 24
+#define GPIO_26 26
+#define GPIO_27 27
+#define GPIO_29 29
+#define GPIO_30 30
+#define GPIO_31 31
+#define GPIO_32 32
+#define GPIO_38 38
+#define GPIO_39 39
+#define GPIO_40 40
+#define GPIO_42 42
+
+/* Bank 1: GPIO_64 - GPIO_127 */
+#define GPIO_67 67
+#define GPIO_68 68
+#define GPIO_69 69
+#define GPIO_70 70
+#define GPIO_74 74
+#define GPIO_75 75
+#define GPIO_76 76
+#define GPIO_77 77
+#define GPIO_78 78
+#define GPIO_79 79
+#define GPIO_80 80
+#define GPIO_81 81
+#define GPIO_84 84
+#define GPIO_85 85
+#define GPIO_86 86
+#define GPIO_89 89
+#define GPIO_90 90
+#define GPIO_91 91
+#define GPIO_92 92
+#define GPIO_104 104
+#define GPIO_105 105
+#define GPIO_106 106
+#define GPIO_107 107
+#define GPIO_113 113
+#define GPIO_114 114
+#define GPIO_115 115
+#define GPIO_116 116
+
+/* Bank 2: GPIO_128 - GPIO_191 */
+#define GPIO_130 130
+#define GPIO_131 131
+#define GPIO_132 132
+#define GPIO_135 135
+#define GPIO_136 136
+#define GPIO_137 137
+#define GPIO_138 138
+#define GPIO_139 139
+#define GPIO_140 140
+#define GPIO_141 141
+#define GPIO_142 142
+#define GPIO_143 143
+#define GPIO_144 144
+#define GPIO_145 145
+#define GPIO_146 146
+#define GPIO_147 147
+#define GPIO_148 148
+#define GPIO_153 153
+#define GPIO_154 154
+#define GPIO_155 155
+#define GPIO_156 156
+#define GPIO_157 157
+
+/* IOMUX function names and values */
+#define GPIO_0_IOMUX_PWR_BTN_L 0
+#define GPIO_0_IOMUX_GPIOxx 1
+#define GPIO_1_IOMUX_SYS_RESET_L 0
+#define GPIO_1_IOMUX_GPIOxx 1
+#define GPIO_2_IOMUX_WAKE_L 0
+#define GPIO_2_IOMUX_GPIOxx 1
+#define GPIO_3_IOMUX_GPIOxx 0
+#define GPIO_4_IOMUX_GPIOxx 0
+#define GPIO_5_IOMUX_GPIOxx 0
+#define GPIO_5_IOMUX_DEVSLP0 1
+#define GPIO_6_IOMUX_GPIOxx 0
+#define GPIO_6_IOMUX_DEVSLP1 1
+#define GPIO_6_IOMUX_MDIO0_SCL 2
+#define GPIO_7_IOMUX_GPIOxx 0
+#define GPIO_7_IOMUX_SVI_RST_L 1
+#define GPIO_8_IOMUX_GPIOxx 0
+#define GPIO_8_IOMUX_TMU_CLK_OUT0 1
+#define GPIO_8_IOMUX_TMU_CLK_OUT1 2
+#define GPIO_9_IOMUX_GPIOxx 0
+/* GPIO 9 IOMUX == 1 is also GPIOxx */
+#define GPIO_9_IOMUX_MDIO2_SCL 2
+#define GPIO_10_IOMUX_GPIOxx 0
+#define GPIO_10_IOMUX_S0A3_GPIO 1
+#define GPIO_11_IOMUX_GPIOxx 0
+#define GPIO_11_IOMUX_BLINK 1
+#define GPIO_11_IOMUX_MDIO3_SDA 2
+#define GPIO_12_IOMUX_LLB_L 0
+#define GPIO_12_IOMUX_GPIOxx 1
+#define GPIO_12_IOMUX_LPC_PME_L 2
+#define GPIO_13_IOMUX_USB_SBTX_0 0
+#define GPIO_13_IOMUX_GPIOxx 1
+#define GPIO_14_IOMUX_USB_SBTX_1 0
+#define GPIO_14_IOMUX_GPIOxx 1
+#define GPIO_16_IOMUX_USB_OC0_L 0
+#define GPIO_16_IOMUX_GPIOxx 1
+#define GPIO_17_IOMUX_USB_OC1_L 0
+#define GPIO_17_IOMUX_GPIOxx 1
+#define GPIO_18_IOMUX_USB_OC2_L 0
+#define GPIO_18_IOMUX_GPIOxx 1
+#define GPIO_19_IOMUX_SMBUS1_SCL 0
+#define GPIO_19_IOMUX_I2C3_SCL 1
+#define GPIO_19_IOMUX_I3C3_SCL 2
+#define GPIO_19_IOMUX_GPIOxx 3
+#define GPIO_20_IOMUX_SMBUS1_SDA 0
+#define GPIO_20_IOMUX_I2C3_SDA 1
+#define GPIO_20_IOMUX_I3C3_SDA 2
+#define GPIO_20_IOMUX_GPIOxx 3
+#define GPIO_21_IOMUX_ESPI_RESET_L 0
+#define GPIO_21_IOMUX_KBRST_L 1
+#define GPIO_21_IOMUX_GPIOxx 2
+#define GPIO_22_IOMUX_LDRQ0_L 0
+#define GPIO_22_IOMUX_ESPI_ALERT_D1 1
+#define GPIO_22_IOMUX_GPIOxx 2
+#define GPIO_22_IOMUX_SD0_CMD 3
+#define GPIO_23_IOMUX_AC_PRES 0
+#define GPIO_23_IOMUX_GPIOxx 1
+#define GPIO_23_IOMUX_MDIO2_SDA 2
+#define GPIO_24_IOMUX_USB_OC3_L 0
+#define GPIO_24_IOMUX_GPIOxx 1
+#define GPIO_26_IOMUX_PCIE_RST0_L 0
+#define GPIO_26_IOMUX_GPIOxx 1
+#define GPIO_27_IOMUX_GPIOxx 0
+#define GPIO_27_IOMUX_PCIE_RST1_L 1
+#define GPIO_29_IOMUX_SPI_TPM_CS_L 0
+#define GPIO_29_IOMUX_GPIOxx 1
+#define GPIO_30_IOMUX_SPI_CS2_L 0
+#define GPIO_30_IOMUX_ESPI_CS_L 1
+#define GPIO_30_IOMUX_GPIOxx 2
+#define GPIO_31_IOMUX_SPI_CS3_L 0
+#define GPIO_31_IOMUX_GPIOxx 1
+#define GPIO_32_IOMUX_GPIOxx 0
+#define GPIO_32_IOMUX_LPC_RST_L 1
+#define GPIO_32_IOMUX_MDIO3_SCL 2
+#define GPIO_38_IOMUX_CLK_REQ5_L 0
+#define GPIO_38_IOMUX_GPIOxx 1
+#define GPIO_38_IOMUX_MDIO1_SDA 2
+#define GPIO_39_IOMUX_CLK_REQ6_L 0
+#define GPIO_39_IOMUX_GPIOxx 1
+#define GPIO_39_IOMUX_MDIO1_SCL 2
+#define GPIO_40_IOMUX_GPIOxx 0
+/* GPIO 40 IOMUX == 1 is also GPIOxx */
+#define GPIO_40_IOMUX_MDIO0_SDA 2
+#define GPIO_42_IOMUX_GPIOxx 0
+#define GPIO_67_IOMUX_SPI_ROM_REQ 0
+#define GPIO_67_IOMUX_GPIOxx 1
+#define GPIO_68_IOMUX_SPI1_DAT2 0
+#define GPIO_68_IOMUX_GPIOxx 1
+#define GPIO_68_IOMUX_SERIRQ 2
+#define GPIO_68_IOMUX_SD0_DATA3 3
+#define GPIO_69_IOMUX_SPI1_DAT3 0
+#define GPIO_69_IOMUX_GPIOxx 1
+#define GPIO_69_IOMUX_SD0_CLK 2
+#define GPIO_70_IOMUX_SPI2_CLK 0
+#define GPIO_70_IOMUX_GPIOxx 1
+#define GPIO_74_IOMUX_SPI1_CS1_L 0
+#define GPIO_74_IOMUX_GPIOxx 1
+#define GPIO_74_IOMUX_GFX10_CAC_IPIO0 2
+#define GPIO_75_IOMUX_SPI2_CS1_L 0
+#define GPIO_75_IOMUX_LPCCLK1 1
+#define GPIO_75_IOMUX_GPIOxx 2
+#define GPIO_76_IOMUX_SPI_ROM_GNT 0
+#define GPIO_76_IOMUX_GPIOxx 1
+#define GPIO_77_IOMUX_SPI1_CLK 0
+#define GPIO_77_IOMUX_GPIOxx 1
+/* GPIO 77 IOMUX == 2 is also GPIOxx */
+#define GPIO_77_IOMUX_SD0_DATA0 3
+#define GPIO_78_IOMUX_SPI1_CS2_L 0
+#define GPIO_78_IOMUX_GPIOxx 1
+#define GPIO_78_IOMUX_GFX10_CAC_IPIO1 2
+#define GPIO_78_IOMUX_SD0_DATA1 3
+#define GPIO_79_IOMUX_SPI1_CS3_L 0
+#define GPIO_79_IOMUX_GPIOxx 1
+#define GPIO_79_IOMUX_LPC_CLKRUN_L 2
+#define GPIO_80_IOMUX_SPI1_DAT1 0
+#define GPIO_80_IOMUX_GPIOxx 1
+/* GPIO 80 IOMUX == 2 is also GPIOxx */
+#define GPIO_80_IOMUX_SD0_DATA2 3
+#define GPIO_81_IOMUX_SPI1_DAT0 0
+#define GPIO_81_IOMUX_GPIOxx 1
+#define GPIO_84_IOMUX_FANIN0 0
+#define GPIO_84_IOMUX_GPIOxx 1
+#define GPIO_85_IOMUX_FANOUT0 0
+#define GPIO_85_IOMUX_GPIOxx 1
+#define GPIO_86_IOMUX_GPIOxx 0
+#define GPIO_86_IOMUX_LPC_SMI_L 1
+#define GPIO_89_IOMUX_GENINT1_L 0
+#define GPIO_89_IOMUX_PSP_INTR0 1
+#define GPIO_89_IOMUX_GPIOxx 2
+#define GPIO_90_IOMUX_GENINT2_L 0
+#define GPIO_90_IOMUX_PSP_INTR1 1
+#define GPIO_90_IOMUX_GPIOxx 2
+#define GPIO_91_IOMUX_SPKR 0
+#define GPIO_91_IOMUX_GPIOxx 1
+#define GPIO_92_IOMUX_CLK_REQ0_L 0
+#define GPIO_92_IOMUX_SATA_IS0_L 1
+#define GPIO_92_IOMUX_SATA_ZP0_L 2
+#define GPIO_92_IOMUX_GPIOxx 3
+#define GPIO_104_IOMUX_SPI2_DAT0 0
+#define GPIO_104_IOMUX_GPIOxx 1
+#define GPIO_105_IOMUX_SPI2_DAT1 0
+#define GPIO_105_IOMUX_GPIOxx 1
+#define GPIO_106_IOMUX_SPI2_DAT2 0
+#define GPIO_106_IOMUX_GPIOxx 1
+#define GPIO_107_IOMUX_SPI2_DAT3 0
+#define GPIO_107_IOMUX_GPIOxx 1
+#define GPIO_113_IOMUX_SMBUS0_SCL 0
+#define GPIO_113_IOMUX_I2C2_SCL 1
+#define GPIO_113_IOMUX_I3C2_SCL 2
+#define GPIO_113_IOMUX_GPIOxx 3
+#define GPIO_114_IOMUX_SMBUS0_SDA 0
+#define GPIO_114_IOMUX_I2C2_SDA 1
+#define GPIO_114_IOMUX_I3C2_SDA 2
+#define GPIO_114_IOMUX_GPIOxx 3
+#define GPIO_115_IOMUX_CLK_REQ1_L 0
+#define GPIO_115_IOMUX_GPIOxx 1
+#define GPIO_116_IOMUX_CLK_REQ2_L 0
+#define GPIO_116_IOMUX_GPIOxx 1
+#define GPIO_130_IOMUX_SATA_ACT_L 0
+#define GPIO_130_IOMUX_GPIOxx 1
+#define GPIO_131_IOMUX_CLK_REQ3_L 0
+#define GPIO_131_IOMUX_SATA_IS1_L 1
+#define GPIO_131_IOMUX_SATA_ZP1_L 2
+#define GPIO_131_IOMUX_GPIOxx 3
+#define GPIO_132_IOMUX_CLK_REQ4_L 0
+#define GPIO_132_IOMUX_OSCIN 1
+#define GPIO_132_IOMUX_GPIOxx 2
+#define GPIO_135_IOMUX_GPIOxx 0
+#define GPIO_135_IOMUX_UART2_CTS_L 1
+#define GPIO_135_IOMUX_UART3_TXD 2
+#define GPIO_136_IOMUX_GPIOxx 0
+#define GPIO_136_IOMUX_UART2_RXD 1
+#define GPIO_137_IOMUX_GPIOxx 0
+#define GPIO_137_IOMUX_UART2_RTS_L 1
+#define GPIO_137_IOMUX_UART3_RXD 2
+#define GPIO_138_IOMUX_GPIOxx 0
+#define GPIO_138_IOMUX_UART2_TXD 1
+#define GPIO_139_IOMUX_GPIOxx 0
+#define GPIO_139_IOMUX_UART2_INTR 1
+#define GPIO_140_IOMUX_GPIOxx 0
+#define GPIO_140_IOMUX_UART0_CTS_L 1
+#define GPIO_140_IOMUX_UART1_TXD 2
+#define GPIO_141_IOMUX_GPIOxx 0
+#define GPIO_141_IOMUX_UART0_RXD 1
+#define GPIO_142_IOMUX_GPIOxx 0
+#define GPIO_142_IOMUX_UART0_RTS_L 1
+#define GPIO_142_IOMUX_UART1_RXD 2
+#define GPIO_143_IOMUX_GPIOxx 0
+#define GPIO_143_IOMUX_UART0_TXD 1
+#define GPIO_144_IOMUX_GPIOxx 0
+#define GPIO_144_IOMUX_SHUTDOWN_L 1
+#define GPIO_144_IOMUX_UART0_INTR 2
+#define GPIO_145_IOMUX_I2C0_SCL 0
+#define GPIO_145_IOMUX_I3C0_SCL 1
+#define GPIO_145_IOMUX_GPIOxx 2
+#define GPIO_146_IOMUX_I2C0_SDA 0
+#define GPIO_146_IOMUX_I3C0_SDA 1
+#define GPIO_146_IOMUX_GPIOxx 2
+#define GPIO_147_IOMUX_I2C1_SCL 0
+#define GPIO_147_IOMUX_I3C1_SCL 1
+#define GPIO_147_IOMUX_GPIOxx 2
+#define GPIO_148_IOMUX_I2C1_SDA 0
+#define GPIO_148_IOMUX_I3C1_SDA 1
+#define GPIO_148_IOMUX_GPIOxx 2
+#define GPIO_153_IOMUX_GPIOxx 0
+#define GPIO_153_IOMUX_UART4_CTS_L 1
+#define GPIO_154_IOMUX_GPIOxx 0
+#define GPIO_154_IOMUX_UART4_RTS_L 1
+#define GPIO_155_IOMUX_GPIOxx 0
+#define GPIO_155_IOMUX_UART4_RXD 1
+#define GPIO_156_IOMUX_GPIOxx 0
+#define GPIO_156_IOMUX_UART4_TXD 1
+#define GPIO_157_IOMUX_GPIOxx 0
+#define GPIO_157_IOMUX_UART4_INTR 1
+
+#endif /* AMD_MORGANA_GPIO_H */
diff --git a/src/soc/amd/morgana/include/soc/i2c.h b/src/soc/amd/morgana/include/soc/i2c.h
new file mode 100644
index 0000000000..10b7249006
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/i2c.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_I2C_H
+#define AMD_MORGANA_I2C_H
+
+#include <soc/gpio.h>
+#include <types.h>
+
+#define GPIO_I2C0_SCL BIT(0)
+#define GPIO_I2C1_SCL BIT(1)
+#define GPIO_I2C2_SCL BIT(2)
+#define GPIO_I2C3_SCL BIT(3)
+#define GPIO_I2C_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+
+
+#define I2C0_SCL_PIN GPIO_145
+#define I2C1_SCL_PIN GPIO_147
+#define I2C2_SCL_PIN GPIO_113
+#define I2C3_SCL_PIN GPIO_19
+
+#define I2C0_SCL_PIN_IOMUX_GPIOxx GPIO_145_IOMUX_GPIOxx
+#define I2C1_SCL_PIN_IOMUX_GPIOxx GPIO_147_IOMUX_GPIOxx
+#define I2C2_SCL_PIN_IOMUX_GPIOxx GPIO_113_IOMUX_GPIOxx
+#define I2C3_SCL_PIN_IOMUX_GPIOxx GPIO_19_IOMUX_GPIOxx
+
+void i2c_set_bar(unsigned int bus, uintptr_t bar);
+
+#endif /* AMD_MORGANA_I2C_H */
diff --git a/src/soc/amd/morgana/include/soc/iomap.h b/src/soc/amd/morgana/include/soc/iomap.h
new file mode 100644
index 0000000000..53b7bc2f42
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/iomap.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_IOMAP_H
+#define AMD_MORGANA_IOMAP_H
+
+#define I2C_MASTER_DEV_COUNT 4
+#define I2C_MASTER_START_INDEX 0
+#define I2C_PERIPHERAL_DEV_COUNT 0 /* TODO: Only master for now. */
+#define I2C_CTRLR_COUNT (I2C_MASTER_DEV_COUNT + I2C_PERIPHERAL_DEV_COUNT)
+
+#if ENV_X86
+
+/* MMIO Ranges */
+/* IO_APIC_ADDR defined in arch/x86 0xfec00000 */
+#define GNB_IO_APIC_ADDR 0xfec01000
+#define SPI_BASE_ADDRESS 0xfec10000
+
+/* FCH AL2AHB Registers */
+#define ALINK_AHB_ADDRESS 0xfedc0000
+
+#define APU_I2C0_BASE 0xfedc2000
+#define APU_I2C1_BASE 0xfedc3000
+#define APU_I2C2_BASE 0xfedc4000
+#define APU_I2C3_BASE 0xfedc5000
+
+#define APU_DMAC0_BASE 0xfedc7000
+#define APU_DMAC1_BASE 0xfedc8000
+#define APU_UART0_BASE 0xfedc9000
+#define APU_UART1_BASE 0xfedca000
+#define APU_DMAC2_BASE 0xfedcc000
+#define APU_DMAC3_BASE 0xfedcd000
+#define APU_UART2_BASE 0xfedce000
+#define APU_UART3_BASE 0xfedcf000
+#define APU_DMAC4_BASE 0xfedd0000
+#define APU_UART4_BASE 0xfedd1000
+
+#define APU_EMMC_BASE 0xfedd5000
+#define APU_EMMC_CONFIG_BASE 0xfedd5800
+
+#endif /* ENV_X86 */
+
+#define FLASH_BASE_ADDR ((0xffffffff - CONFIG_ROM_SIZE) + 1)
+
+/* I/O Ranges */
+#define ACPI_IO_BASE 0x0400
+#define ACPI_PM_EVT_BLK (ACPI_IO_BASE + 0x00)
+#define ACPI_PM1_STS (ACPI_PM_EVT_BLK + 0x00)
+#define ACPI_PM1_EN (ACPI_PM_EVT_BLK + 0x02)
+#define ACPI_PM1_CNT_BLK (ACPI_IO_BASE + 0x04)
+#define ACPI_PM_TMR_BLK (ACPI_IO_BASE + 0x08)
+#define ACPI_CPU_CONTROL (ACPI_IO_BASE + 0x10)
+#define ACPI_GPE0_BLK (ACPI_IO_BASE + 0x20)
+#define ACPI_GPE0_STS (ACPI_GPE0_BLK + 0x00)
+#define ACPI_GPE0_EN (ACPI_GPE0_BLK + 0x04)
+#define SMB_BASE_ADDR 0x0b00
+
+#endif /* AMD_MORGANA_IOMAP_H */
diff --git a/src/soc/amd/morgana/include/soc/lpc.h b/src/soc/amd/morgana/include/soc/lpc.h
new file mode 100644
index 0000000000..ab5f429bee
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/lpc.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_LPC_H
+#define AMD_MORGANA_LPC_H
+
+/* LPC_MISC_CONTROL_BITS at D14F3x078 */
+
+#define LPC_LDRQ0_PU_EN BIT(10)
+#define LPC_LDRQ0_PD_EN BIT(9)
+
+#define SPI_BASE_ADDRESS_REGISTER 0xa0
+#define SPI_BASE_ALIGNMENT BIT(8)
+#define SPI_BASE_RESERVED (BIT(5) | BIT(6) | BIT(7))
+#define PSP_SPI_MMIO_SEL BIT(4)
+#define ROUTE_TPM_2_SPI BIT(3)
+#define SPI_ABORT_ENABLE BIT(2)
+#define SPI_ROM_ENABLE BIT(1)
+#define SPI_ROM_ALT_ENABLE BIT(0)
+#define SPI_PRESERVE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
+
+#endif /* AMD_MORGANA_LPC_H */
diff --git a/src/soc/amd/morgana/include/soc/msr.h b/src/soc/amd/morgana/include/soc/msr.h
new file mode 100644
index 0000000000..0a6a7995d5
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/msr.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_MSR_H
+#define AMD_MORGANA_MSR_H
+
+/* MSRC001_00[6B:64] P-state [7:0] bit definitions */
+#define PSTATE_DEF_HI_ENABLE_SHIFT 31
+#define PSTATE_DEF_HI_ENABLE_MASK (0x1 << PSTATE_DEF_HI_ENABLE_SHIFT)
+#define PSTATE_DEF_LO_CUR_DIV_SHIFT 30
+#define PSTATE_DEF_LO_CUR_DIV_MASK (0x3 << PSTATE_DEF_LO_CUR_DIV_SHIFT)
+#define PSTATE_DEF_LO_CUR_VAL_SHIFT 22
+#define PSTATE_DEF_LO_CUR_VAL_MASK (0xFF << PSTATE_DEF_LO_CUR_VAL_SHIFT)
+#define PSTATE_DEF_LO_CORE_VID_SHIFT 14
+#define PSTATE_DEF_LO_CORE_VID_MASK (0xFF << PSTATE_DEF_LO_CORE_VID_SHIFT)
+#define PSTATE_DEF_LO_FREQ_DIV_SHIFT 8
+#define PSTATE_DEF_LO_FREQ_DIV_MASK (0x3F << PSTATE_DEF_LO_FREQ_DIV_SHIFT)
+#define PSTATE_DEF_LO_FREQ_DIV_MIN 0x8
+#define PSTATE_DEF_LO_EIGHTH_STEP_MAX 0x1A
+#define PSTATE_DEF_LO_FREQ_DIV_MAX 0x3E
+#define PSTATE_DEF_LO_FREQ_MUL_SHIFT 0
+#define PSTATE_DEF_LO_FREQ_MUL_MASK (0xFF << PSTATE_DEF_LO_FREQ_MUL_SHIFT)
+#define PSTATE_DEF_LO_CORE_FREQ_BASE 25
+
+/* Value defined in Serial VID Interface 3.0 spec (#56413, NDA only) */
+#define SERIAL_VID_DECODE_MICROVOLTS 5000
+#define SERIAL_VID_BASE_MICROVOLTS 245000L
+
+#define MSR_CPPC_CAPABILITY_1 0xc00102b0
+#define SHIFT_CPPC_CAPABILITY_1_HIGHEST_PERF 24
+#define SHIFT_CPPC_CAPABILITY_1_NOMINAL_PERF 16
+#define SHIFT_CPPC_CAPABILITY_1_LOW_NON_LIN_PERF 8
+#define SHIFT_CPPC_CAPABILITY_1_LOWEST_PERF 0
+
+#define MSR_CPPC_ENABLE 0xc00102b1
+#define MSR_CPPC_REQUEST 0xc00102b3
+#define SHIFT_CPPC_REQUEST_ENERGY_PERF_PREF 24
+#define SHIFT_CPPC_REQUEST_DES_PERF 16
+#define SHIFT_CPPC_REQUEST_MIN_PERF 8
+#define SHIFT_CPPC_REQUEST_MAX_PERF 0
+
+#define MSR_CPPC_STATUS 0xc00102b4
+
+#define MSR_MAX_PERFORMANCE_FREQUENCY_CLOCK_COUNT 0xe7
+#define MSR_ACTUAL_PERFORMANCE_FREQUENCY_CLOCK_COUNT 0xe8
+
+#endif /* AMD_MORGANA_MSR_H */
diff --git a/src/soc/amd/morgana/include/soc/nvs.h b/src/soc/amd/morgana/include/soc/nvs.h
new file mode 100644
index 0000000000..572c776a89
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/nvs.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Update for Morgana */
+
+/*
+ * NOTE: The layout of the global_nvs structure below must match the layout
+ * in soc/soc/amd/morgana/acpi/globalnvs.asl !!!
+ *
+ */
+
+#ifndef AMD_MORGANA_NVS_H
+#define AMD_MORGANA_NVS_H
+
+#include <stdint.h>
+
+struct __packed global_nvs {
+ /* Miscellaneous */
+ uint8_t unused_was_pcnt; /* 0x00 - Processor Count */
+ uint8_t lids; /* 0x01 - LID State */
+ uint8_t unused_was_pwrs; /* 0x02 - AC Power State */
+ uint32_t cbmc; /* 0x03 - 0x06 - coreboot Memory Console */
+ uint64_t pm1i; /* 0x07 - 0x0e - System Wake Source - PM1 Index */
+ uint64_t gpei; /* 0x0f - 0x16 - GPE Wake Source */
+ uint8_t tmps; /* 0x17 - Temperature Sensor ID */
+ uint8_t tcrt; /* 0x18 - Critical Threshold */
+ uint8_t tpsv; /* 0x19 - Passive Threshold */
+};
+
+#endif /* AMD_MORGANA_NVS_H */
diff --git a/src/soc/amd/morgana/include/soc/pci_devs.h b/src/soc/amd/morgana/include/soc/pci_devs.h
new file mode 100644
index 0000000000..4eb4e113cd
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/pci_devs.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_PCI_DEVS_H
+#define AMD_MORGANA_PCI_DEVS_H
+
+#include <device/pci_def.h>
+#include <amdblocks/pci_devs.h>
+
+/* GNB Root Complex */
+#define GNB_DEV 0x0
+#define GNB_FUNC 0
+#define GNB_DEVFN PCI_DEVFN(GNB_DEV, GNB_FUNC)
+#define SOC_GNB_DEV _SOC_DEV(GNB_DEV, GNB_FUNC)
+
+/* IOMMU */
+#define IOMMU_DEV 0x0
+#define IOMMU_FUNC 2
+#define IOMMU_DEVFN PCI_DEVFN(IOMMU_DEV, IOMMU_FUNC)
+#define SOC_IOMMU_DEV _SOC_DEV(IOMMU_DEV, IOMMU_FUNC)
+
+/* PCIe GFX/GPP Bridge device 1 with no ports */
+#define PCIE_GPP_BRIDGE_1_DEV 0x1
+
+/* PCIe GPP Bridge device 2 with up to 6 ports */
+#define PCIE_GPP_BRIDGE_2_DEV 0x2
+
+#define PCIE_GPP_2_0_FUNC 1
+#define PCIE_GPP_2_0_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_0_FUNC)
+#define SOC_GPP_2_0_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_0_FUNC)
+
+#define PCIE_GPP_2_1_FUNC 2
+#define PCIE_GPP_2_1_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_1_FUNC)
+#define SOC_GPP_2_1_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_1_FUNC)
+
+#define PCIE_GPP_2_2_FUNC 3
+#define PCIE_GPP_2_2_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_2_FUNC)
+#define SOC_GPP_2_2_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_2_FUNC)
+
+#define PCIE_GPP_2_3_FUNC 4
+#define PCIE_GPP_2_3_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_3_FUNC)
+#define SOC_GPP_2_3_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_3_FUNC)
+
+#define PCIE_GPP_2_4_FUNC 5
+#define PCIE_GPP_2_4_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_4_FUNC)
+#define SOC_GPP_2_4_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_4_FUNC)
+
+#define PCIE_GPP_2_5_FUNC 6
+#define PCIE_GPP_2_5_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_5_FUNC)
+#define SOC_GPP_2_5_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_5_FUNC)
+
+/* PCIe Bridges to Bus A, Bus B and Bus C devices */
+#define PCIE_ABC_BRIDGE_DEV 0x8
+
+#define PCIE_ABC_A_FUNC 1
+#define PCIE_ABC_A_DEVFN PCI_DEVFN(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_A_FUNC)
+#define SOC_PCIE_ABC_A_DEV _SOC_DEV(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_A_FUNC)
+
+#define GFX_DEV 0x0
+#define GFX_FUNC 0
+#define GFX_DEVFN PCI_DEVFN(GFX_DEV, GFX_FUNC)
+
+#define GFX_HDA_DEV 0x0
+#define GFX_HDA_FUNC 1
+#define GFX_HDA_DEVFN PCI_DEVFN(GFX_HDA_DEV, GFX_HDA_FUNC)
+
+#define XHCI0_DEV 0x0
+#define XHCI0_FUNC 3
+#define XHCI0_DEVFN PCI_DEVFN(XHCI0_DEV, XHCI0_FUNC)
+
+#define XHCI1_DEV 0x0
+#define XHCI1_FUNC 4
+#define XHCI1_DEVFN PCI_DEVFN(XHCI1_DEV, XHCI1_FUNC)
+
+#define AUDIO_DEV 0x0
+#define AUDIO_FUNC 5
+#define AUDIO_DEVFN PCI_DEVFN(AUDIO_DEV, AUDIO_FUNC)
+
+#define HD_AUDIO_DEV 0x0
+#define HD_AUDIO_FUNC 6
+#define HD_AUDIO_DEVFN PCI_DEVFN(HD_AUDIO_DEV, HD_AUDIO_FUNC)
+
+#define PCIE_ABC_B_FUNC 2
+#define PCIE_GPP_B_DEVFN PCI_DEVFN(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_B_FUNC)
+#define SOC_PCIE_GPP_B_DEV _SOC_DEV(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_B_FUNC)
+
+#define PCIE_ABC_C_FUNC 3
+#define PCIE_GPP_C_DEVFN PCI_DEVFN(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_C_FUNC)
+#define SOC_PCIE_GPP_C_DEV _SOC_DEV(PCIE_ABC_BRIDGE_DEV, PCIE_ABC_C_FUNC)
+
+#define XHCI2_DEV 0x0
+#define XHCI2_FUNC 0
+#define XHCI2_DEVFN PCI_DEVFN(XHCI2_DEV, XHCI2_FUNC)
+
+/* SMBUS */
+#define SMBUS_DEV 0x14
+#define SMBUS_FUNC 0
+#define SMBUS_DEVFN PCI_DEVFN(SMBUS_DEV, SMBUS_FUNC)
+#define SOC_SMBUS_DEV _SOC_DEV(SMBUS_DEV, SMBUS_FUNC)
+
+/* LPC BUS */
+#define PCU_DEV 0x14
+#define LPC_FUNC 3
+#define LPC_DEVFN PCI_DEVFN(PCU_DEV, LPC_FUNC)
+#define SOC_LPC_DEV _SOC_DEV(PCU_DEV, LPC_FUNC)
+
+/* Data Fabric functions */
+#define DF_DEV 0x18
+
+#define DF_F0_DEVFN PCI_DEVFN(DF_DEV, 0)
+#define SOC_DF_F0_DEV _SOC_DEV(DF_DEV, 0)
+
+#define DF_F1_DEVFN PCI_DEVFN(DF_DEV, 1)
+#define SOC_DF_F1_DEV _SOC_DEV(DF_DEV, 1)
+
+#define DF_F2_DEVFN PCI_DEVFN(DF_DEV, 2)
+#define SOC_DF_F2_DEV _SOC_DEV(DF_DEV, 2)
+
+#define DF_F3_DEVFN PCI_DEVFN(DF_DEV, 3)
+#define SOC_DF_F3_DEV _SOC_DEV(DF_DEV, 3)
+
+#define DF_F4_DEVFN PCI_DEVFN(DF_DEV, 4)
+#define SOC_DF_F4_DEV _SOC_DEV(DF_DEV, 4)
+
+#define DF_F5_DEVFN PCI_DEVFN(DF_DEV, 5)
+#define SOC_DF_F5_DEV _SOC_DEV(DF_DEV, 5)
+
+#define DF_F6_DEVFN PCI_DEVFN(DF_DEV, 6)
+#define SOC_DF_F6_DEV _SOC_DEV(DF_DEV, 6)
+
+#define DF_F7_DEVFN PCI_DEVFN(DF_DEV, 7)
+#define SOC_DF_F7_DEV _SOC_DEV(DF_DEV, 7)
+
+#endif /* AMD_MORGANA_PCI_DEVS_H */
diff --git a/src/soc/amd/morgana/include/soc/platform_descriptors.h b/src/soc/amd/morgana/include/soc/platform_descriptors.h
new file mode 100644
index 0000000000..d6ece12087
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/platform_descriptors.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_PLATFORM_DESCRIPTORS_H
+#define AMD_MORGANA_PLATFORM_DESCRIPTORS_H
+
+#include <types.h>
+#include <platform_descriptors.h>
+#include <FspmUpd.h>
+
+/* Mainboard callback to obtain DXI/PCIe and DDI descriptors. */
+void mainboard_get_dxio_ddi_descriptors(
+ const fsp_dxio_descriptor **dxio_descs, size_t *dxio_num,
+ const fsp_ddi_descriptor **ddi_descs, size_t *ddi_num);
+
+void mb_pre_fspm(FSP_M_CONFIG *mcfg);
+
+#endif /* AMD_MORGANA_PLATFORM_DESCRIPTORS_H */
diff --git a/src/soc/amd/morgana/include/soc/psp_transfer.h b/src/soc/amd/morgana/include/soc/psp_transfer.h
new file mode 100644
index 0000000000..20b1cc82c6
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/psp_transfer.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_PSP_TRANSFER_H
+#define AMD_MORGANA_PSP_TRANSFER_H
+
+# if (CONFIG_CMOS_RECOVERY_BYTE != 0)
+# define CMOS_RECOVERY_BYTE CONFIG_CMOS_RECOVERY_BYTE
+# elif CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK)
+# error "Must set CONFIG_CMOS_RECOVERY_BYTE"
+# endif
+
+#define CMOS_RECOVERY_MAGIC_VAL 0x96
+
+#define TRANSFER_INFO_SIZE 64
+#define TIMESTAMP_BUFFER_SIZE 0x200
+
+#define TRANSFER_MAGIC_VAL 0x50544953
+
+/* Bit definitions for the psp_info field in the PSP transfer_info_struct */
+#define PSP_INFO_PRODUCTION_MODE 0x00000001UL
+#define PSP_INFO_PRODUCTION_SILICON 0x00000002UL
+#define PSP_INFO_VALID 0x80000000UL
+
+/* Area for things that would cause errors in a linker script */
+#if !defined(__ASSEMBLER__)
+#include <stdint.h>
+
+struct transfer_info_struct {
+ uint32_t magic_val; /* Identifier */
+ uint32_t struct_bytes; /* Size of this structure */
+ uint32_t buffer_size; /* Size of the transfer buffer area */
+
+ /* Offsets from start of transfer buffer */
+ uint32_t workbuf_offset;
+ uint32_t console_offset;
+ uint32_t timestamp_offset;
+ uint32_t fmap_offset;
+
+ uint32_t unused1[5];
+
+ /* Fields reserved for the PSP */
+ uint64_t timestamp; /* Offset 0x30 */
+ uint32_t psp_unused; /* Offset 0x38 */
+ uint32_t psp_info; /* Offset 0x3C */
+};
+
+_Static_assert(sizeof(struct transfer_info_struct) == TRANSFER_INFO_SIZE,
+ "TRANSFER_INFO_SIZE is incorrect");
+
+/* Make sure the PSP transferred information over to x86 side. */
+int transfer_buffer_valid(const struct transfer_info_struct *ptr);
+/* Verify vboot work buffer is valid in transfer buffer */
+void verify_psp_transfer_buf(void);
+/* Display the transfer block's PSP_info data */
+void show_psp_transfer_info(void);
+/* Replays the pre-x86 cbmem console into the x86 cbmem console */
+void replay_transfer_buffer_cbmemc(void);
+/* Called by bootblock_c_entry in the VBOOT_STARTS_BEFORE_BOOTBLOCK case */
+void boot_with_psp_timestamp(uint64_t base_timestamp);
+
+#endif
+#endif /* AMD_MORGANA_PSP_TRANSFER_H */
diff --git a/src/soc/amd/morgana/include/soc/psp_verstage_addr.h b/src/soc/amd/morgana/include/soc/psp_verstage_addr.h
new file mode 100644
index 0000000000..e99c525131
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/psp_verstage_addr.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_PSP_VERSTAGE_ADDR_H
+#define AMD_MORGANA_PSP_VERSTAGE_ADDR_H
+
+/*
+ * Start of available space is 0x0 and this is where the
+ * header for the user app (verstage) must be mapped.
+ * Size is 208KB
+ */
+#define PSP_SRAM_START 0x0
+#define PSP_SRAM_SIZE (208K)
+#define VERSTAGE_START PSP_SRAM_START
+
+/*
+ * The top of the stack must be 4k aligned, so set the bottom as 4k aligned
+ * and make the size a multiple of 4k
+ */
+
+#define PSP_VERSTAGE_STACK_START 0x2a000
+#define PSP_VERSTAGE_STACK_SIZE (40K)
+
+#endif /* AMD_MORGANA_PSP_VERSTAGE_ADDR_H */
diff --git a/src/soc/amd/morgana/include/soc/smi.h b/src/soc/amd/morgana/include/soc/smi.h
new file mode 100644
index 0000000000..b622ee6067
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/smi.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_SMI_H
+#define AMD_MORGANA_SMI_H
+
+#include <types.h>
+
+#define SMI_GEVENTS 24
+#define SCIMAPS 64 /* 0..63 */
+#define SCI_GPES 32
+#define NUMBER_SMITYPES 160
+
+#define SMI_EVENT_STATUS 0x0
+#define SMI_EVENT_ENABLE 0x04
+#define SMI_SCI_TRIG 0x08
+#define SMI_SCI_LEVEL 0x0c
+#define SMI_SCI_STATUS 0x10
+#define SMI_SCI_EN 0x14
+#define SMI_SCI_MAP0 0x40
+# define SMI_SCI_MAP(X) (SMI_SCI_MAP0 + (X))
+
+/* SMI source and status */
+#define SMITYPE_G_GENINT1_L 0
+#define SMITYPE_G_GENINT2_L 1
+#define SMITYPE_G_AGPIO3 2
+#define SMITYPE_G_ESPI_ALERT_L 3
+#define SMITYPE_G_AGPIO4 4
+#define SMITYPE_G_BLINK 5
+#define SMITYPE_G_SPKR 6
+#define SMITYPE_G_AGPIO5 7
+#define SMITYPE_G_WAKE_L 8
+#define SMITYPE_G_SPI_TPM_CS_L 9
+#define SMITYPE_G_AGPIO6 10
+#define SMITYPE_G_AGPIO7 11
+#define SMITYPE_G_USBOC0_L 12
+#define SMITYPE_G_USBOC1_L 13
+#define SMITYPE_G_USBOC2_L 14
+#define SMITYPE_G_USBOC3_L 15
+#define SMITYPE_G_AGPIO23 16
+#define SMITYPE_G_AGPIO32 17
+#define SMITYPE_G_FANIN0 18
+#define SMITYPE_G_SYSRESET_L 19
+#define SMITYPE_G_AGPIO40 20
+#define SMITYPE_G_PWR_BTN_L 21
+#define SMITYPE_G_AGPIO9 22
+#define SMITYPE_G_AGPIO8 23
+#define GEVENT_MASK ((1 << SMITYPE_G_GENINT1_L) \
+ | (1 << SMITYPE_G_GENINT2_L) \
+ | (1 << SMITYPE_G_AGPIO3) \
+ | (1 << SMITYPE_G_ESPI_ALERT_L) \
+ | (1 << SMITYPE_G_AGPIO4) \
+ | (1 << SMITYPE_G_BLINK) \
+ | (1 << SMITYPE_G_SPKR) \
+ | (1 << SMITYPE_G_AGPIO5) \
+ | (1 << SMITYPE_G_WAKE_L) \
+ | (1 << SMITYPE_G_SPI_TPM_CS_L) \
+ | (1 << SMITYPE_G_AGPIO6) \
+ | (1 << SMITYPE_G_AGPIO7) \
+ | (1 << SMITYPE_G_USBOC0_L) \
+ | (1 << SMITYPE_G_USBOC1_L) \
+ | (1 << SMITYPE_G_USBOC2_L) \
+ | (1 << SMITYPE_G_USBOC3_L) \
+ | (1 << SMITYPE_G_AGPIO23) \
+ | (1 << SMITYPE_G_AGPIO32) \
+ | (1 << SMITYPE_G_FANIN0) \
+ | (1 << SMITYPE_G_SYSRESET_L) \
+ | (1 << SMITYPE_G_AGPIO40) \
+ | (1 << SMITYPE_G_PWR_BTN_L) \
+ | (1 << SMITYPE_G_AGPIO9) \
+ | (1 << SMITYPE_G_AGPIO8))
+#define SMITYPE_MP2_WAKE 24
+#define SMITYPE_MP2_GPIO0 25
+#define SMITYPE_ESPI_SYS 26
+#define SMITYPE_ESPI_WAKE_PME 27
+#define SMITYPE_MP2_GPIO1 28
+#define SMITYPE_GPP_PME 29
+#define SMITYPE_NB_GPP_HOT_PLUG 30
+/* 31 Reserved */
+#define SMITYPE_WAKE_L2 32
+#define SMITYPE_PSP 33
+/* 34,35 Reserved */
+#define SMITYPE_ESPI_SCI_B 36
+#define SMITYPE_CIO_FCH_PME_S5_0 37
+#define SMITYPE_CIO_FCH_PME_S5_1 38
+#define SMITYPE_AZPME 39
+#define SMITYPE_USB_PD_I2C4 40
+#define SMITYPE_GPIO_CTL 41
+#define SMITYPE_XHC2_PME 42
+#define SMITYPE_ALT_HPET_ALARM 43
+#define SMITYPE_FAN_THERMAL 44
+#define SMITYPE_ASF_MASTER_SLAVE 45
+#define SMITYPE_I2S_WAKE 46
+#define SMITYPE_SMBUS0_MASTER 47
+#define SMITYPE_TWARN 48
+#define SMITYPE_TRAFFIC_MON 49
+#define SMITYPE_ILLB 50
+#define SMITYPE_PWRBUTTON_UP 51
+#define SMITYPE_PROCHOT 52
+#define SMITYPE_APU_HW 53
+#define SMITYPE_NB_SCI 54
+#define SMITYPE_RAS_SERR 55
+#define SMITYPE_XHC0_PME 56
+#define SMITYPE_XHC1_PME 57
+#define SMITYPE_ACDC_TIMER 58
+/* 59-60 Reserved */
+#define SMITYPE_XHC3_PME 61
+#define SMITYPE_XHC4_PME 62
+#define SMITYPE_CUR_TEMP_STATUS_5 63
+#define SMITYPE_KB_RESET 64
+#define SMITYPE_SLP_TYP 65
+#define SMITYPE_AL2H_ACPI 66
+/* 67 Reserved */
+#define SMITYPE_NB_GPP_PME_PULSE 68
+#define SMITYPE_NB_GPP_HP_PULSE 69
+#define SMITYPE_USB_PD_I2C4_INTR2 70
+/* 71 Reserved */
+#define SMITYPE_GBL_RLS 72
+#define SMITYPE_BIOS_RLS 73
+#define SMITYPE_PWRBUTTON_DOWN 74
+#define SMITYPE_SMI_CMD_PORT 75
+#define SMITYPE_USB_SMI 76
+#define SMITYPE_SERIRQ 77
+#define SMITYPE_SMBUS0_INTR 78
+/* 79-80 Reserved */
+#define SMITYPE_INTRUDER 81
+#define SMITYPE_VBAT_LOW 82
+#define SMITYPE_PROTHOT 83
+#define SMITYPE_PCI_SERR 84
+/* 85-89 Reserved */
+#define SMITYPE_EMUL60_64 90
+/* 91-132 Reserved */
+#define SMITYPE_FANIN0 133
+/* 134-140 Reserved */
+#define SMITYPE_CF9_WRITE 141
+#define SMITYPE_SHORT_TIMER 142
+#define SMITYPE_LONG_TIMER 143
+#define SMITYPE_AB_SMI 144
+#define SMITYPE_ANY_RESET 145
+#define SMITYPE_ESPI_SMI 146
+/* 147 Reserved */
+#define SMITYPE_IOTRAP0 148
+#define SMITYPE_IOTRAP1 149
+#define SMITYPE_IOTRAP2 150
+#define SMITYPE_IOTRAP3 151
+#define SMITYPE_MEMTRAP0 152
+/* 153-155 Reserved */
+#define SMITYPE_CFGTRAP0 156
+/* 157-159 Reserved */
+
+#define TYPE_TO_MASK(X) (1 << (X) % 32)
+
+#define SMI_REG_SMISTS0 0x80
+#define SMI_REG_SMISTS1 0x84
+#define SMI_REG_SMISTS2 0x88
+#define SMI_REG_SMISTS3 0x8c
+#define SMI_REG_SMISTS4 0x90
+
+#define SMI_REG_POINTER 0x94
+# define SMI_STATUS_SRC_SCI (1 << 0)
+# define SMI_STATUS_SRC_0 (1 << 1) /* SMIx80 */
+# define SMI_STATUS_SRC_1 (1 << 2) /* SMIx84... */
+# define SMI_STATUS_SRC_2 (1 << 3)
+# define SMI_STATUS_SRC_3 (1 << 4)
+# define SMI_STATUS_SRC_4 (1 << 5)
+
+#define SMI_TIMER 0x96
+#define SMI_TIMER_MASK 0x7fff
+#define SMI_TIMER_EN (1 << 15)
+
+#define SMI_REG_SMITRIG0 0x98
+# define SMITRIG0_PSP (1 << 25)
+# define SMITRG0_EOS (1 << 28)
+# define SMI_TIMER_SEL (1 << 29)
+# define SMITRG0_SMIENB (1 << 31)
+
+#define SMI_REG_CONTROL0 0xa0
+#define SMI_REG_CONTROL1 0xa4
+#define SMI_REG_CONTROL2 0xa8
+#define SMI_REG_CONTROL3 0xac
+#define SMI_REG_CONTROL4 0xb0
+#define SMI_REG_CONTROL5 0xb4
+#define SMI_REG_CONTROL6 0xb8
+#define SMI_REG_CONTROL7 0xbc
+#define SMI_REG_CONTROL8 0xc0
+#define SMI_REG_CONTROL9 0xc4
+
+#define SMI_MODE_MASK 0x03
+
+#endif /* AMD_MORGANA_SMI_H */
diff --git a/src/soc/amd/morgana/include/soc/smu.h b/src/soc/amd/morgana/include/soc/smu.h
new file mode 100644
index 0000000000..308a861771
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/smu.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_SMU_H
+#define AMD_MORGANA_SMU_H
+
+/* SMU mailbox register offsets in SMN */
+#define SMN_SMU_MESG_ID 0x3b10528
+#define SMN_SMU_MESG_RESP 0x3b10578
+#define SMN_SMU_MESG_ARGS_BASE 0x3b10998
+
+#define SMU_NUM_ARGS 6
+
+enum smu_message_id {
+ SMC_MSG_S3ENTRY = 0x0b,
+};
+
+/*
+ * Request the SMU put system into S3, S4, or S5. On entry, SlpTyp determines S-State and
+ * SlpTypeEn gets set by the SMU. Function does not return if successful.
+ */
+void smu_sx_entry(void);
+
+#endif /* AMD_MORGANA_SMU_H */
diff --git a/src/soc/amd/morgana/include/soc/southbridge.h b/src/soc/amd/morgana/include/soc/southbridge.h
new file mode 100644
index 0000000000..75f0beb72f
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/southbridge.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_SOUTHBRIDGE_H
+#define AMD_MORGANA_SOUTHBRIDGE_H
+
+#include <soc/iomap.h>
+
+/* Power management registers: 0xfed80300 or index/data at IO 0xcd6/cd7 */
+#define PM_ISACONTROL 0x04
+#define ABCLKGATEEN BIT(16)
+#define PM_PCI_CTRL 0x08
+#define FORCE_SLPSTATE_RETRY BIT(25)
+#define PWR_RESET_CFG 0x10
+#define TOGGLE_ALL_PWR_GOOD (1 << 1)
+#define PM_SERIRQ_CONF 0x54
+#define PM_SERIRQ_NUM_BITS_17 0x0000
+#define PM_SERIRQ_NUM_BITS_18 0x0004
+#define PM_SERIRQ_NUM_BITS_19 0x0008
+#define PM_SERIRQ_NUM_BITS_20 0x000c
+#define PM_SERIRQ_NUM_BITS_21 0x0010
+#define PM_SERIRQ_NUM_BITS_22 0x0014
+#define PM_SERIRQ_NUM_BITS_23 0x0018
+#define PM_SERIRQ_NUM_BITS_24 0x001c
+#define PM_SERIRQ_MODE BIT(6)
+#define PM_SERIRQ_ENABLE BIT(7)
+#define PM_EVT_BLK 0x60
+#define WAK_STS BIT(15) /*AcpiPmEvtBlkx00 Pm1Status */
+#define PCIEXPWAK_STS BIT(14)
+#define RTC_STS BIT(10)
+#define PWRBTN_STS BIT(8)
+#define GBL_STS BIT(5)
+#define BM_STS BIT(4)
+#define TIMER_STS BIT(0)
+#define PCIEXPWAK_DIS BIT(14) /*AcpiPmEvtBlkx02 Pm1Enable */
+#define RTC_EN BIT(10)
+#define PWRBTN_EN BIT(8)
+#define GBL_EN BIT(5)
+#define TIMER_STS BIT(0)
+#define PM1_CNT_BLK 0x62
+#define PM_TMR_BLK 0x64
+#define PM_GPE0_BLK 0x68
+#define PM_ACPI_SMI_CMD 0x6a
+#define PM_ACPI_CONF 0x74
+#define PM_ACPI_DECODE_STD BIT(0)
+#define PM_ACPI_GLOBAL_EN BIT(1)
+#define PM_ACPI_RTC_EN_EN BIT(2)
+#define PM_ACPI_SLPBTN_EN_EN BIT(3)
+#define PM_ACPI_TIMER_EN_EN BIT(4)
+#define PM_ACPI_MASK_ARB_DIS BIT(6)
+#define PM_ACPI_BIOS_RLS BIT(7)
+#define PM_ACPI_PWRBTNEN_EN BIT(8)
+#define PM_ACPI_REDUCED_HW_EN BIT(9)
+#define PM_ACPI_S5_LPC_PIN_MODE_SEL BIT(10)
+#define PM_ACPI_S5_LPC_PIN_MODE BIT(11)
+#define PM_ACPI_LPC_RST_DIS BIT(12)
+#define PM_ACPI_SEL_PWRGD_PAD BIT(13)
+#define PM_ACPI_SEL_SMU_THERMTRIP BIT(14)
+#define PM_ACPI_SW_S5PWRMUX_OVRD_N BIT(15)
+#define PM_ACPI_SW_S5PWRMUX BIT(16)
+#define PM_ACPI_EN_SHUTDOWN_MSG BIT(17)
+#define PM_ACPI_EN_SYNC_FLOOD BIT(18)
+#define PM_ACPI_FORCE_SPIUSEPIN_0 BIT(19)
+#define PM_ACPI_EN_DF_INTRWAKE BIT(20)
+#define PM_ACPI_MASK_USB_S5_RST BIT(21)
+#define PM_ACPI_USE_RSMU_RESET BIT(22)
+#define PM_ACPI_RST_USB_S5 BIT(23)
+#define PM_ACPI_BLOCK_PCIE_PME BIT(24)
+#define PM_ACPI_PCIE_WAK_MASK BIT(25)
+#define PM_ACPI_PCIE_WAK_INTR_DIS BIT(26)
+#define PM_ACPI_WAKE_AS_GEVENT BIT(27)
+#define PM_ACPI_NB_PME_GEVENT BIT(28)
+#define PM_ACPI_RTC_WAKE_EN BIT(29)
+#define PM_ACPI_USE_GATED_ALINK_CLK BIT(30)
+#define PM_ACPI_DELAY_GPP_OFF_TIME BIT(31)
+#define PM_SPI_PAD_PU_PD 0x90
+#define PM_LPC_GATING 0xec
+#define PM_LPC_AB_NO_BYPASS_EN BIT(2)
+#define PM_LPC_A20_EN BIT(1)
+#define PM_LPC_ENABLE BIT(0)
+
+#define PM1_LIMIT 16
+#define GPE0_LIMIT 32
+#define TOTAL_BITS(a) (8 * sizeof(a))
+
+#define FCH_LEGACY_UART_DECODE (ALINK_AHB_ADDRESS + 0x20) /* 0xfedc0020 */
+
+/* FCH MISC Registers 0xfed80e00 */
+#define GPP_CLK_CNTRL 0x00
+#define GPP_CLK0_REQ_SHIFT 0
+#define GPP_CLK1_REQ_SHIFT 2
+#define GPP_CLK4_REQ_SHIFT 4
+#define GPP_CLK2_REQ_SHIFT 6
+#define GPP_CLK3_REQ_SHIFT 8
+#define GPP_CLK5_REQ_SHIFT 10
+#define GPP_CLK6_REQ_SHIFT 12
+#define GPP_CLK_OUTPUT_COUNT 7
+#define GPP_CLK_OUTPUT_AVAILABLE 4
+#define GPP_CLK_REQ_MASK(clk_shift) (0x3 << (clk_shift))
+#define GPP_CLK_REQ_ON(clk_shift) (0x3 << (clk_shift))
+#define GPP_CLK_REQ_EXT(clk_shift) (0x1 << (clk_shift))
+#define GPP_CLK_REQ_OFF(clk_shift) (0x0 << (clk_shift))
+
+#define MISC_CLKGATEDCNTL 0x2c
+#define ALINKCLK_GATEOFFEN BIT(16)
+#define BLINKCLK_GATEOFFEN BIT(17)
+#define XTAL_PAD_S0I3_TURNOFF_EN BIT(19)
+#define XTAL_PAD_S3_TURNOFF_EN BIT(20)
+#define XTAL_PAD_S5_TURNOFF_EN BIT(21)
+#define MISC_CGPLL_CONFIGURATION0 0x30
+#define USB_PHY_CMCLK_S3_DIS BIT(8)
+#define USB_PHY_CMCLK_S0I3_DIS BIT(9)
+#define USB_PHY_CMCLK_S5_DIS BIT(10)
+#define MISC_CLK_CNTL0 0x40 /* named MISC_CLK_CNTL1 on Picasso */
+#define BP_X48M0_S0I3_DIS BIT(4)
+#define BP_X48M0_OUTPUT_EN BIT(2) /* 1=En, unlike Hudson, Kern */
+
+void fch_pre_init(void);
+void fch_early_init(void);
+void fch_init(void *chip_info);
+void fch_final(void *chip_info);
+
+void enable_aoac_devices(void);
+void wait_for_aoac_enabled(unsigned int dev);
+
+#endif /* AMD_MORGANA_SOUTHBRIDGE_H */
diff --git a/src/soc/amd/morgana/include/soc/uart.h b/src/soc/amd/morgana/include/soc/uart.h
new file mode 100644
index 0000000000..45e0ed9560
--- /dev/null
+++ b/src/soc/amd/morgana/include/soc/uart.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#ifndef AMD_MORGANA_UART_H
+#define AMD_MORGANA_UART_H
+
+#include <types.h>
+
+void set_uart_config(unsigned int idx); /* configure hardware of FCH UART selected by idx */
+void clear_uart_legacy_config(void); /* disable legacy I/O decode for FCH UART */
+
+#endif /* AMD_MORGANA_UART_H */
diff --git a/src/soc/amd/morgana/mca.c b/src/soc/amd/morgana/mca.c
new file mode 100644
index 0000000000..c104a33b23
--- /dev/null
+++ b/src/soc/amd/morgana/mca.c
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/mca.h>
+#include <cpu/x86/msr.h>
+#include <types.h>
+
+static const char *const mca_bank_name[] = {
+ [0] = "Load-store unit",
+ [1] = "Instruction fetch unit",
+ [2] = "L2 cache unit",
+ [3] = "Decode unit",
+ [4] = "",
+ [5] = "Execution unit",
+ [6] = "Floating point unit",
+ [7] = "L3 cache unit",
+ [8] = "L3 cache unit",
+ [9] = "L3 cache unit",
+ [10] = "L3 cache unit",
+ [11] = "UMC",
+ [12] = "UMC",
+ [13] = "CS",
+ [14] = "CS",
+ [15] = "NBIO",
+ [16] = "PIE",
+};
+
+bool mca_has_expected_bank_count(void)
+{
+ return ARRAY_SIZE(mca_bank_name) == mca_get_bank_count();
+}
+
+bool mca_is_valid_bank(unsigned int bank)
+{
+ return (bank < ARRAY_SIZE(mca_bank_name) && mca_bank_name[bank] != NULL);
+}
+
+const char *mca_get_bank_name(unsigned int bank)
+{
+ if (mca_is_valid_bank(bank))
+ return mca_bank_name[bank];
+ else
+ return "";
+}
diff --git a/src/soc/amd/morgana/preload.c b/src/soc/amd/morgana/preload.c
new file mode 100644
index 0000000000..47f3580714
--- /dev/null
+++ b/src/soc/amd/morgana/preload.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Move to common? */
+
+#include <bootstate.h>
+#include <fsp/api.h>
+
+static void start_fsps_preload(void *unused)
+{
+ preload_fsps();
+}
+
+BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, start_fsps_preload, NULL);
diff --git a/src/soc/amd/morgana/psp_verstage/Makefile.inc b/src/soc/amd/morgana/psp_verstage/Makefile.inc
new file mode 100644
index 0000000000..8d1e5e4aa0
--- /dev/null
+++ b/src/soc/amd/morgana/psp_verstage/Makefile.inc
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+ifeq $($(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK),y)
+
+subdirs-y += ../../common/psp_verstage
+
+verstage-generic-ccopts += -I$(src)/soc/amd/morgana/psp_verstage/include
+verstage-generic-ccopts += -I$(src)/soc/amd/common/psp_verstage/include
+verstage-generic-ccopts += -Isrc/vendorcode/amd/fsp/morgana/include
+verstage-generic-ccopts += -Isrc/vendorcode/amd/fsp/common/include
+
+verstage-y += svc.c
+verstage-y += chipset.c
+verstage-y += uart.c
+
+verstage-y +=$(top)/src/vendorcode/amd/fsp/common/bl_uapp/bl_uapp_startup.S
+verstage-y += $(top)/src/vendorcode/amd/fsp/common/bl_uapp/bl_uapp_end.S
+
+endif
diff --git a/src/soc/amd/morgana/psp_verstage/chipset.c b/src/soc/amd/morgana/psp_verstage/chipset.c
new file mode 100644
index 0000000000..539ddb4405
--- /dev/null
+++ b/src/soc/amd/morgana/psp_verstage/chipset.c
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <bl_uapp/bl_syscall_public.h>
+#include <cbfs.h>
+#include <console/console.h>
+#include <psp_verstage.h>
+
+/*
+ * We can't pass pointer to hash table in the SPI.
+ * The AMD PSP team specifically required that whole hash table
+ * should be copied into memory before passing them to the PSP
+ * to reduce window of TOCTOU.
+ */
+#define MAX_NUM_HASH_ENTRIES 128
+static struct psp_fw_hash_table hash_table;
+static struct psp_fw_entry_hash_256 hash_256[MAX_NUM_HASH_ENTRIES];
+static struct psp_fw_entry_hash_384 hash_384[MAX_NUM_HASH_ENTRIES];
+
+void update_psp_fw_hash_table(const char *fname)
+{
+ uint8_t *spi_ptr = (uint8_t *)cbfs_map(fname, NULL);
+ uint32_t len;
+
+ if (!spi_ptr) {
+ printk(BIOS_ERR, "Error: AMD Firmware hash table %s not found\n", fname);
+ /*
+ * If we don't supply hash table, the PSP will refuse to boot.
+ * So returning here is safe to do.
+ */
+ return;
+ }
+
+ memcpy(&hash_table, spi_ptr, offsetof(struct psp_fw_hash_table, fw_hash_256));
+
+ if (hash_table.no_of_entries_256 > MAX_NUM_HASH_ENTRIES ||
+ hash_table.no_of_entries_384 > MAX_NUM_HASH_ENTRIES) {
+ printk(BIOS_ERR, "Error: Too many entries in AMD Firmware hash table"
+ " (SHA256:%d, SHA384:%d)\n",
+ hash_table.no_of_entries_256, hash_table.no_of_entries_384);
+ return;
+ }
+
+ if (hash_table.no_of_entries_256 == 0 &&
+ hash_table.no_of_entries_384 == 0) {
+ printk(BIOS_ERR, "Error: No entries in AMD Firmware hash table"
+ " (SHA256:%d, SHA384:%d)\n",
+ hash_table.no_of_entries_256, hash_table.no_of_entries_384);
+ return;
+ }
+
+ spi_ptr += offsetof(struct psp_fw_hash_table, fw_hash_256);
+
+ hash_table.fw_hash_256 = hash_256;
+ hash_table.fw_hash_384 = hash_384;
+ len = sizeof(struct psp_fw_entry_hash_256) * hash_table.no_of_entries_256;
+ memcpy(hash_256, spi_ptr, len);
+
+ spi_ptr += len;
+ len = sizeof(struct psp_fw_entry_hash_384) * hash_table.no_of_entries_384;
+ memcpy(hash_384, spi_ptr, len);
+
+ svc_set_fw_hash_table(&hash_table);
+}
+
+uint32_t update_psp_bios_dir(uint32_t *psp_dir_offset, uint32_t *bios_dir_offset)
+{
+ return svc_update_psp_bios_dir(psp_dir_offset, bios_dir_offset);
+}
+
+uint32_t save_uapp_data(void *address, uint32_t size)
+{
+ return svc_save_uapp_data(address, size);
+}
+
+uint32_t get_bios_dir_addr(struct embedded_firmware *ef_table)
+{
+ return 0;
+}
+
+int platform_set_sha_op(enum vb2_hash_algorithm hash_alg,
+ struct sha_generic_data *sha_op)
+{
+ if (hash_alg == VB2_HASH_SHA256) {
+ sha_op->SHAType = SHA_TYPE_256;
+ sha_op->DigestLen = 32;
+ } else if (hash_alg == VB2_HASH_SHA384) {
+ sha_op->SHAType = SHA_TYPE_384;
+ sha_op->DigestLen = 48;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Functions below are stub functions for not-yet-implemented PSP features.
+ * These functions should be replaced with proper implementations later.
+ */
+
+uint32_t svc_write_postcode(uint32_t postcode)
+{
+ return 0;
+}
+
+void platform_report_mode(int developer_mode_enabled)
+{
+ printk(BIOS_INFO, "Reporting %s mode\n",
+ developer_mode_enabled ? "Developer" : "Normal");
+ if (developer_mode_enabled)
+ svc_set_platform_boot_mode(CHROME_BOOK_BOOT_MODE_DEVELOPER);
+ else
+ svc_set_platform_boot_mode(CHROME_BOOK_BOOT_MODE_NORMAL);
+}
diff --git a/src/soc/amd/morgana/psp_verstage/svc.c b/src/soc/amd/morgana/psp_verstage/svc.c
new file mode 100644
index 0000000000..2fc29aae65
--- /dev/null
+++ b/src/soc/amd/morgana/psp_verstage/svc.c
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include "svc.h"
+
+#include <assert.h>
+#include <bl_uapp/bl_syscall_public.h>
+#include <psp_verstage.h>
+#include <stddef.h>
+#include <string.h>
+
+void svc_exit(uint32_t status)
+{
+ uint32_t unused = 0;
+ SVC_CALL0(SVC_EXIT, unused);
+}
+
+void svc_debug_print(const char *string)
+{
+ uint32_t unused = 0;
+ struct cmd_param_debug param = {
+ .debug_buffer = (char *)string,
+ .debug_buffer_len = strlen(string),
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_DEBUG_PRINT, (void *)&param, unused);
+}
+
+void svc_debug_print_ex(uint32_t dword0,
+ uint32_t dword1, uint32_t dword2, uint32_t dword3)
+{
+ uint32_t unused = 0;
+ struct cmd_param_debug_ex param = {
+ .word0 = dword0,
+ .word1 = dword1,
+ .word2 = dword2,
+ .word3 = dword3,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_DEBUG_PRINT_EX, (void *)&param, unused);
+}
+
+uint32_t svc_get_boot_mode(uint32_t *boot_mode)
+{
+ uint32_t retval = 0;
+ struct cmd_param_get_boot_mode param = {
+ .ptr_boot_mode = boot_mode,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_GET_BOOT_MODE, (void *)&param, retval);
+ return retval;
+}
+
+void svc_delay_in_usec(uint32_t delay)
+{
+ uint32_t unused = 0;
+ struct cmd_param_delay_in_micro_second param = {
+ .delay = delay,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_DELAY_IN_MICRO_SECONDS, (void *)&param, unused);
+}
+
+uint32_t svc_get_spi_rom_info(struct spirom_info *spi_rom_info)
+{
+ uint32_t retval = 0;
+ struct cmd_param_spirom_info param = {
+ .ptr_spirom_info = spi_rom_info,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_GET_SPI_INFO, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_map_fch_dev(enum fch_io_device io_device,
+ uint32_t arg1, uint32_t arg2, void **io_device_axi_addr)
+{
+ uint32_t retval = 0;
+ struct cmd_param_map_fch_io_device param = {
+ .io_device = io_device,
+ .arg1 = arg1,
+ .arg2 = arg2,
+ .pptr_io_device_addr_axi = io_device_axi_addr,
+ };
+ assert(io_device < FCH_IO_DEVICE_END);
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_MAP_FCH_IO_DEVICE, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_unmap_fch_dev(enum fch_io_device io_device, void *io_device_axi_addr)
+{
+ uint32_t retval = 0;
+ struct cmd_param_unmap_fch_io_device param = {
+ .io_device = io_device,
+ .ptr_io_device_addr_axi = io_device_axi_addr,
+ };
+ assert(io_device < FCH_IO_DEVICE_END);
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_UNMAP_FCH_IO_DEVICE, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_map_spi_rom(void *spi_rom_addr,
+ uint32_t size, void **spi_rom_axi_addr)
+{
+ uint32_t retval = 0;
+ struct cmd_param_map_spirom param = {
+ .spirom_addr = (uintptr_t)spi_rom_addr,
+ .size = size,
+ .ppspirom_addr_axi = spi_rom_axi_addr,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_MAP_SPIROM_DEVICE, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_unmap_spi_rom(void *spi_rom_addr)
+{
+ uint32_t retval = 0;
+ struct cmd_param_unmap_spirom param = {
+ .ptr_spirom_addr_axi = spi_rom_addr,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_UNMAP_SPIROM_DEVICE, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_update_psp_bios_dir(uint32_t *psp_dir_offset,
+ uint32_t *bios_dir_offset)
+{
+ uint32_t retval = 0;
+ struct cmd_param_psp_update param = {
+ .ptr_psp_dir_addr = psp_dir_offset,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_UPDATE_PSP_BIOS_DIR, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_save_uapp_data(void *address, uint32_t size)
+{
+ uint32_t retval = 0;
+ struct cmd_param_copy_data_from_uapp param = {
+ .address = (uintptr_t)address,
+ .size = size,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_COPY_DATA_FROM_UAPP, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_read_timer_val(enum psp_timer_type type, uint64_t *counter_value)
+{
+ unsigned int retval = 0;
+ struct cmd_param_read_timer_val param = {
+ .timer_type = type,
+ .ptr_counter_value = counter_value,
+ };
+ assert(type < PSP_TIMER_TYPE_MAX);
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_READ_TIMER_VAL, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_reset_system(enum reset_type reset_type)
+{
+ unsigned int retval = 0;
+ struct cmd_param_reset_system param = {
+ .reset_type = reset_type,
+ };
+ assert(reset_type < RESET_TYPE_MAX);
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_RESET_SYSTEM, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_crypto_sha(struct sha_generic_data *sha_op, enum sha_operation_mode sha_mode)
+{
+ uint32_t retval = 0;
+ struct cmd_param_sha param = {
+ .ptr_sha_op = sha_op,
+ };
+ assert(sha_mode == SHA_GENERIC);
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_SHA, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_modexp(struct mod_exp_params *mod_exp_param)
+{
+ uint32_t retval = 0;
+ struct cmd_param_modexp param = {
+ .ptr_modexp = mod_exp_param,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_MODEXP, (void *)&param, retval);
+ return retval;
+
+}
+
+uint32_t svc_ccp_dma(uint32_t spi_rom_offset, void *dest, uint32_t size)
+{
+ uint32_t retval = 0;
+ struct cmd_param_ccp_dma param = {
+ .spi_offset = spi_rom_offset,
+ .dst_addr = (uintptr_t)dest,
+ .size = size,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_CCP_DMA, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_set_platform_boot_mode(enum chrome_platform_boot_mode boot_mode)
+{
+ uint32_t retval = 0;
+ struct cmd_param_set_platform_boot_mode param = {
+ .boot_mode = boot_mode,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_SET_PLATFORM_BOOT_MODE, (void *)&param, retval);
+ return retval;
+}
+
+uint32_t svc_set_fw_hash_table(struct psp_fw_hash_table *hash_table)
+{
+ uint32_t retval = 0;
+ struct cmd_param_set_fw_hash_table param = {
+ .ptr_psp_fw_hash_table = hash_table,
+ };
+ SVC_CALL2(SVC_VERSTAGE_CMD, CMD_SET_FW_HASH_TABLE, (void *)&param, retval);
+ return retval;
+}
diff --git a/src/soc/amd/morgana/psp_verstage/svc.h b/src/soc/amd/morgana/psp_verstage/svc.h
new file mode 100644
index 0000000000..2507ee1dc2
--- /dev/null
+++ b/src/soc/amd/morgana/psp_verstage/svc.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+/* TODO: See what can be made common */
+
+#ifndef PSP_VERSTAGE_SVC_H
+#define PSP_VERSTAGE_SVC_H
+
+#include <bl_uapp/bl_syscall_public.h>
+#include <types.h>
+
+#define SVC_CALL4(SVC_ID, R0, R1, R2, R3, Ret) \
+ __asm__ __volatile__ ( \
+ "mov r0, %[reg0]\n\t" \
+ "mov r1, %[reg1]\n\t" \
+ "mov r2, %[reg2]\n\t" \
+ "mov r3, %[reg3]\n\t" \
+ "svc %[id]\n\t" \
+ "mov %[result], r0\n\t" \
+ : [result] "=r" (Ret) /* output */ \
+ : [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1), [reg2] "r" (R2), \
+ [reg3] "r" (R3) /* input(s) */ \
+ : "r0", "r1", "r2", "r3", "memory", "cc" /* list of clobbered registers */)
+
+#define SVC_CALL3(SVC_ID, R0, R1, R2, Ret) \
+ __asm__ __volatile__ ( \
+ "mov r0, %[reg0]\n\t" \
+ "mov r1, %[reg1]\n\t" \
+ "mov r2, %[reg2]\n\t" \
+ "svc %[id]\n\t" \
+ "mov %[result], r0\n\t" \
+ : [result] "=r" (Ret) /* output */ \
+ : [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1), [reg2] "r" (R2) \
+ : "r0", "r1", "r2", "memory", "cc" /* list of clobbered registers */)
+
+#define SVC_CALL2(SVC_ID, R0, R1, Ret) \
+ __asm__ __volatile__ ( \
+ "mov r0, %[reg0]\n\t" \
+ "mov r1, %[reg1]\n\t" \
+ "svc %[id]\n\t" \
+ "mov %[result], r0\n\t" \
+ : [result] "=r" (Ret) /* output */ \
+ : [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1)/* input(s) */ \
+ : "r0", "r1", "memory", "cc" /* list of clobbered registers */)
+
+#define SVC_CALL1(SVC_ID, R0, Ret) \
+ __asm__ __volatile__ ( \
+ "mov r0, %[reg0]\n\t" \
+ "svc %[id]\n\t" \
+ "mov %[result], r0\n\t" \
+ : [result] "=r" (Ret) /* output */ \
+ : [id] "i" (SVC_ID), [reg0] "r" (R0) /* input(s) */ \
+ : "r0", "memory", "cc" /* list of clobbered registers */)
+
+#define SVC_CALL0(SVC_ID, Ret) \
+ __asm__ __volatile__ ( \
+ "svc %[id]\n\t" \
+ "mov %[result], r0\n\t" \
+ : [result] "=r" (Ret) /* output */ \
+ : [id] "I" (SVC_ID) /* input(s) */ \
+ : "memory", "cc" /* list of clobbered registers */)
+
+struct cmd_param_sha {
+ struct sha_generic_data *ptr_sha_op;
+};
+
+struct cmd_param_debug {
+ char *debug_buffer;
+ uint32_t debug_buffer_len;
+};
+
+struct cmd_param_debug_ex {
+ uint32_t word0;
+ uint32_t word1;
+ uint32_t word2;
+ uint32_t word3;
+};
+
+struct cmd_param_modexp {
+ struct mod_exp_params *ptr_modexp;
+};
+
+struct cmd_param_psp_update {
+ unsigned int *ptr_psp_dir_addr;
+};
+
+struct cmd_param_spirom_info {
+ struct spirom_info *ptr_spirom_info;
+};
+
+struct cmd_param_map_spirom {
+ unsigned int spirom_addr;
+ unsigned int size;
+ void **ppspirom_addr_axi;
+};
+
+struct cmd_param_unmap_spirom {
+ void *ptr_spirom_addr_axi;
+};
+
+struct cmd_param_read_timer_val {
+ enum psp_timer_type timer_type;
+ uint64_t *ptr_counter_value;
+};
+
+struct cmd_param_delay_in_micro_second {
+ uint32_t delay;
+};
+
+struct cmd_param_reset_system {
+ uint32_t reset_type;
+};
+
+struct cmd_param_get_boot_mode {
+ unsigned int *ptr_boot_mode;
+};
+
+struct cmd_param_copy_data_from_uapp {
+ unsigned int address;
+ unsigned int size;
+};
+
+struct cmd_param_map_fch_io_device {
+ enum fch_io_device io_device;
+ unsigned int arg1;
+ unsigned int arg2;
+ void **pptr_io_device_addr_axi;
+};
+
+struct cmd_param_unmap_fch_io_device {
+ enum fch_io_device io_device;
+ void *ptr_io_device_addr_axi;
+};
+
+struct cmd_param_ccp_dma {
+ uint32_t spi_offset;
+ uint32_t dst_addr;
+ uint32_t size;
+};
+
+struct cmd_param_set_platform_boot_mode {
+ uint32_t boot_mode;
+};
+
+struct cmd_param_set_fw_hash_table {
+ struct psp_fw_hash_table *ptr_psp_fw_hash_table;
+};
+
+#endif /* PSP_VERSTAGE_SVC_H */
diff --git a/src/soc/amd/morgana/psp_verstage/uart.c b/src/soc/amd/morgana/psp_verstage/uart.c
new file mode 100644
index 0000000000..d2cba27891
--- /dev/null
+++ b/src/soc/amd/morgana/psp_verstage/uart.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Can this be made common? Kconfig option? */
+
+#include <bl_uapp/bl_syscall_public.h>
+#include <amdblocks/uart.h>
+#include <types.h>
+
+uintptr_t get_uart_base(unsigned int idx)
+{
+ /* Mapping the UART is not supported. */
+ return 0;
+}
diff --git a/src/soc/amd/morgana/reset.c b/src/soc/amd/morgana/reset.c
new file mode 100644
index 0000000000..83bfcee546
--- /dev/null
+++ b/src/soc/amd/morgana/reset.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Move to common? */
+
+#include <arch/io.h>
+#include <cf9_reset.h>
+#include <reset.h>
+#include <soc/southbridge.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/reset.h>
+
+void do_cold_reset(void)
+{
+ /* De-assert and then assert all PwrGood signals on CF9 reset. */
+ pm_write16(PWR_RESET_CFG, pm_read16(PWR_RESET_CFG) |
+ TOGGLE_ALL_PWR_GOOD);
+ outb(RST_CPU | SYS_RST, RST_CNT);
+}
+
+void do_warm_reset(void)
+{
+ /* Assert reset signals only. */
+ outb(RST_CPU | SYS_RST, RST_CNT);
+}
+
+void do_board_reset(void)
+{
+ do_cold_reset();
+}
diff --git a/src/soc/amd/morgana/romstage.c b/src/soc/amd/morgana/romstage.c
new file mode 100644
index 0000000000..dce0b69735
--- /dev/null
+++ b/src/soc/amd/morgana/romstage.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/memmap.h>
+#include <amdblocks/pmlib.h>
+#include <arch/cpu.h>
+#include <console/console.h>
+#include <fsp/api.h>
+#include <program_loading.h>
+#include <romstage_common.h>
+
+void __noreturn romstage_main(void)
+{
+ post_code(0x40);
+
+ /* Snapshot chipset state prior to any FSP call */
+ fill_chipset_state();
+
+ fsp_memory_init(acpi_is_wakeup_s3());
+
+ /* Fixup settings FSP-M should not be changing */
+ fch_disable_legacy_dma_io();
+
+ memmap_stash_early_dram_usage();
+
+ run_ramstage();
+}
diff --git a/src/soc/amd/morgana/root_complex.c b/src/soc/amd/morgana/root_complex.c
new file mode 100644
index 0000000000..5dd5d79579
--- /dev/null
+++ b/src/soc/amd/morgana/root_complex.c
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <acpi/acpigen.h>
+#include <amdblocks/acpi.h>
+#include <amdblocks/alib.h>
+#include <amdblocks/ioapic.h>
+#include <amdblocks/memmap.h>
+#include <arch/ioapic.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <cpu/amd/msr.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <fsp/util.h>
+#include <soc/iomap.h>
+#include <stdint.h>
+#include "chip.h"
+
+#define DPTC_TOTAL_UPDATE_PARAMS 7
+
+struct dptc_input {
+ uint16_t size;
+ struct alib_dptc_param params[DPTC_TOTAL_UPDATE_PARAMS];
+} __packed;
+
+#define DPTC_INPUTS(_thermctllmit, _sustained, _fast, _slow, \
+ _vrmCurrentLimit, _vrmMaxCurrentLimit, _vrmSocCurrentLimit) \
+ { \
+ .size = sizeof(struct dptc_input), \
+ .params = { \
+ { \
+ .id = ALIB_DPTC_THERMAL_CONTROL_LIMIT_ID, \
+ .value = _thermctllmit, \
+ }, \
+ { \
+ .id = ALIB_DPTC_SUSTAINED_POWER_LIMIT_ID, \
+ .value = _sustained, \
+ }, \
+ { \
+ .id = ALIB_DPTC_FAST_PPT_LIMIT_ID, \
+ .value = _fast, \
+ }, \
+ { \
+ .id = ALIB_DPTC_SLOW_PPT_LIMIT_ID, \
+ .value = _slow, \
+ }, \
+ { \
+ .id = ALIB_DPTC_VRM_CURRENT_LIMIT_ID, \
+ .value = _vrmCurrentLimit, \
+ }, \
+ { \
+ .id = ALIB_DPTC_VRM_MAXIMUM_CURRENT_LIMIT, \
+ .value = _vrmMaxCurrentLimit, \
+ }, \
+ { \
+ .id = ALIB_DPTC_VRM_SOC_CURRENT_LIMIT_ID, \
+ .value = _vrmSocCurrentLimit, \
+ }, \
+ }, \
+ }
+
+/*
+ *
+ * +--------------------------------+
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * reserved_dram_end +--------------------------------+
+ * | |
+ * | verstage (if reqd) |
+ * | (VERSTAGE_SIZE) |
+ * +--------------------------------+ VERSTAGE_ADDR
+ * | |
+ * | FSP-M |
+ * | (FSP_M_SIZE) |
+ * +--------------------------------+ FSP_M_ADDR
+ * | romstage |
+ * | (ROMSTAGE_SIZE) |
+ * +--------------------------------+ ROMSTAGE_ADDR = BOOTBLOCK_END
+ * | | X86_RESET_VECTOR = BOOTBLOCK_END - 0x10
+ * | bootblock |
+ * | (C_ENV_BOOTBLOCK_SIZE) |
+ * +--------------------------------+ BOOTBLOCK_ADDR = BOOTBLOCK_END - C_ENV_BOOTBLOCK_SIZE
+ * | Unused hole |
+ * | (30KiB) |
+ * +--------------------------------+
+ * | FMAP cache (FMAP_SIZE) |
+ * +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE + 0x200
+ * | Early Timestamp region (512B) |
+ * +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE
+ * | Preram CBMEM console |
+ * | (PRERAM_CBMEM_CONSOLE_SIZE) |
+ * +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE
+ * | PSP shared (vboot workbuf) |
+ * | (PSP_SHAREDMEM_SIZE) |
+ * +--------------------------------+ PSP_SHAREDMEM_BASE
+ * | APOB (120KiB) |
+ * +--------------------------------+ PSP_APOB_DRAM_ADDRESS
+ * | Early BSP stack |
+ * | (EARLYRAM_BSP_STACK_SIZE) |
+ * reserved_dram_start +--------------------------------+ EARLY_RESERVED_DRAM_BASE
+ * | DRAM |
+ * +--------------------------------+ 0x100000
+ * | Option ROM |
+ * +--------------------------------+ 0xc0000
+ * | Legacy VGA |
+ * +--------------------------------+ 0xa0000
+ * | DRAM |
+ * +--------------------------------+ 0x0
+ */
+static void read_resources(struct device *dev)
+{
+ uint32_t mem_usable = (uintptr_t)cbmem_top();
+ unsigned int idx = 0;
+ const struct hob_header *hob = fsp_get_hob_list();
+ const struct hob_resource *res;
+ struct resource *gnb_apic;
+
+ uintptr_t early_reserved_dram_start, early_reserved_dram_end;
+ const struct memmap_early_dram *e = memmap_get_early_dram_usage();
+
+ early_reserved_dram_start = e->base;
+ early_reserved_dram_end = e->base + e->size;
+
+ /* The root complex has no PCI BARs implemented, so there's no need to call
+ pci_dev_read_resources for it */
+
+ /* 0x0 - 0x9ffff */
+ ram_resource_kb(dev, idx++, 0, 0xa0000 / KiB);
+
+ /* 0xa0000 - 0xbffff: legacy VGA */
+ mmio_resource_kb(dev, idx++, 0xa0000 / KiB, 0x20000 / KiB);
+
+ /* 0xc0000 - 0xfffff: Option ROM */
+ reserved_ram_resource_kb(dev, idx++, 0xc0000 / KiB, 0x40000 / KiB);
+
+ /* 1MiB - bottom of DRAM reserved for early coreboot usage */
+ ram_resource_kb(dev, idx++, (1 * MiB) / KiB,
+ (early_reserved_dram_start - (1 * MiB)) / KiB);
+
+ /* DRAM reserved for early coreboot usage */
+ reserved_ram_resource_kb(dev, idx++, early_reserved_dram_start / KiB,
+ (early_reserved_dram_end - early_reserved_dram_start) / KiB);
+
+ /*
+ * top of DRAM consumed early - low top usable RAM
+ * cbmem_top() accounts for low UMA and TSEG if they are used.
+ */
+ ram_resource_kb(dev, idx++, early_reserved_dram_end / KiB,
+ (mem_usable - early_reserved_dram_end) / KiB);
+
+ mmconf_resource(dev, idx++);
+
+ if (!hob) {
+ printk(BIOS_ERR, "Error: %s incomplete because no HOB list was found\n",
+ __func__);
+ return;
+ }
+
+ for (; hob->type != HOB_TYPE_END_OF_HOB_LIST; hob = fsp_next_hob(hob)) {
+
+ if (hob->type != HOB_TYPE_RESOURCE_DESCRIPTOR)
+ continue;
+
+ res = fsp_hob_header_to_resource(hob);
+
+ if (res->type == EFI_RESOURCE_SYSTEM_MEMORY && res->addr < mem_usable)
+ continue; /* 0 through low usable was set above */
+ if (res->type == EFI_RESOURCE_MEMORY_MAPPED_IO)
+ continue; /* Done separately */
+
+ if (res->type == EFI_RESOURCE_SYSTEM_MEMORY)
+ ram_resource_kb(dev, idx++, res->addr / KiB, res->length / KiB);
+ else if (res->type == EFI_RESOURCE_MEMORY_RESERVED)
+ reserved_ram_resource_kb(dev, idx++, res->addr / KiB, res->length / KiB);
+ else
+ printk(BIOS_ERR, "Error: failed to set resources for type %d\n",
+ res->type);
+ }
+
+ /* GNB IOAPIC resource */
+ gnb_apic = new_resource(dev, idx++);
+ gnb_apic->base = GNB_IO_APIC_ADDR;
+ gnb_apic->size = 0x00001000;
+ gnb_apic->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
+}
+
+static void root_complex_init(struct device *dev)
+{
+ setup_ioapic((u8 *)GNB_IO_APIC_ADDR, GNB_IOAPIC_ID);
+}
+
+static void acipgen_dptci(void)
+{
+ const struct soc_amd_morgana_config *config = config_of_soc();
+
+ /* Normal mode DPTC values. */
+ struct dptc_input default_input = DPTC_INPUTS(config->thermctl_limit_degreeC,
+ config->sustained_power_limit_mW,
+ config->fast_ppt_limit_mW,
+ config->slow_ppt_limit_mW,
+ config->vrm_current_limit_mA,
+ config->vrm_maximum_current_limit_mA,
+ config->vrm_soc_current_limit_mA);
+ acpigen_write_alib_dptc_default((uint8_t *)&default_input, sizeof(default_input));
+
+ /* Low/No Battery */
+ struct dptc_input no_battery_input = DPTC_INPUTS(
+ config->thermctl_limit_degreeC,
+ config->sustained_power_limit_mW,
+ config->fast_ppt_limit_mW,
+ config->slow_ppt_limit_mW,
+ config->vrm_current_limit_throttle_mA,
+ config->vrm_maximum_current_limit_throttle_mA,
+ config->vrm_soc_current_limit_throttle_mA);
+ acpigen_write_alib_dptc_no_battery((uint8_t *)&no_battery_input,
+ sizeof(no_battery_input));
+}
+
+static void root_complex_fill_ssdt(const struct device *device)
+{
+ acpi_fill_root_complex_tom(device);
+ if (CONFIG(SOC_AMD_COMMON_BLOCK_ACPI_DPTC))
+ acipgen_dptci();
+}
+
+static const char *gnb_acpi_name(const struct device *dev)
+{
+ return "GNB";
+}
+
+static struct device_operations root_complex_operations = {
+ .read_resources = read_resources,
+ .set_resources = noop_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = root_complex_init,
+ .acpi_name = gnb_acpi_name,
+ .acpi_fill_ssdt = root_complex_fill_ssdt,
+};
+
+static const struct pci_driver family17_root_complex __pci_driver = {
+ .ops = &root_complex_operations,
+ .vendor = PCI_VID_AMD,
+ .device = PCI_DID_AMD_17H_MODEL_A0AF_NB, /* TODO: Update for Morgana */
+};
diff --git a/src/soc/amd/morgana/smihandler.c b/src/soc/amd/morgana/smihandler.c
new file mode 100644
index 0000000000..1f44afa0b2
--- /dev/null
+++ b/src/soc/amd/morgana/smihandler.c
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Update for Morgana */
+/* TODO: What can be made common */
+
+#include <acpi/acpi.h>
+#include <amdblocks/acpi.h>
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/psp.h>
+#include <amdblocks/smi.h>
+#include <amdblocks/smm.h>
+#include <arch/hlt.h>
+#include <arch/io.h>
+#include <console/console.h>
+#include <cpu/x86/cache.h>
+#include <cpu/x86/smm.h>
+#include <elog.h>
+#include <soc/smi.h>
+#include <soc/smu.h>
+#include <soc/southbridge.h>
+#include <types.h>
+
+static void fch_apmc_smi_handler(void)
+{
+ const uint8_t cmd = inb(pm_acpi_smi_cmd_port());
+
+ switch (cmd) {
+ case APM_CNT_ACPI_ENABLE:
+ acpi_clear_pm_gpe_status();
+ acpi_enable_sci();
+ break;
+ case APM_CNT_ACPI_DISABLE:
+ acpi_disable_sci();
+ break;
+ case APM_CNT_ELOG_GSMI:
+ if (CONFIG(ELOG_GSMI))
+ handle_smi_gsmi();
+ break;
+ case APM_CNT_SMMSTORE:
+ if (CONFIG(SMMSTORE))
+ handle_smi_store();
+ break;
+ case APM_CNT_SMMINFO:
+ psp_notify_smm();
+ break;
+ }
+
+ mainboard_smi_apmc(cmd);
+}
+
+/*
+ * Both the psp_notify_sx_info and the smu_sx_entry call will clobber the SMN index register
+ * during the SMN accesses. Since the SMI handler is the last thing that gets called before
+ * entering S3, this won't interfere with any indirect SMN accesses via the same register pair.
+ */
+static void fch_slp_typ_handler(void)
+{
+ uint32_t pci_ctrl, reg32;
+ uint16_t pm1cnt, reg16;
+ uint8_t slp_typ, rst_ctrl;
+
+ /* Figure out SLP_TYP */
+ pm1cnt = acpi_read16(MMIO_ACPI_PM1_CNT_BLK);
+ printk(BIOS_SPEW, "SMI#: SLP = 0x%04x\n", pm1cnt);
+ slp_typ = acpi_sleep_from_pm1(pm1cnt);
+
+ /* Do any mainboard sleep handling */
+ mainboard_smi_sleep(slp_typ);
+
+ switch (slp_typ) {
+ case ACPI_S0:
+ printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n");
+ break;
+ case ACPI_S3:
+ printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n");
+ break;
+ case ACPI_S4:
+ printk(BIOS_DEBUG, "SMI#: Entering S4 (Suspend-To-Disk)\n");
+ break;
+ case ACPI_S5:
+ printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n");
+ break;
+ default:
+ printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n");
+ break;
+ }
+
+ if (slp_typ >= ACPI_S3) {
+ wbinvd();
+
+ clear_all_smi_status();
+
+ /* Do not send SMI before AcpiPm1CntBlkx00[SlpTyp] */
+ pci_ctrl = pm_read32(PM_PCI_CTRL);
+ pci_ctrl &= ~FORCE_SLPSTATE_RETRY;
+ pm_write32(PM_PCI_CTRL, pci_ctrl);
+
+ /* Enable SlpTyp */
+ rst_ctrl = pm_read8(PM_RST_CTRL1);
+ rst_ctrl |= SLPTYPE_CONTROL_EN;
+ pm_write8(PM_RST_CTRL1, rst_ctrl);
+
+ /*
+ * Before the final command, check if there's pending wake
+ * event. Read enable first, so that reading the actual status
+ * is as close as possible to entering S3. The idea is to
+ * minimize the opportunity for a wake event to happen before
+ * actually entering S3. If there's a pending wake event, log
+ * it and continue normal path. S3 will fail and the wake event
+ * becomes a SCI.
+ */
+ if (CONFIG(ELOG_GSMI)) {
+ reg16 = acpi_read16(MMIO_ACPI_PM1_EN);
+ reg16 &= acpi_read16(MMIO_ACPI_PM1_STS);
+ if (reg16)
+ elog_add_extended_event(
+ ELOG_SLEEP_PENDING_PM1_WAKE,
+ (u32)reg16);
+
+ reg32 = acpi_read32(MMIO_ACPI_GPE0_EN);
+ reg32 &= acpi_read32(MMIO_ACPI_GPE0_STS);
+ if (reg32)
+ elog_add_extended_event(
+ ELOG_SLEEP_PENDING_GPE0_WAKE,
+ reg32);
+ } /* if (CONFIG(ELOG_GSMI)) */
+
+ if (slp_typ == ACPI_S3)
+ psp_notify_sx_info(ACPI_S3);
+
+ smu_sx_entry(); /* Leave SlpTypeEn clear, SMU will set */
+ printk(BIOS_ERR, "Error: System did not go to sleep\n");
+ hlt();
+ }
+}
+
+int southbridge_io_trap_handler(int smif)
+{
+ return 0;
+}
+
+/*
+ * Table of functions supported in the SMI handler. Note that SMI source setup
+ * in fch.c is unrelated to this list.
+ */
+static const struct smi_sources_t smi_sources[] = {
+ { .type = SMITYPE_SMI_CMD_PORT, .handler = fch_apmc_smi_handler },
+ { .type = SMITYPE_SLP_TYP, .handler = fch_slp_typ_handler},
+};
+
+void *get_smi_source_handler(int source)
+{
+ size_t i;
+
+ for (i = 0 ; i < ARRAY_SIZE(smi_sources) ; i++)
+ if (smi_sources[i].type == source)
+ return smi_sources[i].handler;
+
+ return NULL;
+}
diff --git a/src/soc/amd/morgana/smu.c b/src/soc/amd/morgana/smu.c
new file mode 100644
index 0000000000..d8cd081bad
--- /dev/null
+++ b/src/soc/amd/morgana/smu.c
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <amdblocks/smu.h>
+#include <soc/smu.h>
+
+/* TODO: can this be made common? */
+
+/*
+ * Request the SMU to put system into S3, S4, or S5. On entry, SlpTyp determines S-State and
+ * SlpTypeEn gets set by the SMU. Function does not return if successful.
+ */
+void smu_sx_entry(void)
+{
+ struct smu_payload msg = { 0 }; /* Unused for SMC_MSG_S3ENTRY */
+
+ printk(BIOS_DEBUG, "SMU: Put system into S3/S4/S5\n");
+ send_smu_message(SMC_MSG_S3ENTRY, &msg);
+}
diff --git a/src/soc/amd/morgana/uart.c b/src/soc/amd/morgana/uart.c
new file mode 100644
index 0000000000..0cf1af8446
--- /dev/null
+++ b/src/soc/amd/morgana/uart.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/aoac.h>
+#include <amdblocks/gpio.h>
+#include <amdblocks/uart.h>
+#include <commonlib/helpers.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/mmio.h>
+#include <soc/aoac_defs.h>
+#include <soc/gpio.h>
+#include <soc/southbridge.h>
+#include <soc/uart.h>
+#include <types.h>
+
+static const struct {
+ uintptr_t base;
+ struct soc_amd_gpio mux[2];
+} uart_info[] = {
+ [0] = { APU_UART0_BASE, {
+ PAD_NF(GPIO_143, UART0_TXD, PULL_NONE),
+ PAD_NF(GPIO_141, UART0_RXD, PULL_NONE),
+ } },
+ [1] = { APU_UART1_BASE, {
+ PAD_NF(GPIO_140, UART1_TXD, PULL_NONE),
+ PAD_NF(GPIO_142, UART1_RXD, PULL_NONE),
+ } },
+ [2] = { APU_UART2_BASE, {
+ PAD_NF(GPIO_138, UART2_TXD, PULL_NONE),
+ PAD_NF(GPIO_136, UART2_RXD, PULL_NONE),
+ } },
+ [3] = { APU_UART3_BASE, {
+ PAD_NF(GPIO_135, UART3_TXD, PULL_NONE),
+ PAD_NF(GPIO_137, UART3_RXD, PULL_NONE),
+ } },
+ [4] = { APU_UART4_BASE, {
+ PAD_NF(GPIO_156, UART4_TXD, PULL_NONE),
+ PAD_NF(GPIO_155, UART4_RXD, PULL_NONE),
+ } },
+};
+
+uintptr_t get_uart_base(unsigned int idx)
+{
+ if (idx >= ARRAY_SIZE(uart_info))
+ return 0;
+
+ return uart_info[idx].base;
+}
+
+void clear_uart_legacy_config(void)
+{
+ write16p(FCH_LEGACY_UART_DECODE, 0);
+}
+
+void set_uart_config(unsigned int idx)
+{
+ if (idx >= ARRAY_SIZE(uart_info))
+ return;
+
+ gpio_configure_pads(uart_info[idx].mux, 2);
+}
+
+static const char *uart_acpi_name(const struct device *dev)
+{
+ switch (dev->path.mmio.addr) {
+ case APU_UART0_BASE:
+ return "FUR0";
+ case APU_UART1_BASE:
+ return "FUR1";
+ case APU_UART2_BASE:
+ return "FUR2";
+ case APU_UART3_BASE:
+ return "FUR3";
+ case APU_UART4_BASE:
+ return "FUR4";
+ default:
+ return NULL;
+ }
+}
+
+/* Even though this is called enable, it gets called for both enabled and disabled devices. */
+static void uart_enable(struct device *dev)
+{
+ unsigned int dev_id;
+
+ switch (dev->path.mmio.addr) {
+ case APU_UART0_BASE:
+ dev_id = FCH_AOAC_DEV_UART0;
+ break;
+ case APU_UART1_BASE:
+ dev_id = FCH_AOAC_DEV_UART1;
+ break;
+ case APU_UART2_BASE:
+ dev_id = FCH_AOAC_DEV_UART2;
+ break;
+ case APU_UART3_BASE:
+ dev_id = FCH_AOAC_DEV_UART3;
+ break;
+ case APU_UART4_BASE:
+ dev_id = FCH_AOAC_DEV_UART4;
+ break;
+ default:
+ printk(BIOS_ERR, "%s: Unknown device: %s\n", __func__, dev_path(dev));
+ return;
+ }
+
+ if (dev->enabled) {
+ power_on_aoac_device(dev_id);
+ wait_for_aoac_enabled(dev_id);
+ } else {
+ power_off_aoac_device(dev_id);
+ }
+}
+
+static void uart_read_resources(struct device *dev)
+{
+ mmio_resource_kb(dev, 0, dev->path.mmio.addr / KiB, 4);
+}
+
+struct device_operations morgana_uart_mmio_ops = {
+ .read_resources = uart_read_resources,
+ .set_resources = noop_set_resources,
+ .scan_bus = scan_static_bus,
+ .enable = uart_enable,
+ .acpi_name = uart_acpi_name,
+ .acpi_fill_ssdt = uart_inject_ssdt,
+};
diff --git a/src/soc/amd/morgana/xhci.c b/src/soc/amd/morgana/xhci.c
new file mode 100644
index 0000000000..9f62b18a29
--- /dev/null
+++ b/src/soc/amd/morgana/xhci.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for Morgana */
+
+#include <amdblocks/gpio.h>
+#include <amdblocks/smi.h>
+#include <bootstate.h>
+#include <device/device.h>
+#include <device/pci_ids.h>
+#include <drivers/usb/pci_xhci/pci_xhci.h>
+#include <soc/pci_devs.h>
+#include <soc/smi.h>
+
+static const struct sci_source xhci_sci_sources[] = {
+ {
+ .scimap = SMITYPE_XHC0_PME,
+ .gpe = GEVENT_31,
+ .direction = SMI_SCI_LVL_HIGH,
+ .level = SMI_SCI_EDG
+ },
+ {
+ .scimap = SMITYPE_XHC1_PME,
+ .gpe = GEVENT_31,
+ .direction = SMI_SCI_LVL_HIGH,
+ .level = SMI_SCI_EDG
+ },
+ {
+ .scimap = SMITYPE_XHC2_PME,
+ .gpe = GEVENT_31,
+ .direction = SMI_SCI_LVL_HIGH,
+ .level = SMI_SCI_EDG
+ }
+};
+
+enum cb_err pci_xhci_get_wake_gpe(const struct device *dev, int *gpe)
+{
+ if (dev->bus->dev->path.type != DEVICE_PATH_PCI)
+ return CB_ERR_ARG;
+
+ if (dev->path.type != DEVICE_PATH_PCI)
+ return CB_ERR_ARG;
+
+ if (dev->bus->dev->path.pci.devfn == PCIE_ABC_A_DEVFN) {
+ if (dev->path.pci.devfn == XHCI0_DEVFN) {
+ *gpe = xhci_sci_sources[0].gpe;
+ return CB_SUCCESS;
+ } else if (dev->path.pci.devfn == XHCI1_DEVFN) {
+ *gpe = xhci_sci_sources[1].gpe;
+ return CB_SUCCESS;
+ }
+ } else if (dev->bus->dev->path.pci.devfn == PCIE_GPP_C_DEVFN) {
+ if (dev->path.pci.devfn == XHCI2_DEVFN
+ && dev->device == PCI_DID_AMD_FAM17H_MODELA0H_XHCI2) {
+ *gpe = xhci_sci_sources[2].gpe;
+ return CB_SUCCESS;
+ }
+ }
+
+ return CB_ERR_ARG;
+}
+
+static void configure_xhci_sci(void *unused)
+{
+ gpe_configure_sci(xhci_sci_sources, ARRAY_SIZE(xhci_sci_sources) - 1);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, configure_xhci_sci, NULL);