soc/amd/sabrina: add new SoC as copy of soc/amd/cezanne
The Cezanne SoC code was initially started as a copy of example/min86
which only provides enough code to make the SoC code build. Then the
different parts of the real SoC support was brought in patch by patch
which also helped cleaning up and untangling the code. Since the Cezanne
SoC code is now in a rather good shape and the Sabrina SoC is similar to
the Cezanne SoC from the coreboot side, the new SoC support is started
with a copy of the Cezanne code and all the needed changes will be
applied on top of that. In order for the build not to fail due to
duplicate files, this patch does not only copy the directory, but also
replaces most instances of the Cezanne name with Sabrina. Since the
needed blobs aren't available in the 3rdparty/amd_blobs repository yet,
the Cezanne blobs are used for now so that the build will succeed. As
soon as the proper blobs will be available in that repository, the code
will be switched over to use them.
As suggested by Nico, I added a "TODO: Check if this is still correct"
comment to the beginning of every copied file and all SOC_AMD_COMMON_*
Kconfig option selects which will be removed after re-verifying that
each file and each selected common code block is still correct for the
new SoC.
Signed-off-by: Felix Held <felix-coreboot@felixheld.de>
Change-Id: I978ddbdbfd70863acac17d98732936ec2be8fe3c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/61077
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Marshall Dawson <marshalldawson3rd@gmail.com>
diff --git a/src/soc/amd/sabrina/Kconfig b/src/soc/amd/sabrina/Kconfig
new file mode 100644
index 0000000..6e84bf7
--- /dev/null
+++ b/src/soc/amd/sabrina/Kconfig
@@ -0,0 +1,466 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# TODO: Check if this is still correct
+
+config SOC_AMD_SABRINA
+ bool
+ help
+ AMD Sabrina support
+
+if SOC_AMD_SABRINA
+
+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 CONSOLE_CBMEM_PRINT_PRE_BOOTBLOCK_CONTENTS if VBOOT_STARTS_BEFORE_BOOTBLOCK
+ select DRIVERS_USB_ACPI
+ select DRIVERS_I2C_DESIGNWARE
+ 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_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 # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_ACPI # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_ACPIMMIO # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_ACPI_ALIB # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_ACPI_GPIO # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_ACPI_IVRS # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_AOAC # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_APOB # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_DATA_FABRIC # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_GRAPHICS # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_HAS_ESPI # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_I2C # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_IOMMU # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_LPC # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_MCAX # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_NONCAR # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PCI # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PCI_MMCONF # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PCIE_GPP_DRIVER # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PM # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PM_CHIPSET_STATE_SAVE # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_PSP_GEN2 # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_SMBUS # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_SMI # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_SMM # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_SMU # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_SPI # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_TSC_FAM17H_19H # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_UART # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_BLOCK_UCODE # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_FSP_DMI_TABLES # TODO: Check if this is still correct
+ select SOC_AMD_COMMON_FSP_PCI # TODO: Check if this is still correct
+ select SSE2
+ select UDK_2017_BINDING
+ 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 SOC_AMD_COMMON_BLOCK_UCODE_SIZE
+ default 5568
+
+config CHIPSET_DEVICETREE
+ string
+ default "soc/amd/sabrina/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_SHAREDMEM_BASE
+ hex
+ default 0x2011000 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 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 RAMBASE
+ hex
+ default 0x10000000
+
+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 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
+
+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
+ default "src/soc/amd/sabrina/fw.cfg"
+
+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 "3rdparty/amd_blobs/cezanne/PSP/wtl-czn.sbin"
+
+config PSP_SOFTFUSE_BITS
+ string "PSP Soft Fuse bits to enable"
+ default "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 post code destination: 0=LPC 1=eSPI
+ (Set by PSP_INITIALIZE_ESPI)
+ 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 Chrome OS 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_SABRINA
diff --git a/src/soc/amd/sabrina/Makefile.inc b/src/soc/amd/sabrina/Makefile.inc
new file mode 100644
index 0000000..734f152
--- /dev/null
+++ b/src/soc/amd/sabrina/Makefile.inc
@@ -0,0 +1,294 @@
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TODO: Check if this is still correct
+
+ifeq ($(CONFIG_SOC_AMD_SABRINA),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_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 += cppc.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 += graphics.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/sabrina/include
+CPPFLAGS_common += -I$(src)/soc/amd/sabrina/acpi
+CPPFLAGS_common += -I$(src)/vendorcode/amd/fsp/sabrina
+
+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))
+
+SABRINA_FWM_POSITION=$(call int-add, \
+ $(call int-subtract, 0xffffffff \
+ $(call int-shift-left, \
+ 0x80000 $(CONFIG_AMD_FWM_POSITION_INDEX))) 0x20000 1)
+
+SABRINA_FW_A_POSITION=$(call int-add, \
+ $(shell awk '$$2 == "FMAP_SECTION_FW_MAIN_A_START" {print $$3}' $(obj)/fmap_config.h) \
+ 0x40)
+
+SABRINA_FW_B_POSITION=$(call int-add, \
+ $(shell awk '$$2 == "FMAP_SECTION_FW_MAIN_B_START" {print $$3}' $(obj)/fmap_config.h) \
+ 0x40)
+#
+# 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).
+#
+
+FIRMWARE_LOCATION=$(shell grep -e FIRMWARE_LOCATION $(CONFIG_AMDFW_CONFIG_FILE) | awk '{print $$2}')
+
+ifeq ($(CONFIG_PSP_DISABLE_POSTCODES),y)
+PSP_SOFTFUSE_BITS += 7
+endif
+
+ifeq ($(CONFIG_PSP_POSTCODES_ON_ESPI),y)
+PSP_SOFTFUSE_BITS += 15
+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
+
+ifeq ($(CONFIG_PSP_S0I3_RESUME_VERSTAGE),y)
+PSP_SOFTFUSE_BITS += 58
+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
+
+#
+# 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
+
+# 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_PSP_SOFTFUSE=$(call add_opt_prefix, $(PSP_SOFTFUSE), --soft-fuse)
+
+OPT_WHITELIST_FILE=$(call add_opt_prefix, $(PSP_WHITELIST_FILE), --whitelist)
+
+# Add all the files listed in the config file
+POUND_SIGN=$(call strip_quotes, "\#")
+DEP_FILES= $(patsubst %,$(FIRMWARE_LOCATION)/%, $(shell sed -e /^$(POUND_SIGN)/d -e /*/d -e /^FIRMWARE_LOCATION/d $(CONFIG_AMDFW_CONFIG_FILE) | awk '{print $$2}' ))
+
+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 "Cezanne" \
+ --flashsize $(CONFIG_ROM_SIZE)
+
+$(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) \
+ --location $(shell printf "%#x" $(SABRINA_FWM_POSITION)) \
+ --multilevel \
+ --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) \
+ --location $(shell printf "%#x" $(SABRINA_FW_A_POSITION)) \
+ --anywhere \
+ --multilevel \
+ --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) \
+ --location $(shell printf "%#x" $(SABRINA_FW_B_POSITION)) \
+ --anywhere \
+ --multilevel \
+ --output $@
+
+
+cbfs-files-y += apu/amdfw
+apu/amdfw-file := $(obj)/amdfw.rom
+apu/amdfw-position := $(SABRINA_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 := $(call strip_quotes, $(SABRINA_FW_A_POSITION))
+apu/amdfw_a-type := raw
+
+cbfs-files-y += apu/amdfw_b
+apu/amdfw_b-file := $(obj)/amdfw_b.rom
+apu/amdfw_b-position := $(call strip_quotes, $(SABRINA_FW_B_POSITION))
+apu/amdfw_b-type := raw
+endif
+
+cpu_microcode_bins += $(wildcard ${FIRMWARE_LOCATION}/UcodePatch_*.bin)
+
+endif # ($(CONFIG_SOC_AMD_SABRINA),y)
diff --git a/src/soc/amd/sabrina/acpi.c b/src/soc/amd/sabrina/acpi.c
new file mode 100644
index 0000000..ea67bcf
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi.c
@@ -0,0 +1,370 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+/* ACPI - create the Fixed ACPI Description Tables (FADT) */
+
+#include <acpi/acpi.h>
+#include <acpi/acpigen.h>
+#include <amdblocks/acpi.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"
+#include <soc/cppc.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_sabrina_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 >= 0xF8) && (core_vid <= 0xFF)) {
+ /* Voltage off for VID codes 0xF8 to 0xFF */
+ voltage_in_uvolts = 0;
+ } else {
+ voltage_in_uvolts =
+ SERIAL_VID_MAX_MICROVOLTS - (SERIAL_VID_DECODE_MICROVOLTS * core_vid);
+ }
+
+ /* Power in mW */
+ power_in_mw = (voltage_in_uvolts) / 1000 * current_value_amps;
+
+ switch (current_divisor) {
+ case 0:
+ break;
+ case 1:
+ power_in_mw = power_in_mw / 10L;
+ break;
+ case 2:
+ power_in_mw = power_in_mw / 100L;
+ 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 = ((cpuid_ebx(CPUID_EBX_CORE_ID) & CPUID_EBX_THREADS_MASK)
+ >> CPUID_EBX_THREADS_SHIFT)
+ + 1;
+ 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/sabrina/acpi/globalnvs.asl b/src/soc/amd/sabrina/acpi/globalnvs.asl
new file mode 100644
index 0000000..19d58d5
--- /dev/null
+++ b/src/soc/amd/sabrina/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/sabrina/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/sabrina/acpi/mmio.asl b/src/soc/amd/sabrina/acpi/mmio.asl
new file mode 100644
index 0000000..381405f
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi/mmio.asl
@@ -0,0 +1,290 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 (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)
+{
+ Name (_HID, "AMDI0010")
+ 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)
+ }
+
+ AOAC_DEVICE(FCH_AOAC_DEV_I2C3, 0)
+}
+
+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/sabrina/acpi/pci0.asl b/src/soc/amd/sabrina/acpi/pci0.asl
new file mode 100644
index 0000000..853c686
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi/pci0.asl
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+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/sabrina/acpi/pci_int_defs.asl b/src/soc/amd/sabrina/acpi/pci_int_defs.asl
new file mode 100644
index 0000000..e0d1fa2
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi/pci_int_defs.asl
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+/* 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 */
+ PI25, 0x00000008, /* Index 0x77: I2C5 */
+
+ /* 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 */
+ II25, 0x00000008, /* Index 0xF7: I2C5 */
+}
diff --git a/src/soc/amd/sabrina/acpi/rtc_workaround.asl b/src/soc/amd/sabrina/acpi/rtc_workaround.asl
new file mode 100644
index 0000000..8bbca4e3
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi/rtc_workaround.asl
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+/*
+ * Workaround for RTC on Cezanne.
+ * See https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/kernel/v5.10/drivers/platform/x86/amd-pmc.c;l=416;drc=54a96af06ae6851e4a02e8dd700de0d579ef7839
+ */
+
+Scope (\_SB.PEP) {
+ Name (_PRW, Package () {
+ Package() {\_SB.GPIO, 0},
+ 0x03
+ })
+}
+
+Scope (\_SB.GPIO) {
+ Name (_AEI, ResourceTemplate () {
+ GpioInt(Edge, ActiveHigh, ExclusiveAndWake, PullNone, 0x0000, "\\_SB.GPIO",,,,)
+ {
+ 44 /* int_shdwsysalarmfire */
+ }
+ })
+
+ Method (_E2C, 0, Serialized) {
+ Notify (\_SB_.PEP, 0x02)
+ }
+}
diff --git a/src/soc/amd/sabrina/acpi/soc.asl b/src/soc/amd/sabrina/acpi/soc.asl
new file mode 100644
index 0000000..f5a41a1
--- /dev/null
+++ b/src/soc/amd/sabrina/acpi/soc.asl
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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>
+
+#include "rtc_workaround.asl"
+
+/*
+ * Platform Wake Notify
+ *
+ * This is called by soc/amd/common/acpi/platform.asl.
+ */
+Method (PNOT)
+{
+ /* Report AC/DC state to ALIB using WAL1() */
+ \WAL1 ()
+}
diff --git a/src/soc/amd/sabrina/agesa_acpi.c b/src/soc/amd/sabrina/agesa_acpi.c
new file mode 100644
index 0000000..f8193c7
--- /dev/null
+++ b/src/soc/amd/sabrina/agesa_acpi.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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/sabrina/aoac.c b/src/soc/amd/sabrina/aoac.c
new file mode 100644
index 0000000..33b00b4
--- /dev/null
+++ b/src/soc/amd/sabrina/aoac.c
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 \
+ : -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/sabrina/bootblock.c b/src/soc/amd/sabrina/bootblock.c
new file mode 100644
index 0000000..bbf56d3
--- /dev/null
+++ b/src/soc/amd/sabrina/bootblock.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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/sabrina/chip.c b/src/soc/amd/sabrina/chip.c
new file mode 100644
index 0000000..9835c6e
--- /dev/null
+++ b/src/soc/amd/sabrina/chip.c
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 sabrina_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:
+ dev->ops = &sabrina_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_sabrina_ops = {
+ CHIP_NAME("AMD Sabrina SoC")
+ .enable_dev = enable_dev,
+ .init = soc_init,
+ .final = soc_final
+};
diff --git a/src/soc/amd/sabrina/chip.h b/src/soc/amd/sabrina/chip.h
new file mode 100644
index 0000000..6903180
--- /dev/null
+++ b/src/soc/amd/sabrina/chip.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef SABRINA_CHIP_H
+#define SABRINA_CHIP_H
+
+#include <amdblocks/chip.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/sabrina/FspUsb.h>
+
+struct soc_amd_sabrina_config {
+ struct soc_amd_common_config common_config;
+ u8 i2c_scl_reset;
+ struct dw_i2c_bus_config i2c[I2C_CTRLR_COUNT];
+ u8 i2c_pad_ctrl_rx_sel[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;
+
+ 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;
+
+ 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;
+
+ /* Enable dptc for tablet mode (0 = disable, 1 = enable) */
+ uint8_t dptc_enable;
+
+ /* STAPM Configuration for tablet mode (need enable dptc_enable first) */
+ uint32_t fast_ppt_limit_tablet_mode_mW;
+ uint32_t slow_ppt_limit_tablet_mode_mW;
+ uint32_t sustained_power_limit_tablet_mode_mW;
+ uint32_t thermctl_limit_tablet_mode_degreeC;
+
+ /* 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_COUNT];
+
+ /* 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 /* SABRINA_CHIP_H */
diff --git a/src/soc/amd/sabrina/chipset.cb b/src/soc/amd/sabrina/chipset.cb
new file mode 100644
index 0000000..486f42f
--- /dev/null
+++ b/src/soc/amd/sabrina/chipset.cb
@@ -0,0 +1,114 @@
+# TODO: Check if this is still correct
+
+chip soc/amd/sabrina
+ 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, do not disable
+ device pci 01.1 alias gpp_gfx_bridge_0 off end
+ device pci 01.2 alias gpp_gfx_bridge_1 off end
+ device pci 01.3 alias gpp_gfx_bridge_2 off end
+
+ 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 02.7 alias gpp_bridge_6 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 3.1 alias usb3_port1 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
+ chip drivers/usb/acpi
+ device usb 2.2 alias usb2_port2 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.3 alias usb2_port3 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_port4 off end
+ end
+ chip drivers/usb/acpi
+ device usb 3.1 alias usb3_port5 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.0 alias usb2_port4 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.1 alias usb2_port5 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.2 alias usb2_port6 off end
+ end
+ chip drivers/usb/acpi
+ device usb 2.3 alias usb2_port7 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 # Internal GPP Bridge 1 to Bus B
+ device pci 0.0 alias sata_0 off end # first SATA controller; AHCI Mode
+ device pci 0.1 alias sata_1 off end # second SATA Controller; SATA Raid/AHCI Mode
+ device pci 0.2 alias xgbe_0 off end # 10 GbE Controller Port 0 (XGBE0)
+ device pci 0.3 alias xgbe_1 off end # 10 GbE Controller Port 1 (XGBE1)
+ end
+ device pci 08.3 alias gpp_bridge_c off # Internal GPP Bridge 2 to Bus C
+ device pci 0.0 alias dummy_function_c off end # PCIe Dummy Function
+ device pci 0.2 alias i2s_ac97 off end # I2S/AC'97 Audio
+ 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 0xfedd5000 alias emmc off end
+end
diff --git a/src/soc/amd/sabrina/config.c b/src/soc/amd/sabrina/config.c
new file mode 100644
index 0000000..ef1d556
--- /dev/null
+++ b/src/soc/amd/sabrina/config.c
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <amdblocks/chip.h>
+#include <device/device.h>
+#include "chip.h"
+
+const struct soc_amd_common_config *soc_get_common_config()
+{
+ /* config_of_soc calls die() internally if cfg was NULL, so no need to re-check */
+ const struct soc_amd_sabrina_config *cfg = config_of_soc();
+ return &cfg->common_config;
+}
diff --git a/src/soc/amd/sabrina/cppc.c b/src/soc/amd/sabrina/cppc.c
new file mode 100644
index 0000000..d35e0a5
--- /dev/null
+++ b/src/soc/amd/sabrina/cppc.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <acpi/acpi_pm.h>
+#include <acpi/acpigen.h>
+#include <arch/cpu.h>
+#include <soc/cppc.h>
+#include <soc/msr.h>
+
+/*
+ * version 2 is expected to be the typical use case.
+ * For now this function 'punts' on version 3 and just
+ * populates the additional fields with 'unsupported'.
+ */
+void cpu_init_cppc_config(struct cppc_config *config, u32 version)
+{
+ config->version = version;
+
+ config->entries[CPPC_HIGHEST_PERF] = CPPC_REG_MSR(MSR_CPPC_CAPABILITY_1, SHIFT_CPPC_CAPABILITY_1_HIGHEST_PERF, 8);
+ config->entries[CPPC_NOMINAL_PERF] = CPPC_REG_MSR(MSR_CPPC_CAPABILITY_1, SHIFT_CPPC_CAPABILITY_1_NOMINAL_PERF, 8);
+ config->entries[CPPC_LOWEST_NONL_PERF] = CPPC_REG_MSR(MSR_CPPC_CAPABILITY_1, SHIFT_CPPC_CAPABILITY_1_LOW_NON_LIN_PERF, 8);
+ config->entries[CPPC_LOWEST_PERF] = CPPC_REG_MSR(MSR_CPPC_CAPABILITY_1, SHIFT_CPPC_CAPABILITY_1_LOWEST_PERF, 8);
+ config->entries[CPPC_GUARANTEED_PERF] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_DESIRED_PERF] = CPPC_REG_MSR(MSR_CPPC_REQUEST, SHIFT_CPPC_REQUEST_DES_PERF, 8);
+ config->entries[CPPC_MIN_PERF] = CPPC_REG_MSR(MSR_CPPC_REQUEST, SHIFT_CPPC_REQUEST_MIN_PERF, 8);
+ config->entries[CPPC_MAX_PERF] = CPPC_REG_MSR(MSR_CPPC_REQUEST, SHIFT_CPPC_REQUEST_MAX_PERF, 8);
+ config->entries[CPPC_PERF_REDUCE_TOLERANCE] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_TIME_WINDOW] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_COUNTER_WRAP] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_REF_PERF_COUNTER] = CPPC_REG_MSR(MSR_MAX_PERFORMANCE_FREQUENCY_CLOCK_COUNT, 0, 64);
+ config->entries[CPPC_DELIVERED_PERF_COUNTER] = CPPC_REG_MSR(MSR_ACTUAL_PERFORMANCE_FREQUENCY_CLOCK_COUNT, 0, 64);
+ config->entries[CPPC_PERF_LIMITED] = CPPC_REG_MSR(MSR_CPPC_STATUS, 1, 1);
+ config->entries[CPPC_ENABLE] = CPPC_REG_MSR(MSR_CPPC_ENABLE, 0, 1);
+
+ if (version < 2)
+ return;
+
+ config->entries[CPPC_AUTO_SELECT] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_AUTO_ACTIVITY_WINDOW] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_PERF_PREF] = CPPC_REG_MSR(MSR_CPPC_REQUEST, SHIFT_CPPC_REQUEST_ENERGY_PERF_PREF, 8);
+ config->entries[CPPC_REF_PERF] = CPPC_UNSUPPORTED;
+
+ if (version < 3)
+ return;
+
+ config->entries[CPPC_LOWEST_FREQ] = CPPC_UNSUPPORTED;
+ config->entries[CPPC_NOMINAL_FREQ] = CPPC_UNSUPPORTED;
+}
+
+
+void generate_cppc_entries(unsigned int core_id)
+{
+ /* Generate GCPC package in first logical core */
+ if (core_id == 0) {
+ struct cppc_config cppc_config;
+ cpu_init_cppc_config(&cppc_config, CPPC_VERSION_3);
+ acpigen_write_CPPC_package(&cppc_config);
+ }
+
+ /* Write _CPC entry for each logical core */
+ acpigen_write_CPPC_method();
+}
diff --git a/src/soc/amd/sabrina/cpu.c b/src/soc/amd/sabrina/cpu.c
new file mode 100644
index 0000000..6c6bc69
--- /dev/null
+++ b/src/soc/amd/sabrina/cpu.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <amdblocks/cpu.h>
+#include <amdblocks/mca.h>
+#include <amdblocks/reset.h>
+#include <amdblocks/smm.h>
+#include <assert.h>
+#include <console/console.h>
+#include <cpu/amd/microcode.h>
+#include <cpu/cpu.h>
+#include <cpu/x86/lapic.h>
+#include <cpu/x86/mp.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/smm.h>
+#include <device/device.h>
+#include <soc/cpu.h>
+#include <soc/iomap.h>
+#include <types.h>
+
+_Static_assert(CONFIG_MAX_CPUS == 16, "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 */
+
+/*
+ * Do essential initialization tasks before APs can be fired up -
+ *
+ * 1. Prevent race condition in MTRR solution. Enable MTRRs on the BSP. This
+ * creates the MTRR solution that the APs will use. Otherwise APs will try to
+ * apply the incomplete solution as the BSP is calculating it.
+ */
+static void pre_mp_init(void)
+{
+ x86_setup_mtrrs_with_detect_no_above_4gb();
+ x86_mtrr_check();
+}
+
+static void post_mp_init(void)
+{
+ global_smi_enable();
+ apm_control(APM_CNT_SMMINFO);
+}
+
+static const struct mp_ops mp_ops = {
+ .pre_mp_init = pre_mp_init,
+ .get_cpu_count = get_cpu_count,
+ .get_smm_info = get_smm_info,
+ .relocation_handler = smm_relocation_handler,
+ .post_mp_init = post_mp_init,
+};
+
+void mp_init_cpus(struct bus *cpu_bus)
+{
+ if (mp_init_with_smm(cpu_bus, &mp_ops) != 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_BASE_ADDR, CONFIG_ROM_SIZE, MTRR_TYPE_WRPROT);
+}
+
+static void zen_2_3_init(struct device *dev)
+{
+ check_mca();
+ setup_lapic();
+ 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, CEZANNE_A0_CPUID},
+ { 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/sabrina/data_fabric.c b/src/soc/amd/sabrina/data_fabric.c
new file mode 100644
index 0000000..a51a716
--- /dev/null
+++ b/src/soc/amd/sabrina/data_fabric.c
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <acpi/acpi_device.h>
+#include <amdblocks/data_fabric.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_DEVICE_ID_AMD_FAM17H_MODEL60H_DF0:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF0:
+ return "DFD0";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF1:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF1:
+ return "DFD1";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF2:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF2:
+ return "DFD2";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF3:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF3:
+ return "DFD3";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF4:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF4:
+ return "DFD4";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF5:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF5:
+ return "DFD5";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF6:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF6:
+ return "DFD6";
+ case PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF7:
+ case PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_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[] = {
+ /* Renoir DF devices */
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF0,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF1,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF2,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF3,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF4,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF5,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF6,
+ PCI_DEVICE_ID_AMD_FAM17H_MODEL60H_DF7,
+ /* Cezanne DF devices */
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF0,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF1,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF2,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF3,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF4,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF5,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF6,
+ PCI_DEVICE_ID_AMD_FAM19H_MODEL51H_DF7,
+ 0
+};
+
+static const struct pci_driver data_fabric_driver __pci_driver = {
+ .ops = &data_fabric_ops,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .devices = pci_device_ids,
+};
diff --git a/src/soc/amd/sabrina/early_fch.c b/src/soc/amd/sabrina/early_fch.c
new file mode 100644
index 0000000..45ba85c
--- /dev/null
+++ b/src/soc/amd/sabrina/early_fch.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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_sabrina_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();
+ reset_i2c_peripherals();
+
+ /*
+ * 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)
+{
+ 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/sabrina/espi_util.c b/src/soc/amd/sabrina/espi_util.c
new file mode 100644
index 0000000..41289ae
--- /dev/null
+++ b/src/soc/amd/sabrina/espi_util.c
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <amdblocks/acpimmio.h>
+#include <amdblocks/lpc.h>
+#include <device/pci_ops.h>
+#include <soc/espi.h>
+#include <soc/lpc.h>
+#include <soc/pci_devs.h>
+#include <soc/southbridge.h>
+#include <types.h>
+
+void espi_disable_lpc_ldrq(void)
+{
+ /* Beware that the bit definitions for LPC_LDRQ0_PU_EN and LPC_LDRQ0_PD_EN are swapped
+ on Picasso and older compared to Renoir/Cezanne and newer */
+ uint32_t dword = pci_read_config32(SOC_LPC_DEV, LPC_MISC_CONTROL_BITS);
+ dword &= ~(LPC_LDRQ0_PU_EN | LPC_LDRQ1_EN | LPC_LDRQ0_EN);
+ dword |= LPC_LDRQ0_PD_EN;
+ pci_write_config32(SOC_LPC_DEV, LPC_MISC_CONTROL_BITS, dword);
+}
+
+void espi_switch_to_spi2_pads(void)
+{
+ /* Use SPI2 pins for eSPI */
+ uint32_t dword = pm_read32(PM_SPI_PAD_PU_PD);
+ dword |= PM_ESPI_CS_USE_DATA2;
+ pm_write32(PM_SPI_PAD_PU_PD, dword);
+
+ /* Switch the pads that can be used as either LPC or secondary eSPI to 1.8V mode */
+ dword = pm_read32(PM_ACPI_CONF);
+ dword |= PM_ACPI_S5_LPC_PIN_MODE | PM_ACPI_S5_LPC_PIN_MODE_SEL;
+ pm_write32(PM_ACPI_CONF, dword);
+}
diff --git a/src/soc/amd/sabrina/fch.c b/src/soc/amd/sabrina/fch.c
new file mode 100644
index 0000000..54404e4
--- /dev/null
+++ b/src/soc/amd/sabrina/fch.c
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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_SATA, "SATA" },
+ { 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_I2C5, "I2C5" },
+};
+
+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);
+}
+
+static void fch_init_resets(void)
+{
+ pm_write16(PWR_RESET_CFG, pm_read16(PWR_RESET_CFG) | TOGGLE_ALL_PWR_GOOD);
+}
+
+/* configure the general purpose PCIe clock outputs according to the devicetree settings */
+static void gpp_clk_setup(void)
+{
+ const struct soc_amd_sabrina_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.
+ */
+ switch (cfg->gpp_clk_config[i]) {
+ 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_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)
+{
+ fch_init_resets();
+ 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/sabrina/fsp_m_params.c b/src/soc/amd/sabrina/fsp_m_params.c
new file mode 100644
index 0000000..abbb0d1
--- /dev/null
+++ b/src/soc/amd/sabrina/fsp_m_params.c
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 "chip.h"
+
+__weak void mb_pre_fspm(void)
+{
+}
+
+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;
+ const fsp_ddi_descriptor *fsp_ddi;
+ size_t num_dxio;
+ size_t num_ddi;
+
+ 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_sabrina_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));
+ mcfg->sata_enable = is_dev_enabled(DEV_PTR(sata_0)) || is_dev_enabled(DEV_PTR(sata_1));
+
+ if (config->usb_phy_custom) {
+ mcfg->usb_phy = (struct usb_phy_config *)&config->usb_phy;
+ mcfg->usb_phy->Version_Major = 0xd;
+ mcfg->usb_phy->Version_Minor = 0x6;
+ mcfg->usb_phy->TableLength = 100;
+ } else {
+ mcfg->usb_phy = NULL;
+ }
+
+ fsp_fill_pcie_ddi_descriptors(mcfg);
+ fsp_assign_ioapic_upds(mcfg);
+ mb_pre_fspm();
+}
diff --git a/src/soc/amd/sabrina/fsp_s_params.c b/src/soc/amd/sabrina/fsp_s_params.c
new file mode 100644
index 0000000..3f7aa9f
--- /dev/null
+++ b/src/soc/amd/sabrina/fsp_s_params.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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/sabrina/fw.cfg b/src/soc/amd/sabrina/fw.cfg
new file mode 100644
index 0000000..95dd4e1
--- /dev/null
+++ b/src/soc/amd/sabrina/fw.cfg
@@ -0,0 +1,42 @@
+# PSP fw config file
+
+# TODO: Check if this is still correct
+
+FIRMWARE_LOCATION 3rdparty/amd_blobs/cezanne/PSP
+
+# type file
+# PSP
+AMD_PUBKEY_FILE TypeId0x00_CezannePublicKey.tkn
+PSPBTLDR_FILE TypeId0x01_PspBootLoader_CZN.sbin
+PSPBTLDR_WL_FILE TypeId0x01_PspBootLoader_WL_CZN.sbin
+PSPSECUREOS_FILE TypeId0x02_PspOS_CZN.sbin
+PSPRCVR_FILE TypeId0x03_PspRecoveryBootLoader_CZN.sbin
+PSP_SMUFW1_SUB0_FILE TypeId0x08_SmuFirmware_CZN.csbin
+PSPSECUREDEBUG_FILE TypeId0x09_SecureDebugUnlockKey_CZN.stkn
+PSPTRUSTLETS_FILE TypeId0x0C_FtpmDrv_CZN.csbin
+PSP_SMUFW2_SUB0_FILE TypeId0x12_SmuFirmware2_CZN.csbin
+PSP_SEC_DEBUG_FILE TypeId0x13_PspEarlyUnlock_CZN.sbin
+PSP_HW_IPCFG_FILE TypeId0x20_HwIpCfg_CZN_A0.sbin
+PSP_IKEK_FILE TypeId0x21_PspIkek_CZN.bin
+PSP_SECG0_FILE TypeId0x24_SecurePolicyL0_CZN.sbin
+PSP_MP2FW0_FILE TypeId0x25_Mp2Fw_CZN.sbin
+AMD_DRIVER_ENTRIES TypeId0x28_PspSystemDriver_CZN.sbin
+PSP_KVM_ENGINE_DUMMY_FILE TypeId0x29_KvmEngineDummy.csbin
+PSP_S0I3_FILE TypeId0x2D_AgesaRunTimeDrv_CZN.sbin
+PSP_ABL0_FILE TypeId0x30_AgesaBootloaderU_CZN_LPDDR4.csbin
+VBIOS_BTLOADER_FILE TypeId0x3C_VbiosBootLoader_CZN.sbin
+SECURE_POLICY_L1_FILE TypeId0x45_SecurePolicyL1_CZN.sbin
+UNIFIEDUSB_FILE TypeId0x44_UnifiedUsb_CZN.sbin
+DRTMTA_FILE TypeId0x47_DrtmTA_CZN.sbin
+KEYDBBL_FILE TypeId0x50_KeyDbBl_CZN.sbin
+KEYDB_TOS_FILE TypeId0x51_KeyDbTos_CZN.sbin
+DMCUERAMDCN21_FILE TypeId0x58_DmcuEramDcn21.sbin
+DMCUINTVECTORSDCN21_FILE TypeId0x59_DmcuIntvectorsDcn21.sbin
+PSPBTLDR_AB_FILE TypeId0x73_PspBootLoader_AB_CZN.sbin
+
+# BDT
+PSP_PMUI_FILE1 TypeId0x64_Appb_CZN_1D_Lpddr4_Imem.csbin
+PSP_PMUD_FILE1 TypeId0x65_Appb_CZN_1D_Lpddr4_Dmem.csbin
+PSP_PMUI_FILE2 TypeId0x64_Appb_CZN_2D_Lpddr4_Imem.csbin
+PSP_PMUD_FILE2 TypeId0x65_Appb_CZN_2D_Lpddr4_Dmem.csbin
+PSP_MP2CFG_FILE MP2FWConfig.sbin
diff --git a/src/soc/amd/sabrina/gpio.c b/src/soc/amd/sabrina/gpio.c
new file mode 100644
index 0000000..a634398
--- /dev/null
+++ b/src/soc/amd/sabrina/gpio.c
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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_16, GEVENT_12 },
+ { GPIO_17, GEVENT_13 },
+ { GPIO_18, GEVENT_14 },
+ { GPIO_21, GEVENT_5 },
+ { GPIO_22, GEVENT_3 },
+ { GPIO_23, GEVENT_16 },
+ { GPIO_24, GEVENT_15 },
+ { GPIO_40, GEVENT_20 },
+ { GPIO_84, GEVENT_18 },
+ { GPIO_86, GEVENT_9 },
+ { GPIO_89, GEVENT_0 },
+ { GPIO_90, GEVENT_1 },
+ { GPIO_91, GEVENT_6 },
+ { GPIO_129, GEVENT_17 },
+};
+
+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/sabrina/graphics.c b/src/soc/amd/sabrina/graphics.c
new file mode 100644
index 0000000..b65ef88
--- /dev/null
+++ b/src/soc/amd/sabrina/graphics.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <device/pci_rom.h>
+#include <soc/cpu.h>
+#include <stdint.h>
+
+u32 map_oprom_vendev(u32 vendev)
+{
+ u32 new_vendev = vendev;
+
+ switch (vendev) {
+ case CEZANNE_VBIOS_VID_DID:
+ case BARCELO_VBIOS_VID_DID:
+ new_vendev = CEZANNE_VBIOS_VID_DID;
+ break;
+ }
+
+ return new_vendev;
+}
diff --git a/src/soc/amd/sabrina/i2c.c b/src/soc/amd/sabrina/i2c.c
new file mode 100644
index 0000000..2030f40
--- /dev/null
+++ b/src/soc/amd/sabrina/i2c.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <amdblocks/acpimmio.h>
+#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
+
+__weak void mainboard_i2c_override(int bus, uint32_t *pad_settings) { }
+
+void soc_i2c_misc_init(unsigned int bus, const struct dw_i2c_bus_config *cfg)
+{
+ const struct soc_amd_sabrina_config *config = config_of_soc();
+ uint32_t pad_ctrl;
+ int misc_reg;
+
+ if (bus >= ARRAY_SIZE(config->i2c_pad_ctrl_rx_sel))
+ return;
+
+ misc_reg = MISC_I2C0_PAD_CTRL + sizeof(uint32_t) * bus;
+ pad_ctrl = misc_read32(misc_reg);
+
+ pad_ctrl &= ~I2C_PAD_CTRL_NG_MASK;
+ pad_ctrl |= I2C_PAD_CTRL_NG_NORMAL;
+
+ pad_ctrl &= ~I2C_PAD_CTRL_RX_SEL_MASK;
+ pad_ctrl |= config->i2c_pad_ctrl_rx_sel[bus];
+
+ pad_ctrl &= ~I2C_PAD_CTRL_FALLSLEW_MASK;
+ pad_ctrl |= cfg->speed == I2C_SPEED_STANDARD ?
+ I2C_PAD_CTRL_FALLSLEW_STD : I2C_PAD_CTRL_FALLSLEW_LOW;
+ pad_ctrl |= I2C_PAD_CTRL_FALLSLEW_EN;
+
+ mainboard_i2c_override(bus, &pad_ctrl);
+ misc_write32(misc_reg, pad_ctrl);
+}
+
+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_sabrina_config *config = config_of_soc();
+
+ *num_buses = ARRAY_SIZE(config->i2c);
+ return config->i2c;
+}
diff --git a/src/soc/amd/sabrina/include/soc/acpi.h b/src/soc/amd/sabrina/include/soc/acpi.h
new file mode 100644
index 0000000..802d443
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/acpi.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_ACPI_H
+#define AMD_SABRINA_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_SABRINA_ACPI_H */
diff --git a/src/soc/amd/sabrina/include/soc/amd_pci_int_defs.h b/src/soc/amd/sabrina/include/soc/amd_pci_int_defs.h
new file mode 100644
index 0000000..5d28533
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/amd_pci_int_defs.h
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_AMD_PCI_INT_DEFS_H
+#define AMD_SABRINA_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-0x40 reserved */
+#define PIRQ_SATA 0x41 /* SATA */
+/* 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_I2C5 0x77 /* I2C5 */
+/* 0x78-0x7f reserved */
+
+#endif /* AMD_SABRINA_AMD_PCI_INT_DEFS_H */
diff --git a/src/soc/amd/sabrina/include/soc/aoac_defs.h b/src/soc/amd/sabrina/include/soc/aoac_defs.h
new file mode 100644
index 0000000..7554aa6
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/aoac_defs.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_AOAC_DEFS_H
+#define AMD_SABRINA_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_AMBA 17
+#define FCH_AOAC_DEV_ESPI 27
+#define FCH_AOAC_DEV_EMMC 28
+
+#endif /* AMD_SABRINA_AOAC_DEFS_H */
diff --git a/src/soc/amd/sabrina/include/soc/cppc.h b/src/soc/amd/sabrina/include/soc/cppc.h
new file mode 100644
index 0000000..7ae94bf
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/cppc.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_CPPC_H
+#define AMD_SABRINA_CPPC_H
+
+#include <types.h>
+#include <acpi/acpigen.h>
+
+struct cppc_config;
+void cpu_init_cppc_config(struct cppc_config *config, u32 version);
+void generate_cppc_entries(unsigned int core_id);
+
+#endif /* AMD_SABRINA_CPPC_H */
diff --git a/src/soc/amd/sabrina/include/soc/cpu.h b/src/soc/amd/sabrina/include/soc/cpu.h
new file mode 100644
index 0000000..57fda19
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/cpu.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_CPU_H
+#define AMD_SABRINA_CPU_H
+
+#define CEZANNE_A0_CPUID 0x00a50f00
+
+#define CEZANNE_VBIOS_VID_DID 0x10021638
+#define BARCELO_VBIOS_VID_DID 0x100215e7
+
+#endif /* AMD_SABRINA_CPU_H */
diff --git a/src/soc/amd/sabrina/include/soc/data_fabric.h b/src/soc/amd/sabrina/include/soc/data_fabric.h
new file mode 100644
index 0000000..87db4d3e
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/data_fabric.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_DATA_FABRIC_H
+#define AMD_SABRINA_DATA_FABRIC_H
+
+#include <types.h>
+
+/* SoC-specific bits in D18F0_MMIO_CTRL0 */
+#define DF_MMIO_NP BIT(16)
+
+#define IOMS0_FABRIC_ID 10
+
+#define NUM_NB_MMIO_REGS 8
+
+void data_fabric_set_mmio_np(void);
+
+#endif /* AMD_SABRINA_DATA_FABRIC_H */
diff --git a/src/soc/amd/sabrina/include/soc/espi.h b/src/soc/amd/sabrina/include/soc/espi.h
new file mode 100644
index 0000000..7edef44
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/espi.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_ESPI_H
+#define AMD_SABRINA_ESPI_H
+
+void espi_disable_lpc_ldrq(void);
+void espi_switch_to_spi2_pads(void);
+
+#endif /* AMD_SABRINA_ESPI_H */
diff --git a/src/soc/amd/sabrina/include/soc/gpio.h b/src/soc/amd/sabrina/include/soc/gpio.h
new file mode 100644
index 0000000..a4b2d1a
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/gpio.h
@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_GPIO_H
+#define AMD_SABRINA_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 272
+
+/* 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_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_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_84 84
+#define GPIO_85 85
+#define GPIO_86 86
+#define GPIO_87 87
+#define GPIO_88 88
+#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_108 108
+#define GPIO_109 109
+#define GPIO_113 113
+#define GPIO_114 114
+#define GPIO_115 115
+#define GPIO_116 116
+#define GPIO_120 120
+#define GPIO_121 121
+
+/* Bank 2: GPIO_128 - GPIO_191 */
+#define GPIO_129 129
+#define GPIO_130 130
+#define GPIO_131 131
+#define GPIO_132 132
+#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
+
+/* remote GPIO bank: GPIO_256 - GPIO_271 */
+#define GPIO_256 256
+#define GPIO_257 257
+#define GPIO_258 258
+#define GPIO_259 259
+#define GPIO_260 260
+#define GPIO_261 261
+#define GPIO_262 262
+#define GPIO_263 263
+#define GPIO_264 264
+#define GPIO_265 265
+#define GPIO_266 266
+#define GPIO_267 267
+#define GPIO_268 268
+#define GPIO_269 269
+#define GPIO_270 270
+#define GPIO_271 271
+
+/* 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_5_IOMUX_DEVSLP2 2
+#define GPIO_6_IOMUX_GPIOxx 0
+#define GPIO_6_IOMUX_DEVSLP1 1
+#define GPIO_6_IOMUX_DEVSLP3 2
+#define GPIO_7_IOMUX_GPIOxx 0
+#define GPIO_7_IOMUX_ACP_I2S_SDIN 1
+#define GPIO_8_IOMUX_GPIOxx 0
+#define GPIO_8_IOMUX_ACP_I2S_LRCLK 1
+#define GPIO_9_IOMUX_GPIOxx 0
+/* GPIO 9 IOMUX == 1 is reserved */
+#define GPIO_9_IOMUX_MDIO1_SCL 2
+#define GPIO_10_IOMUX_GPIOxx 0
+#define GPIO_10_IOMUX_S0A3 1
+/* GPIO 10 IOMUX == 2 is reserved */
+#define GPIO_10_IOMUX_MDIO0_SCL 3
+#define GPIO_11_IOMUX_GPIOxx 0
+#define GPIO_11_IOMUX_BLINK 1
+#define GPIO_12_IOMUX_LLB_L 0
+#define GPIO_12_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_SCL1 0
+#define GPIO_19_IOMUX_I2C3_SCL 1
+#define GPIO_19_IOMUX_GPIOxx 2
+#define GPIO_20_IOMUX_SDA1 0
+#define GPIO_20_IOMUX_I2C3_SDA 1
+#define GPIO_20_IOMUX_GPIOxx 2
+#define GPIO_21_IOMUX_LPC_PD_L 0
+#define GPIO_21_IOMUX_EMMC_CMD 1
+#define GPIO_21_IOMUX_GPIOxx 2
+#define GPIO_22_IOMUX_LPC_PME_L 0
+#define GPIO_22_IOMUX_EMMC_PWR_CTRL 1
+#define GPIO_22_IOMUX_GPIOxx 2
+#define GPIO_23_IOMUX_AC_PRES 0
+/* GPIO 23 IOMUX == 1 is reserved */
+#define GPIO_23_IOMUX_MDIO1_SDA 2
+#define GPIO_23_IOMUX_GPIOxx 3
+#define GPIO_24_IOMUX_USB_OC3_L 0
+#define GPIO_24_IOMUX_GPIOxx 1
+#define GPIO_26_IOMUX_PCIE_RST_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_ESPI_CS_L 1
+#define GPIO_31_IOMUX_GPIOxx 2
+#define GPIO_32_IOMUX_LPC_RST_L 0
+#define GPIO_32_IOMUX_SD_WP_L 1
+#define GPIO_32_IOMUX_GPIOxx 2
+#define GPIO_40_IOMUX_GPIOxx 0
+/* GPIO 40 IOMUX == 1 is reserved */
+#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_GPIOxx 0
+#define GPIO_68_IOMUX_EMMC_CD 1
+#define GPIO_69_IOMUX_GPIOxx 0
+#define GPIO_70_IOMUX_GPIOxx 0
+#define GPIO_70_IOMUX_EMMC_CLK 1
+#define GPIO_70_IOMUX_SD_CLK 2
+#define GPIO_74_IOMUX_LPCCLK0 0
+#define GPIO_74_IOMUX_EMMC_DATA4 1
+#define GPIO_74_IOMUX_GPIOxx 2
+#define GPIO_75_IOMUX_LPCCLK1 0
+#define GPIO_75_IOMUX_EMMC_DATA6 1
+#define GPIO_75_IOMUX_GPIOxx 2
+#define GPIO_76_IOMUX_SPI_ROM_GNT 0
+#define GPIO_76_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_LPC_SMI_L 0
+#define GPIO_86_IOMUX_GPIOxx 1
+#define GPIO_86_IOMUX_SPI_CLK 2
+#define GPIO_87_IOMUX_SERIRQ 0
+#define GPIO_87_IOMUX_EMMC_DATA7 1
+#define GPIO_87_IOMUX_GPIOxx 2
+#define GPIO_88_IOMUX_LPC_CLKRUN_L 0
+#define GPIO_88_IOMUX_EMMC_DATA5 1
+#define GPIO_88_IOMUX_GPIOxx 2
+#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_LAD0 0
+#define GPIO_104_IOMUX_SPI2_DO_ESPI2_D0 1
+#define GPIO_104_IOMUX_SD0_DATA0 2
+#define GPIO_104_IOMUX_GPIOxx 3
+#define GPIO_105_IOMUX_LAD1 0
+#define GPIO_105_IOMUX_SPI2_DI_ESPI2_D1 1
+#define GPIO_105_IOMUX_SD0_DATA1 2
+#define GPIO_105_IOMUX_GPIOxx 3
+#define GPIO_106_IOMUX_LAD2 0
+#define GPIO_106_IOMUX_SPI2_WP_L_ESPI2_D2 1
+#define GPIO_106_IOMUX_SD0_DATA2 2
+#define GPIO_106_IOMUX_GPIOxx 3
+#define GPIO_107_IOMUX_LAD3 0
+#define GPIO_107_IOMUX_SPI2_HOLD_L_ESPI2_D3 1
+#define GPIO_107_IOMUX_SD0_DATA3 2
+#define GPIO_107_IOMUX_GPIOxx 3
+#define GPIO_108_IOMUX_LDRQ0_L 0
+#define GPIO_108_IOMUX_ESPI_ALERT_D1 1
+#define GPIO_108_IOMUX_GPIOxx 2
+#define GPIO_109_IOMUX_LFRAME_L 0
+#define GPIO_109_IOMUX_EMMC_DS 1
+#define GPIO_109_IOMUX_GPIOxx 2
+#define GPIO_113_IOMUX_SCL0 0
+#define GPIO_113_IOMUX_I2C2_SCL 1
+#define GPIO_113_IOMUX_GPIOxx 2
+#define GPIO_114_IOMUX_SDA0 0
+#define GPIO_114_IOMUX_I2C2_SDA 1
+#define GPIO_114_IOMUX_GPIOxx 2
+#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_120_IOMUX_CLK_REQ5_L 0
+#define GPIO_120_IOMUX_GPIOxx 1
+#define GPIO_121_IOMUX_CLK_REQ6_L 0
+#define GPIO_121_IOMUX_GPIOxx 1
+#define GPIO_129_IOMUX_KBRST_L 0
+/* GPIO 129 IOMUX == 1 is reserved */
+#define GPIO_129_IOMUX_GPIOxx 2
+#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_140_IOMUX_GPIOxx 0
+#define GPIO_140_IOMUX_UART0_CTS_L 1
+#define GPIO_140_IOMUX_UART1_TXD 2
+#define GPIO_140_IOMUX_SD0_DATA1 3
+#define GPIO_141_IOMUX_GPIOxx 0
+#define GPIO_141_IOMUX_UART0_RXD 1
+#define GPIO_141_IOMUX_SD0_DATA3 2
+#define GPIO_142_IOMUX_GPIOxx 0
+#define GPIO_142_IOMUX_UART0_RTS_L 1
+#define GPIO_142_IOMUX_UART1_RXD 2
+#define GPIO_142_IOMUX_SD0_DATA0 3
+#define GPIO_143_IOMUX_GPIOxx 0
+#define GPIO_143_IOMUX_UART0_TXD 1
+#define GPIO_143_IOMUX_SD0_DATA2 2
+#define GPIO_144_IOMUX_GPIOxx 0
+/* GPIO 144 IOMUX == 1 is reserved */
+#define GPIO_144_IOMUX_UART0_INTR 2
+#define GPIO_145_IOMUX_I2C0_SCL 0
+#define GPIO_145_IOMUX_GPIOxx 1
+#define GPIO_146_IOMUX_I2C0_SDA 0
+#define GPIO_146_IOMUX_GPIOxx 1
+#define GPIO_147_IOMUX_I2C1_SCL 0
+#define GPIO_147_IOMUX_GPIOxx 1
+#define GPIO_148_IOMUX_I2C1_SDA 0
+#define GPIO_148_IOMUX_GPIOxx 1
+
+/* Remote GPIOs */
+#define GPIO_256_IOMUX_GPIOxx 1
+#define GPIO_257_IOMUX_GPIOxx 1
+#define GPIO_258_IOMUX_GPIOxx 1
+#define GPIO_259_IOMUX_GPIOxx 1
+#define GPIO_260_IOMUX_GPIOxx 1
+#define GPIO_261_IOMUX_GPIOxx 1
+#define GPIO_262_IOMUX_GPIOxx 1
+#define GPIO_263_IOMUX_GPIOxx 1
+#define GPIO_264_IOMUX_GPIOxx 1
+#define GPIO_265_IOMUX_GPIOxx 1
+#define GPIO_266_IOMUX_GPIOxx 1
+#define GPIO_267_IOMUX_GPIOxx 1
+#define GPIO_268_IOMUX_GPIOxx 1
+#define GPIO_269_IOMUX_GPIOxx 1
+#define GPIO_270_IOMUX_GPIOxx 1
+#define GPIO_271_IOMUX_GPIOxx 1
+
+#endif /* AMD_SABRINA_GPIO_H */
diff --git a/src/soc/amd/sabrina/include/soc/i2c.h b/src/soc/amd/sabrina/include/soc/i2c.h
new file mode 100644
index 0000000..950b105
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/i2c.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_I2C_H
+#define AMD_SABRINA_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_SABRINA_I2C_H */
diff --git a/src/soc/amd/sabrina/include/soc/iomap.h b/src/soc/amd/sabrina/include/soc/iomap.h
new file mode 100644
index 0000000..7b5f784
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/iomap.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_IOMAP_H
+#define AMD_SABRINA_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
+
+#if CONFIG(HPET_ADDRESS_OVERRIDE)
+#error HPET address override is not allowed and must be fixed at 0xfed00000
+#endif
+#define HPET_BASE_ADDRESS 0xfed00000
+
+/* 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_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_SABRINA_IOMAP_H */
diff --git a/src/soc/amd/sabrina/include/soc/lpc.h b/src/soc/amd/sabrina/include/soc/lpc.h
new file mode 100644
index 0000000..d5e5712
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/lpc.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_LPC_H
+#define AMD_SABRINA_LPC_H
+
+/* LPC_MISC_CONTROL_BITS at D14F3x078 */
+/* The definitions of bits 9 and 10 are swapped on Picasso and older compared to Renoir/Cezanne
+ and newer, so we need to keep those in a SoC-specific header file. */
+#define LPC_LDRQ0_PU_EN BIT(10)
+#define LPC_LDRQ0_PD_EN BIT(9)
+
+#define SPIROM_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_SABRINA_LPC_H */
diff --git a/src/soc/amd/sabrina/include/soc/msr.h b/src/soc/amd/sabrina/include/soc/msr.h
new file mode 100644
index 0000000..48c2fd1
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/msr.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_MSR_H
+#define AMD_SABRINA_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
+
+#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_SABRINA_MSR_H */
diff --git a/src/soc/amd/sabrina/include/soc/nvs.h b/src/soc/amd/sabrina/include/soc/nvs.h
new file mode 100644
index 0000000..95b7392
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/nvs.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Check if this is still correct */
+
+/*
+ * NOTE: The layout of the global_nvs structure below must match the layout
+ * in soc/soc/amd/sabrina/acpi/globalnvs.asl !!!
+ *
+ */
+
+#ifndef AMD_SABRINA_NVS_H
+#define AMD_SABRINA_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_SABRINA_NVS_H */
diff --git a/src/soc/amd/sabrina/include/soc/pci_devs.h b/src/soc/amd/sabrina/include/soc/pci_devs.h
new file mode 100644
index 0000000..8e76792
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/pci_devs.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_PCI_DEVS_H
+#define AMD_SABRINA_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 up to 3 ports */
+#define PCIE_GPP_BRIDGE_1_DEV 0x1
+
+#define PCIE_GPP_1_0_FUNC 1
+#define PCIE_GPP_1_0_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_0_FUNC)
+#define SOC_GPP_1_0_DEV _SOC_DEV(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_0_FUNC)
+
+#define PCIE_GPP_1_1_FUNC 2
+#define PCIE_GPP_1_1_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_1_FUNC)
+#define SOC_GPP_1_1_DEV _SOC_DEV(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_1_FUNC)
+
+#define PCIE_GPP_1_2_FUNC 3
+#define PCIE_GPP_1_2_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_2_FUNC)
+#define SOC_GPP_1_2_DEV _SOC_DEV(PCIE_GPP_BRIDGE_1_DEV, PCIE_GPP_1_2_FUNC)
+
+/* PCIe GPP Bridge device 2 with up to 7 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)
+
+#define PCIE_GPP_2_6_FUNC 7
+#define PCIE_GPP_2_6_DEVFN PCI_DEVFN(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_6_FUNC)
+#define SOC_GPP_2_6_DEV _SOC_DEV(PCIE_GPP_BRIDGE_2_DEV, PCIE_GPP_2_6_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 SATA0_DEV 0x0
+#define SATA0_FUNC 0
+#define SATA0_DEVFN PCI_DEVFN(SATA0_DEV, SATA0_FUNC)
+
+#define SATA1_DEV 0x0
+#define SATA1_FUNC 1
+#define SATA1_DEVFN PCI_DEVFN(SATA1_DEV, SATA1_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)
+
+/* 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_SABRINA_PCI_DEVS_H */
diff --git a/src/soc/amd/sabrina/include/soc/platform_descriptors.h b/src/soc/amd/sabrina/include/soc/platform_descriptors.h
new file mode 100644
index 0000000..c8e0fd0
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/platform_descriptors.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_PLATFORM_DESCRIPTORS_H
+#define AMD_SABRINA_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(void);
+
+#endif /* AMD_SABRINA_PLATFORM_DESCRIPTORS_H */
diff --git a/src/soc/amd/sabrina/include/soc/psp_transfer.h b/src/soc/amd/sabrina/include/soc/psp_transfer.h
new file mode 100644
index 0000000..6055599
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/psp_transfer.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_PSP_TRANSFER_H
+#define AMD_SABRINA_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. */
+void verify_psp_transfer_buf(void);
+/* Display the transfer block's PSP_info data */
+void show_psp_transfer_info(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_SABRINA_PSP_TRANSFER_H */
diff --git a/src/soc/amd/sabrina/include/soc/psp_verstage_addr.h b/src/soc/amd/sabrina/include/soc/psp_verstage_addr.h
new file mode 100644
index 0000000..6636ea1
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/psp_verstage_addr.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_PSP_VERSTAGE_ADDR_H
+#define AMD_SABRINA_PSP_VERSTAGE_ADDR_H
+
+/*
+ * Start of available space is 0x36000 and this is where the
+ * header for the user app (verstage) must be mapped.
+ * Size is 0x14000 bytes
+ */
+#define PSP_SRAM_START 0x26000
+#define PSP_SRAM_SIZE (148K)
+#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 0x41000
+#define PSP_VERSTAGE_STACK_SIZE (40K)
+
+#endif /* AMD_SABRINA_PSP_VERSTAGE_ADDR_H */
diff --git a/src/soc/amd/sabrina/include/soc/smi.h b/src/soc/amd/sabrina/include/soc/smi.h
new file mode 100644
index 0000000..056ec31
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/smi.h
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_SMI_H
+#define AMD_SABRINA_SMI_H
+
+#include <types.h>
+
+#define SMI_GEVENTS 24
+#define SCIMAPS 59 /* 0..58 */
+#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_LPCPME 3
+#define SMITYPE_G_AGPIO4 4
+#define SMITYPE_G_LPCPD 5
+#define SMITYPE_G_SPKR 6
+#define SMITYPE_G_AGPIO5 7
+#define SMITYPE_G_WAKE_L 8
+#define SMITYPE_G_LPC_SMI_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_ESPI_RESET_L 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_LPCPME) \
+ | (1 << SMITYPE_G_AGPIO4) \
+ | (1 << SMITYPE_G_LPCPD) \
+ | (1 << SMITYPE_G_SPKR) \
+ | (1 << SMITYPE_G_AGPIO5) \
+ | (1 << SMITYPE_G_WAKE_L) \
+ | (1 << SMITYPE_G_LPC_SMI_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_ESPI_RESET_L) \
+ | (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_WLAN_WLAN_PME 37
+#define SMITYPE_WLAN_BT_PME 38
+#define SMITYPE_AZPME 39
+#define SMITYPE_USB_PD_I2C4 40
+#define SMITYPE_GPIO_CTL 41
+/* 42 Reserved */
+#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-63 Reserved */
+#define SMITYPE_KB_RESET 64
+#define SMITYPE_SLP_TYP 65
+#define SMITYPE_AL2H_ACPI 66
+/* 67-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
+/* 145 Reserved */
+#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_SABRINA_SMI_H */
diff --git a/src/soc/amd/sabrina/include/soc/smu.h b/src/soc/amd/sabrina/include/soc/smu.h
new file mode 100644
index 0000000..e4b8e15
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/smu.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_SMU_H
+#define AMD_SABRINA_SMU_H
+
+/* SMU mailbox register offsets in SMN */
+#define SMN_SMU_MESG_ID 0x3b10528
+#define SMN_SMU_MESG_RESP 0x3b10564
+#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_SABRINA_SMU_H */
diff --git a/src/soc/amd/sabrina/include/soc/southbridge.h b/src/soc/amd/sabrina/include/soc/southbridge.h
new file mode 100644
index 0000000..4ce58dd
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/southbridge.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_SOUTHBRIDGE_H
+#define AMD_SABRINA_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_ESPI_CS_USE_DATA2 BIT(16)
+#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_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_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 */
+#define MISC_I2C0_PAD_CTRL 0xd8
+#define MISC_I2C1_PAD_CTRL 0xdc
+#define MISC_I2C2_PAD_CTRL 0xe0
+#define MISC_I2C3_PAD_CTRL 0xe4
+#define I2C_PAD_CTRL_NG_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define I2C_PAD_CTRL_NG_NORMAL 0xc
+#define I2C_PAD_CTRL_RX_SEL_MASK (BIT(4) | BIT(5))
+#define I2C_PAD_CTRL_RX_SHIFT 4
+#define I2C_PAD_CTRL_RX_SEL_OFF (0 << I2C_PAD_CTRL_RX_SHIFT)
+#define I2C_PAD_CTRL_RX_SEL_3_3V (1 << I2C_PAD_CTRL_RX_SHIFT)
+#define I2C_PAD_CTRL_RX_SEL_1_8V (3 << I2C_PAD_CTRL_RX_SHIFT)
+#define I2C_PAD_CTRL_PULLDOWN_EN BIT(6)
+#define I2C_PAD_CTRL_FALLSLEW_MASK (BIT(7) | BIT(8))
+#define I2C_PAD_CTRL_FALLSLEW_SHIFT 7
+#define I2C_PAD_CTRL_FALLSLEW_STD (0 << I2C_PAD_CTRL_FALLSLEW_SHIFT)
+#define I2C_PAD_CTRL_FALLSLEW_LOW (1 << I2C_PAD_CTRL_FALLSLEW_SHIFT)
+#define I2C_PAD_CTRL_FALLSLEW_EN BIT(9)
+#define I2C_PAD_CTRL_SPIKE_RC_EN BIT(10)
+#define I2C_PAD_CTRL_SPIKE_RC_SEL BIT(11) /* 0 = 50ns, 1 = 20ns */
+#define I2C_PAD_CTRL_CAP_DOWN BIT(12)
+#define I2C_PAD_CTRL_CAP_UP BIT(13)
+#define I2C_PAD_CTRL_RES_DOWN BIT(14)
+#define I2C_PAD_CTRL_RES_UP BIT(15)
+#define I2C_PAD_CTRL_BIAS_CRT_EN BIT(16)
+#define I2C_PAD_CTRL_SPARE0 BIT(17)
+#define I2C_PAD_CTRL_SPARE1 BIT(18)
+
+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);
+
+/* Allow the board to change the default I2C pad configuration */
+void mainboard_i2c_override(int bus, uint32_t *pad_settings);
+
+#endif /* AMD_SABRINA_SOUTHBRIDGE_H */
diff --git a/src/soc/amd/sabrina/include/soc/uart.h b/src/soc/amd/sabrina/include/soc/uart.h
new file mode 100644
index 0000000..a28c57b
--- /dev/null
+++ b/src/soc/amd/sabrina/include/soc/uart.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef AMD_SABRINA_UART_H
+#define AMD_SABRINA_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_SABRINA_UART_H */
diff --git a/src/soc/amd/sabrina/mca.c b/src/soc/amd/sabrina/mca.c
new file mode 100644
index 0000000..b2f5e96
--- /dev/null
+++ b/src/soc/amd/sabrina/mca.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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] = "L3 cache unit",
+ [12] = "L3 cache unit",
+ [13] = "L3 cache unit",
+ [14] = "L3 cache unit",
+ [15] = "",
+ [16] = "",
+ [17] = "UMC",
+ [18] = "UMC",
+ [19] = "CS",
+ [20] = "CS",
+ [21] = "",
+ [22] = "",
+ [23] = "",
+ [24] = "",
+ [25] = "",
+ [26] = "",
+ [27] = "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/sabrina/preload.c b/src/soc/amd/sabrina/preload.c
new file mode 100644
index 0000000..ae37237
--- /dev/null
+++ b/src/soc/amd/sabrina/preload.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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/sabrina/psp_verstage/Makefile.inc b/src/soc/amd/sabrina/psp_verstage/Makefile.inc
new file mode 100644
index 0000000..27539da
--- /dev/null
+++ b/src/soc/amd/sabrina/psp_verstage/Makefile.inc
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# TODO: Check if this is still correct
+
+verstage-generic-ccopts += -I$(src)/soc/amd/sabrina/psp_verstage/include
+verstage-generic-ccopts += -I$(src)/vendorcode/amd/fsp/sabrina/include
+
+verstage-generic-ccopts += -I$(src)/soc/amd/common/psp_verstage/include
+
+subdirs-$(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK) += ../../common/psp_verstage
+
+verstage-y += svc.c
+verstage-y += chipset.c
+
+verstage-y += $(top)/src/vendorcode/amd/fsp/sabrina/bl_uapp/bl_uapp_startup.S
+verstage-y += $(top)/src/vendorcode/amd/fsp/sabrina/bl_uapp/bl_uapp_end.S
diff --git a/src/soc/amd/sabrina/psp_verstage/chipset.c b/src/soc/amd/sabrina/psp_verstage/chipset.c
new file mode 100644
index 0000000..e82a132
--- /dev/null
+++ b/src/soc/amd/sabrina/psp_verstage/chipset.c
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <bl_uapp/bl_syscall_public.h>
+#include <psp_verstage.h>
+
+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 ef_table->bios3_entry;
+}
+
+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;
+}
diff --git a/src/soc/amd/sabrina/psp_verstage/svc.c b/src/soc/amd/sabrina/psp_verstage/svc.c
new file mode 100644
index 0000000..bf1a106
--- /dev/null
+++ b/src/soc/amd/sabrina/psp_verstage/svc.c
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include "svc.h"
+
+#include <assert.h>
+#include <bl_uapp/bl_syscall_public.h>
+#include <psp_verstage.h>
+#include <stddef.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;
+ SVC_CALL1(SVC_DEBUG_PRINT, (uint32_t)string, unused);
+}
+
+void svc_debug_print_ex(uint32_t dword0,
+ uint32_t dword1, uint32_t dword2, uint32_t dword3)
+{
+ uint32_t unused = 0;
+ SVC_CALL4(SVC_DEBUG_PRINT_EX, dword0, dword1, dword2, dword3, unused);
+}
+
+uint32_t svc_get_boot_mode(uint32_t *boot_mode)
+{
+ uint32_t retval = 0;
+ SVC_CALL1(SVC_GET_BOOT_MODE, boot_mode, retval);
+ return retval;
+}
+
+void svc_delay_in_usec(uint32_t delay)
+{
+ uint32_t unused = 0;
+ SVC_CALL1(SVC_DELAY_IN_MICRO_SECONDS, delay, unused);
+}
+
+uint32_t svc_get_spi_rom_info(struct spirom_info *spi_rom_info)
+{
+ uint32_t retval = 0;
+ SVC_CALL1(SVC_GET_SPI_INFO, (uint32_t)spi_rom_info, 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;
+ assert(io_device < FCH_IO_DEVICE_END);
+ SVC_CALL4(SVC_MAP_FCH_IO_DEVICE, io_device, arg1, arg2,
+ (uint32_t)io_device_axi_addr, retval);
+ return retval;
+}
+
+uint32_t svc_unmap_fch_dev(enum fch_io_device io_device, void *io_device_axi_addr)
+{
+ uint32_t retval = 0;
+ assert(io_device < FCH_IO_DEVICE_END);
+ SVC_CALL2(SVC_UNMAP_FCH_IO_DEVICE, (uint32_t)io_device,
+ (uint32_t)io_device_axi_addr, 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;
+ SVC_CALL3(SVC_MAP_SPIROM_DEVICE, spi_rom_addr, size,
+ (uint32_t)spi_rom_axi_addr, retval);
+ return retval;
+}
+
+uint32_t svc_unmap_spi_rom(void *spi_rom_addr)
+{
+ uint32_t retval = 0;
+ SVC_CALL1(SVC_UNMAP_SPIROM_DEVICE, (uint32_t)spi_rom_addr, retval);
+ return retval;
+}
+
+uint32_t svc_update_psp_bios_dir(uint32_t *psp_dir_offset,
+ uint32_t *bios_dir_offset)
+{
+ uint32_t retval = 0;
+ SVC_CALL2(SVC_UPDATE_PSP_BIOS_DIR, (uint32_t)psp_dir_offset,
+ (uint32_t)bios_dir_offset, retval);
+ return retval;
+}
+
+uint32_t svc_save_uapp_data(void *address, uint32_t size)
+{
+ uint32_t retval = 0;
+ SVC_CALL2(SVC_COPY_DATA_FROM_UAPP, (uint32_t)address, size, retval);
+ return retval;
+}
+
+uint32_t svc_read_timer_val(enum psp_timer_type type, uint64_t *counter_value)
+{
+ unsigned int retval = 0;
+ assert(type < PSP_TIMER_TYPE_MAX);
+ SVC_CALL2(SVC_READ_TIMER_VAL, type, counter_value, retval);
+ return retval;
+}
+
+uint32_t svc_reset_system(enum reset_type reset_type)
+{
+ unsigned int retval = 0;
+ assert(reset_type < RESET_TYPE_MAX);
+ SVC_CALL1(SVC_RESET_SYSTEM, reset_type, retval);
+ return retval;
+}
+
+uint32_t svc_crypto_sha(struct sha_generic_data *sha_op, enum sha_operation_mode sha_mode)
+{
+ uint32_t retval = 0;
+ SVC_CALL2(SVC_SHA, sha_op, sha_mode, retval);
+ return retval;
+}
+
+uint32_t svc_modexp(struct mod_exp_params *mod_exp_param)
+{
+ uint32_t retval = 0;
+ SVC_CALL1(SVC_MODEXP, mod_exp_param, retval);
+ return retval;
+}
+
+uint32_t svc_ccp_dma(uint32_t spi_rom_offset, void *dest, uint32_t size)
+{
+ uint32_t retval = 0;
+ SVC_CALL3(SVC_CCP_DMA, spi_rom_offset, dest, size, retval);
+ return retval;
+}
diff --git a/src/soc/amd/sabrina/psp_verstage/svc.h b/src/soc/amd/sabrina/psp_verstage/svc.h
new file mode 100644
index 0000000..86e533a
--- /dev/null
+++ b/src/soc/amd/sabrina/psp_verstage/svc.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#ifndef PSP_VERSTAGE_SVC_H
+#define PSP_VERSTAGE_SVC_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 */)
+
+#endif /* PSP_VERSTAGE_SVC_H */
diff --git a/src/soc/amd/sabrina/reset.c b/src/soc/amd/sabrina/reset.c
new file mode 100644
index 0000000..90fedda
--- /dev/null
+++ b/src/soc/amd/sabrina/reset.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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)
+{
+ /* Warm resets are not supported and must be executed as cold */
+ pm_write16(PWR_RESET_CFG, pm_read16(PWR_RESET_CFG) |
+ TOGGLE_ALL_PWR_GOOD);
+ outb(RST_CPU | SYS_RST, RST_CNT);
+}
+
+void do_board_reset(void)
+{
+ do_cold_reset();
+}
diff --git a/src/soc/amd/sabrina/romstage.c b/src/soc/amd/sabrina/romstage.c
new file mode 100644
index 0000000..91f80ef
--- /dev/null
+++ b/src/soc/amd/sabrina/romstage.c
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 <timestamp.h>
+
+asmlinkage void car_stage_entry(void)
+{
+ timestamp_add_now(TS_START_ROMSTAGE);
+
+ post_code(0x40);
+
+ console_init();
+
+ post_code(0x41);
+
+ /* 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/sabrina/root_complex.c b/src/soc/amd/sabrina/root_complex.c
new file mode 100644
index 0000000..837488e
--- /dev/null
+++ b/src/soc/amd/sabrina/root_complex.c
@@ -0,0 +1,229 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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 4
+
+struct dptc_input {
+ uint16_t size;
+ struct alib_dptc_param params[DPTC_TOTAL_UPDATE_PARAMS];
+} __packed;
+
+#define DPTC_INPUTS(_thermctllmit, _sustained, _fast, _slow) \
+ { \
+ .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, \
+ }, \
+ }, \
+ }
+
+/*
+ *
+ * +--------------------------------+
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * 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 |
+ * | (86KiB) |
+ * +--------------------------------+
+ * | 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 (64KiB) |
+ * +--------------------------------+ 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;
+
+ /* 0x0 - 0x9ffff */
+ ram_resource(dev, idx++, 0, 0xa0000 / KiB);
+
+ /* 0xa0000 - 0xbffff: legacy VGA */
+ mmio_resource(dev, idx++, 0xa0000 / KiB, 0x20000 / KiB);
+
+ /* 0xc0000 - 0xfffff: Option ROM */
+ reserved_ram_resource(dev, idx++, 0xc0000 / KiB, 0x40000 / KiB);
+
+ /* 1MiB - bottom of DRAM reserved for early coreboot usage */
+ ram_resource(dev, idx++, (1 * MiB) / KiB,
+ (early_reserved_dram_start - (1 * MiB)) / KiB);
+
+ /* DRAM reserved for early coreboot usage */
+ reserved_ram_resource(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(dev, idx++, early_reserved_dram_end / KiB,
+ (mem_usable - early_reserved_dram_end) / KiB);
+
+ mmconf_resource(dev, MMIO_CONF_BASE);
+
+ 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(dev, idx++, res->addr / KiB, res->length / KiB);
+ else if (res->type == EFI_RESOURCE_MEMORY_RESERVED)
+ reserved_ram_resource(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, GNB_IO_APIC_ADDR);
+ 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_sabrina_config *config = config_of_soc();
+
+ if (!config->dptc_enable)
+ return;
+
+ 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);
+ struct dptc_input tablet_mode_input = DPTC_INPUTS(
+ config->thermctl_limit_tablet_mode_degreeC,
+ config->sustained_power_limit_tablet_mode_mW,
+ config->fast_ppt_limit_tablet_mode_mW,
+ config->slow_ppt_limit_tablet_mode_mW);
+
+ acpigen_write_alib_dptc((uint8_t *)&default_input, sizeof(default_input),
+ (uint8_t *)&tablet_mode_input, sizeof(tablet_mode_input));
+}
+
+static void root_complex_fill_ssdt(const struct device *device)
+{
+ acpi_fill_root_complex_tom(device);
+ 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_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_17H_MODEL_606F_NB,
+};
diff --git a/src/soc/amd/sabrina/smihandler.c b/src/soc/amd/sabrina/smihandler.c
new file mode 100644
index 0000000..9fda2f9
--- /dev/null
+++ b/src/soc/amd/sabrina/smihandler.c
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TODO: Check if this is still correct */
+
+#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);
+}
+
+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/sabrina/smu.c b/src/soc/amd/sabrina/smu.c
new file mode 100644
index 0000000..dd83713
--- /dev/null
+++ b/src/soc/amd/sabrina/smu.c
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <console/console.h>
+#include <amdblocks/smu.h>
+#include <soc/smu.h>
+
+/*
+ * 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/sabrina/uart.c b/src/soc/amd/sabrina/uart.c
new file mode 100644
index 0000000..c48c3da
--- /dev/null
+++ b/src/soc/amd/sabrina/uart.c
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#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),
+ } },
+};
+
+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)
+{
+ write16((void *)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";
+ 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;
+ 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(dev, 0, dev->path.mmio.addr / KiB, 4);
+}
+
+struct device_operations sabrina_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/sabrina/xhci.c b/src/soc/amd/sabrina/xhci.c
new file mode 100644
index 0000000..c95b5f9
--- /dev/null
+++ b/src/soc/amd/sabrina/xhci.c
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Check if this is still correct */
+
+#include <amdblocks/gpio.h>
+#include <amdblocks/smi.h>
+#include <bootstate.h>
+#include <device/device.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
+ }
+};
+
+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->bus->dev->path.pci.devfn != PCIE_ABC_A_DEVFN)
+ return CB_ERR_ARG;
+
+ if (dev->path.type != DEVICE_PATH_PCI)
+ return CB_ERR_ARG;
+
+ if (dev->path.pci.devfn == XHCI0_DEVFN)
+ *gpe = xhci_sci_sources[0].gpe;
+ else if (dev->path.pci.devfn == XHCI1_DEVFN)
+ *gpe = xhci_sci_sources[1].gpe;
+ else
+ return CB_ERR_ARG;
+
+ return CB_SUCCESS;
+}
+
+static void configure_xhci_sci(void *unused)
+{
+ gpe_configure_sci(xhci_sci_sources, ARRAY_SIZE(xhci_sci_sources));
+}
+
+BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_ENTRY, configure_xhci_sci, NULL);