summaryrefslogtreecommitdiff
path: root/src/mainboard
diff options
context:
space:
mode:
authorMartin Roth <martin.roth@amd.corp-partner.google.com>2022-10-06 16:29:07 -0600
committerMartin Roth <martin.roth@amd.corp-partner.google.com>2022-10-10 21:50:34 +0000
commit3c963d9e88240eaf4ea6eff8af7590d7c473acd4 (patch)
tree6004817a9b79d0c3f3f54d6eb7f6ba8a016bfc1d /src/mainboard
parentf225d761ba1ae6dea878c33668b590fe94293fe5 (diff)
mb/amd/birman: Add framework for morgana crb birman
birman is the reference board for the morgana SoC. It needs to be updated to match the actual board design as well. Signed-off-by: Martin Roth <martin.roth@amd.corp-partner.google.com> Change-Id: I4b16854c954949217a76c3d4f04ddc4001f64337 Reviewed-on: https://review.coreboot.org/c/coreboot/+/68196 Reviewed-by: Fred Reitberger <reitbergerfred@gmail.com> Reviewed-by: Marshall Dawson <marshalldawson3rd@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/mainboard')
-rw-r--r--src/mainboard/amd/birman/Kconfig108
-rw-r--r--src/mainboard/amd/birman/Kconfig.name2
-rw-r--r--src/mainboard/amd/birman/Makefile.inc42
-rw-r--r--src/mainboard/amd/birman/board.fmd8
-rw-r--r--src/mainboard/amd/birman/board_info.txt1
-rw-r--r--src/mainboard/amd/birman/bootblock.c18
-rw-r--r--src/mainboard/amd/birman/chromeos.c21
-rw-r--r--src/mainboard/amd/birman/chromeos.fmd34
-rw-r--r--src/mainboard/amd/birman/devicetree.cb226
-rw-r--r--src/mainboard/amd/birman/dsdt.asl16
-rw-r--r--src/mainboard/amd/birman/early_gpio.c16
-rw-r--r--src/mainboard/amd/birman/ec.c67
-rw-r--r--src/mainboard/amd/birman/ec.h8
-rw-r--r--src/mainboard/amd/birman/gpio.c20
-rw-r--r--src/mainboard/amd/birman/gpio.h9
-rw-r--r--src/mainboard/amd/birman/mainboard.c106
-rw-r--r--src/mainboard/amd/birman/port_descriptors.c130
17 files changed, 832 insertions, 0 deletions
diff --git a/src/mainboard/amd/birman/Kconfig b/src/mainboard/amd/birman/Kconfig
new file mode 100644
index 0000000000..46e5e31bd1
--- /dev/null
+++ b/src/mainboard/amd/birman/Kconfig
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+if BOARD_AMD_BIRMAN
+
+config BOARD_SPECIFIC_OPTIONS
+ def_bool y
+ select BOARD_ROMSIZE_KB_16384
+ select EC_ACPI
+ select SOC_AMD_MORGANA
+ select SOC_AMD_COMMON_BLOCK_USE_ESPI
+ select AMD_SOC_CONSOLE_UART
+ select MAINBOARD_HAS_CHROMEOS
+ select PCIEXP_ASPM
+ select PCIEXP_CLK_PM
+ select PCIEXP_COMMON_CLOCK
+ select PCIEXP_L1_SUB_STATE
+ select SOC_AMD_COMMON_BLOCK_ESPI_RETAIN_PORT80_EN
+
+config FMDFILE
+ default "src/mainboard/amd/birman/chromeos.fmd" if CHROMEOS
+ default "src/mainboard/amd/birman/board.fmd"
+
+config MAINBOARD_DIR
+ default "amd/birman"
+
+config MAINBOARD_PART_NUMBER
+ default "BIRMAN"
+
+config AMD_FWM_POSITION_INDEX
+ int
+ default 3 if CHROMEOS
+ help
+ TODO: might need to be adapted for better placement of files in cbfs
+
+config BIRMAN_HAVE_MCHP_FW
+ bool "Have Microchip EC firmware?"
+ default n
+
+config BIRMAN_MCHP_SIG_FILE
+ string "Microchip EC signature file"
+ depends on BIRMAN_HAVE_MCHP_FW
+ default "3rdparty/blobs/mainboard/amd/birman/EC_birman_sig.bin"
+ help
+ The EC sig blob is the first 4kBytes of the firmware image.
+ The first 4 bytes form a pointer (with CRC) to where the EC firmware
+ is located
+
+config BIRMAN_MCHP_FW_FILE
+ string "Microchip EC firmware file"
+ depends on BIRMAN_HAVE_MCHP_FW
+ default "3rdparty/blobs/mainboard/amd/birman/EC_birman.bin"
+ help
+ The EC firmware blob is at the BIRMAN_MCHP_FW_OFFSET offset of the
+ firmware image.
+
+config BIRMAN_MCHP_FW_OFFSET
+ hex
+ depends on BIRMAN_HAVE_MCHP_FW
+ default 0xB80000
+ help
+ The EC firmware blob defaults to the 4MByte offset of the firmware
+ image. If this offset needs to change, a new signature block must be
+ generated with the updated offset.
+
+config VBOOT
+ select VBOOT_NO_BOARD_SUPPORT
+ select VBOOT_SEPARATE_VERSTAGE
+ select VBOOT_STARTS_IN_BOOTBLOCK
+
+config VBOOT_VBNV_OFFSET
+ hex
+ default 0x2A
+
+config RO_REGION_ONLY
+ string
+ depends on VBOOT_SLOTS_RW_AB || VBOOT_SLOTS_RW_A
+ # Add the EFS and EC to the RO region only
+ # This is a birman-specific override of soc/amd/morgana/Kconfig
+ default "apu/amdfw apu/ecfw"
+
+config CHROMEOS
+ # Use default libpayload config
+ select LP_DEFCONFIG_OVERRIDE if PAYLOAD_DEPTHCHARGE
+ # We don't have recovery buttons, so we can't manually enable devmode.
+ select GBB_FLAG_FORCE_DEV_SWITCH_ON
+
+if !EM100 # EM100 defaults in soc/amd/common/blocks/spi/Kconfig
+config EFS_SPI_READ_MODE
+ default 3 # Quad IO (1-1-4)
+
+config EFS_SPI_SPEED
+ default 0 # 66MHz
+
+config EFS_SPI_MICRON_FLAG
+ default 0
+
+config NORMAL_READ_SPI_SPEED
+ default 1 # 33MHz
+
+config ALT_SPI_SPEED
+ default 1 # 33MHz
+
+config TPM_SPI_SPEED
+ default 1 # 33MHz
+
+endif # !EM100
+
+endif # BOARD_AMD_BIRMAN
diff --git a/src/mainboard/amd/birman/Kconfig.name b/src/mainboard/amd/birman/Kconfig.name
new file mode 100644
index 0000000000..14c117a29d
--- /dev/null
+++ b/src/mainboard/amd/birman/Kconfig.name
@@ -0,0 +1,2 @@
+config BOARD_AMD_BIRMAN
+ bool "Birman"
diff --git a/src/mainboard/amd/birman/Makefile.inc b/src/mainboard/amd/birman/Makefile.inc
new file mode 100644
index 0000000000..b0466e7b04
--- /dev/null
+++ b/src/mainboard/amd/birman/Makefile.inc
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+bootblock-y += bootblock.c
+bootblock-y += early_gpio.c
+bootblock-y += ec.c
+
+romstage-y += port_descriptors.c
+
+ramstage-y += chromeos.c
+ramstage-y += gpio.c
+
+ifneq ($(wildcard $(MAINBOARD_BLOBS_DIR)/APCB_Updatable.bin),)
+APCB_SOURCES = $(MAINBOARD_BLOBS_DIR)/APCB_Updatable.bin
+APCB_SOURCES_RECOVERY = $(MAINBOARD_BLOBS_DIR)/APCB_DefaultRecovery.bin
+else
+$(info APCB sources not found. Skipping APCB. The resulting image won't boot.)
+endif
+
+ifeq ($(CONFIG_BIRMAN_HAVE_MCHP_FW),y)
+$(call add_intermediate, add_mchp_fw)
+ $(CBFSTOOL) $(obj)/coreboot.pre write -r EC -f $(CONFIG_BIRMAN_MCHP_SIG_FILE) --fill-upward
+
+# calculate the absolute position from the config offset
+BIRMAN_EC_POSITION=$(call int-add, \
+ $(call int-subtract, 0xffffffff \
+ $(CONFIG_ROM_SIZE)) $(CONFIG_BIRMAN_MCHP_FW_OFFSET) 1)
+
+cbfs-files-y += apu/ecfw
+apu/ecfw-file := $(CONFIG_BIRMAN_MCHP_FW_FILE)
+apu/ecfw-position := $(BIRMAN_EC_POSITION)
+apu/ecfw-type := raw
+
+else
+files_added:: warn_no_mchp
+endif # CONFIG_BIRMAN_HAVE_MCHP_FW
+
+PHONY+=warn_no_mchp
+warn_no_mchp:
+ printf "\n\t** WARNING **\n"
+ printf "coreboot has been built without the EC FW.\n"
+ printf "Do not flash this image. Your Birman's power button\n"
+ printf "will not respond when you press it.\n\n"
diff --git a/src/mainboard/amd/birman/board.fmd b/src/mainboard/amd/birman/board.fmd
new file mode 100644
index 0000000000..6c6ad92a28
--- /dev/null
+++ b/src/mainboard/amd/birman/board.fmd
@@ -0,0 +1,8 @@
+FLASH@0xFF000000 16M {
+ BIOS {
+ EC 4K
+ RW_MRC_CACHE 120K
+ FMAP 4K
+ COREBOOT(CBFS)
+ }
+}
diff --git a/src/mainboard/amd/birman/board_info.txt b/src/mainboard/amd/birman/board_info.txt
new file mode 100644
index 0000000000..b351b8e696
--- /dev/null
+++ b/src/mainboard/amd/birman/board_info.txt
@@ -0,0 +1 @@
+Category: eval
diff --git a/src/mainboard/amd/birman/bootblock.c b/src/mainboard/amd/birman/bootblock.c
new file mode 100644
index 0000000000..a6e525dcd4
--- /dev/null
+++ b/src/mainboard/amd/birman/bootblock.c
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <bootblock_common.h>
+#include <soc/espi.h>
+#include "ec.h"
+#include "gpio.h"
+
+void bootblock_mainboard_early_init(void)
+{
+ mainboard_program_early_gpios();
+
+ espi_switch_to_spi1_pads();
+}
+
+void bootblock_mainboard_init(void)
+{
+ birman_ec_init();
+}
diff --git a/src/mainboard/amd/birman/chromeos.c b/src/mainboard/amd/birman/chromeos.c
new file mode 100644
index 0000000000..515da94df1
--- /dev/null
+++ b/src/mainboard/amd/birman/chromeos.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <bootmode.h>
+#include <boot/coreboot_tables.h>
+#include <gpio.h>
+#include <types.h>
+#include <vendorcode/google/chromeos/chromeos.h>
+
+void fill_lb_gpios(struct lb_gpios *gpios)
+{
+ struct lb_gpio chromeos_gpios[] = {};
+ lb_add_gpios(gpios, chromeos_gpios, ARRAY_SIZE(chromeos_gpios));
+}
+
+int get_write_protect_state(void)
+{
+ /* Birman doesn't have a write protect pin */
+ return 0;
+}
+
+DECLARE_NO_CROS_GPIOS();
diff --git a/src/mainboard/amd/birman/chromeos.fmd b/src/mainboard/amd/birman/chromeos.fmd
new file mode 100644
index 0000000000..c28070ad11
--- /dev/null
+++ b/src/mainboard/amd/birman/chromeos.fmd
@@ -0,0 +1,34 @@
+FLASH@0xFF000000 16M {
+ SI_BIOS {
+ EC 4K
+ RW_MRC_CACHE(PRESERVE) 120K
+ RW_SECTION_A 4M {
+ VBLOCK_A 8K
+ FW_MAIN_A(CBFS)
+ RW_FWID_A 256
+ }
+ RW_SECTION_B 4M {
+ VBLOCK_B 8K
+ FW_MAIN_B(CBFS)
+ RW_FWID_B 256
+ }
+ RW_ELOG(PRESERVE) 4K
+ RW_SHARED 16K {
+ SHARED_DATA 8K
+ VBLOCK_DEV 8K
+ }
+ RW_VPD(PRESERVE) 8K
+ RW_NVRAM(PRESERVE) 20K
+ SMMSTORE(PRESERVE) 64K
+ RW_LEGACY(CBFS)
+ WP_RO@10M 6M {
+ RO_VPD(PRESERVE) 16K
+ RO_SECTION {
+ FMAP 2K
+ RO_FRID 64
+ GBB@4K 448K
+ COREBOOT(CBFS)
+ }
+ }
+ }
+}
diff --git a/src/mainboard/amd/birman/devicetree.cb b/src/mainboard/amd/birman/devicetree.cb
new file mode 100644
index 0000000000..8b5728f9e2
--- /dev/null
+++ b/src/mainboard/amd/birman/devicetree.cb
@@ -0,0 +1,226 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+# TODO: Update for birman
+
+chip soc/amd/morgana
+ register "common_config.espi_config" = "{
+ .std_io_decode_bitmap = ESPI_DECODE_IO_0x80_EN | ESPI_DECODE_IO_0X2E_0X2F_EN | ESPI_DECODE_IO_0X60_0X64_EN,
+ .generic_io_range[0] = {
+ .base = 0x3f8,
+ .size = 8,
+ },
+ .generic_io_range[1] = {
+ .base = 0x600,
+ .size = 256,
+ },
+ .io_mode = ESPI_IO_MODE_QUAD,
+ .op_freq_mhz = ESPI_OP_FREQ_16_MHZ,
+ .crc_check_enable = 1,
+ .alert_pin = ESPI_ALERT_PIN_PUSH_PULL,
+ .periph_ch_en = 1,
+ .vw_ch_en = 1,
+ .oob_ch_en = 1,
+ .flash_ch_en = 0,
+ }"
+
+ register "i2c_scl_reset" = "GPIO_I2C0_SCL | GPIO_I2C1_SCL |
+ GPIO_I2C2_SCL | GPIO_I2C3_SCL"
+
+ register "i2c[0].early_init" = "1"
+ register "i2c[1].early_init" = "1"
+ register "i2c[2].early_init" = "1"
+ register "i2c[3].early_init" = "1"
+
+ # I2C Pad Control RX Select Configuration
+ register "i2c_pad[0].rx_level" = "I2C_PAD_RX_1_8V"
+ register "i2c_pad[1].rx_level" = "I2C_PAD_RX_1_8V"
+ register "i2c_pad[2].rx_level" = "I2C_PAD_RX_1_8V"
+ register "i2c_pad[3].rx_level" = "I2C_PAD_RX_1_8V"
+
+ register "s0ix_enable" = "true"
+
+ register "pspp_policy" = "DXIO_PSPP_DISABLED" # TODO: reenable when PSPP works
+
+ register "usb_phy_custom" = "1"
+ register "usb_phy" = "{
+ .Usb2PhyPort[0] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb2PhyPort[1] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb2PhyPort[2] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb2PhyPort[3] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb2PhyPort[4] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb2PhyPort[5] = {
+ .compdistune = 0x3,
+ .pllbtune = 0x1,
+ .pllitune = 0x0,
+ .pllptune = 0xe,
+ .sqrxtune = 0x3,
+ .txfslstune = 0x3,
+ .txpreempamptune = 0x2,
+ .txpreemppulsetune = 0x0,
+ .txrisetune = 0x1,
+ .txvreftune = 0x3,
+ .txhsxvtune = 0x3,
+ .txrestune = 0x2,
+ },
+ .Usb3PhyPort[0] = {
+ .tx_term_ctrl = 0x2,
+ .rx_term_ctrl = 0x2,
+ .tx_vboost_lvl_en = 0x0,
+ .tx_vboost_lvl = 0x5,
+ },
+ .Usb3PhyPort[1] = {
+ .tx_term_ctrl = 0x2,
+ .rx_term_ctrl = 0x2,
+ .tx_vboost_lvl_en = 0x0,
+ .tx_vboost_lvl = 0x5,
+ },
+ .Usb3PhyPort[2] = {
+ .tx_term_ctrl = 0x2,
+ .rx_term_ctrl = 0x2,
+ .tx_vboost_lvl_en = 0x0,
+ .tx_vboost_lvl = 0x5,
+ },
+ .ComboPhyStaticConfig[0] = USB_COMBO_PHY_MODE_USB_C,
+ .ComboPhyStaticConfig[1] = USB_COMBO_PHY_MODE_USB_C,
+ .BatteryChargerEnable = 0,
+ .PhyP3CpmP4Support = 0,
+ }"
+
+ register "gpp_clk_config[0]" = "GPP_CLK_REQ"
+ register "gpp_clk_config[1]" = "GPP_CLK_REQ"
+ register "gpp_clk_config[2]" = "GPP_CLK_OFF"
+ register "gpp_clk_config[3]" = "GPP_CLK_REQ"
+
+ device domain 0 on
+ device ref iommu on end
+ device ref gpp_bridge_0 on end # GBE
+ device ref gpp_bridge_1 on end # WIFI
+ device ref gpp_bridge_2 on end # NVMe SSD
+ device ref gpp_bridge_a on # Internal GPP Bridge 0 to Bus A
+ device ref gfx on end # Internal GPU (GFX)
+ device ref gfx_hda on end # Display HD Audio Controller (GFXAZ)
+ device ref crypto on end # Crypto Coprocessor
+ device ref xhci_0 on # USB 3.1 (USB0)
+ chip drivers/usb/acpi
+ device ref xhci_0_root_hub on
+ chip drivers/usb/acpi
+ device ref usb3_port0 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb2_port0 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb2_port1 on end
+ end
+ end
+ end
+ end
+ device ref xhci_1 on # USB 3.1 (USB1)
+ chip drivers/usb/acpi
+ device ref xhci_1_root_hub on
+ chip drivers/usb/acpi
+ device ref usb3_port2 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb3_port3 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb2_port2 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb2_port3 on end
+ end
+ chip drivers/usb/acpi
+ device ref usb2_port4 on end
+ end
+ end
+ end
+ end
+ device ref acp on end # Audio Processor (ACP)
+ end
+ device ref gpp_bridge_c on # Internal GPP Bridge 2 to Bus C
+ device ref xhci_2 on
+ chip drivers/usb/acpi
+ register "type" = "UPC_TYPE_HUB"
+ device usb 0.0 alias xhci_2_root_hub on
+ chip drivers/usb/acpi
+ device usb 2.0 alias usb2_port5 on end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ device ref i2c_0 on end
+ device ref i2c_1 on end
+ device ref i2c_2 on end
+ device ref i2c_3 on end
+ device ref uart_0 on end # UART0
+
+end
diff --git a/src/mainboard/amd/birman/dsdt.asl b/src/mainboard/amd/birman/dsdt.asl
new file mode 100644
index 0000000000..7b8982a645
--- /dev/null
+++ b/src/mainboard/amd/birman/dsdt.asl
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpi.h>
+DefinitionBlock (
+ "dsdt.aml",
+ "DSDT",
+ ACPI_DSDT_REV_2,
+ OEM_ID,
+ ACPI_TABLE_CREATOR,
+ 0x00010001 /* OEM Revision */
+ )
+{
+ #include <acpi/dsdt_top.asl>
+
+ #include <soc.asl>
+}
diff --git a/src/mainboard/amd/birman/early_gpio.c b/src/mainboard/amd/birman/early_gpio.c
new file mode 100644
index 0000000000..bcdeea7914
--- /dev/null
+++ b/src/mainboard/amd/birman/early_gpio.c
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/gpio.h>
+#include "gpio.h"
+
+/* TODO: Update for birman */
+
+/* GPIO pins used by coreboot should be initialized in bootblock */
+
+static const struct soc_amd_gpio gpio_set_stage_reset[] = {
+};
+
+void mainboard_program_early_gpios(void)
+{
+ gpio_configure_pads(gpio_set_stage_reset, ARRAY_SIZE(gpio_set_stage_reset));
+}
diff --git a/src/mainboard/amd/birman/ec.c b/src/mainboard/amd/birman/ec.c
new file mode 100644
index 0000000000..3775ef5a2a
--- /dev/null
+++ b/src/mainboard/amd/birman/ec.c
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* TODO: Update for birman */
+
+#include <ec/acpi/ec.h>
+#include "ec.h"
+
+#define BIRMAN_EC_CMD 0x666
+#define BIRMAN_EC_DATA 0x662
+
+#define EC_GPIO_3_ADDR 0xA3
+#define EC_GPIO_LOM_RESET_AUX BIT(1)
+
+#define EC_GPIO_7_ADDR 0xA7
+#define EC_GPIO_DT_PWREN BIT(2)
+#define EC_GPIO_WWAN_MODULE_RST BIT(5)
+
+#define EC_GPIO_8_ADDR 0xA8
+#define EC_GPIO_SMBUS0_EN BIT(0)
+
+#define EC_GPIO_A_ADDR 0xAA
+#define EC_GPIO_WWAN_PWREN BIT(3)
+#define EC_GPIO_M2_SSD0_PWREN BIT(6)
+#define EC_GPIO_LOM_PWREN BIT(7)
+
+#define EC_GPIO_C_ADDR 0xAC
+#define EC_GPIO_DT_N_WLAN_SW BIT(1)
+#define EC_GPIO_MP2_SEL BIT(2)
+#define EC_GPIO_WWAN_N_LOM_SW BIT(3)
+
+#define EC_SW02_ADDR 0xB7
+#define EC_SW02_MS BIT(7)
+
+static void configure_ec_gpio(void)
+{
+ uint8_t tmp;
+
+ tmp = ec_read(EC_GPIO_3_ADDR);
+ tmp |= EC_GPIO_LOM_RESET_AUX;
+ ec_write(EC_GPIO_3_ADDR, tmp);
+
+ tmp = ec_read(EC_GPIO_7_ADDR);
+ tmp |= EC_GPIO_WWAN_MODULE_RST | EC_GPIO_DT_PWREN;
+ ec_write(EC_GPIO_7_ADDR, tmp);
+
+ tmp = ec_read(EC_GPIO_8_ADDR);
+ tmp |= EC_GPIO_SMBUS0_EN;
+ ec_write(EC_GPIO_8_ADDR, tmp);
+
+ tmp = ec_read(EC_GPIO_A_ADDR);
+ tmp |= EC_GPIO_M2_SSD0_PWREN | EC_GPIO_LOM_PWREN | EC_GPIO_WWAN_PWREN;
+ ec_write(EC_GPIO_A_ADDR, tmp);
+
+ tmp = ec_read(EC_GPIO_C_ADDR);
+ tmp |= EC_GPIO_WWAN_N_LOM_SW | EC_GPIO_MP2_SEL | EC_GPIO_DT_N_WLAN_SW;
+ ec_write(EC_GPIO_C_ADDR, tmp);
+
+ tmp = ec_read(EC_SW02_ADDR);
+ tmp |= EC_SW02_MS;
+ ec_write(EC_SW02_ADDR, tmp);
+}
+
+void birman_ec_init(void)
+{
+ ec_set_ports(BIRMAN_EC_CMD, BIRMAN_EC_DATA);
+ configure_ec_gpio();
+}
diff --git a/src/mainboard/amd/birman/ec.h b/src/mainboard/amd/birman/ec.h
new file mode 100644
index 0000000000..d8e54db35f
--- /dev/null
+++ b/src/mainboard/amd/birman/ec.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef BIRMAN_EC_H
+#define BIRMAN_EC_H
+
+void birman_ec_init(void);
+
+#endif /* BIRMAN_EC_H */
diff --git a/src/mainboard/amd/birman/gpio.c b/src/mainboard/amd/birman/gpio.c
new file mode 100644
index 0000000000..583b1d1ab3
--- /dev/null
+++ b/src/mainboard/amd/birman/gpio.c
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <soc/gpio.h>
+#include "gpio.h"
+
+/* TODO: Update for birman */
+
+/*
+ * As a rule of thumb, GPIO pins used by coreboot should be initialized at
+ * bootblock while GPIO pins used only by the OS should be initialized at
+ * ramstage.
+ */
+static const struct soc_amd_gpio gpio_set_stage_ram[] = {
+
+};
+
+void mainboard_program_gpios(void)
+{
+ gpio_configure_pads(gpio_set_stage_ram, ARRAY_SIZE(gpio_set_stage_ram));
+}
diff --git a/src/mainboard/amd/birman/gpio.h b/src/mainboard/amd/birman/gpio.h
new file mode 100644
index 0000000000..04c98c50df
--- /dev/null
+++ b/src/mainboard/amd/birman/gpio.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef MAINBOARD_GPIO_H
+#define MAINBOARD_GPIO_H
+
+void mainboard_program_early_gpios(void); /* bootblock GPIO configuration */
+void mainboard_program_gpios(void); /* ramstage GPIO configuration */
+
+#endif /* MAINBOARD_GPIO_H */
diff --git a/src/mainboard/amd/birman/mainboard.c b/src/mainboard/amd/birman/mainboard.c
new file mode 100644
index 0000000000..ffb778cf4e
--- /dev/null
+++ b/src/mainboard/amd/birman/mainboard.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <amdblocks/amd_pci_util.h>
+#include <commonlib/helpers.h>
+#include <device/device.h>
+#include <soc/acpi.h>
+#include <string.h>
+#include <types.h>
+#include "gpio.h"
+
+/* TODO: Update for birman */
+
+/*
+ * These arrays set up the FCH PCI_INTR registers 0xC00/0xC01.
+ * This table is responsible for physically routing the PIC and
+ * IOAPIC IRQs to the different PCI devices on the system. It
+ * is read and written via registers 0xC00/0xC01 as an
+ * Index/Data pair. These values are chipset and mainboard
+ * dependent and should be updated accordingly.
+ */
+static uint8_t fch_pic_routing[0x80];
+static uint8_t fch_apic_routing[0x80];
+
+_Static_assert(sizeof(fch_pic_routing) == sizeof(fch_apic_routing),
+ "PIC and APIC FCH interrupt tables must be the same size");
+
+/*
+ * This controls the device -> IRQ routing.
+ *
+ * Hardcoded IRQs:
+ * 0: timer < soc/amd/common/acpi/lpc.asl
+ * 1: i8042 - Keyboard
+ * 2: cascade
+ * 8: rtc0 <- soc/amd/common/acpi/lpc.asl
+ * 9: acpi <- soc/amd/common/acpi/lpc.asl
+ */
+static const struct fch_irq_routing {
+ uint8_t intr_index;
+ uint8_t pic_irq_num;
+ uint8_t apic_irq_num;
+} birman_fch[] = {
+ { PIRQ_A, 12, PIRQ_NC },
+ { PIRQ_B, 14, PIRQ_NC },
+ { PIRQ_C, 15, PIRQ_NC },
+ { PIRQ_D, 12, PIRQ_NC },
+ { PIRQ_E, 14, PIRQ_NC },
+ { PIRQ_F, 15, PIRQ_NC },
+ { PIRQ_G, 12, PIRQ_NC },
+ { PIRQ_H, 14, PIRQ_NC },
+
+ { PIRQ_SCI, ACPI_SCI_IRQ, ACPI_SCI_IRQ },
+ { PIRQ_SD, PIRQ_NC, PIRQ_NC },
+ { PIRQ_SDIO, PIRQ_NC, PIRQ_NC },
+ { PIRQ_EMMC, PIRQ_NC, PIRQ_NC },
+ { PIRQ_GPIO, 11, 11 },
+ { PIRQ_I2C0, 10, 10 },
+ { PIRQ_I2C1, 7, 7 },
+ { PIRQ_I2C2, 6, 6 },
+ { PIRQ_I2C3, 5, 5 },
+ { PIRQ_UART0, 4, 4 },
+ { PIRQ_UART1, 3, 3 },
+
+ /* The MISC registers are not interrupt numbers */
+ { PIRQ_MISC, 0xfa, 0x00 },
+ { PIRQ_MISC0, 0x91, 0x00 },
+ { PIRQ_HPET_L, 0x00, 0x00 },
+ { PIRQ_HPET_H, 0x00, 0x00 },
+};
+
+static void init_tables(void)
+{
+ const struct fch_irq_routing *entry;
+ int i;
+
+ memset(fch_pic_routing, PIRQ_NC, sizeof(fch_pic_routing));
+ memset(fch_apic_routing, PIRQ_NC, sizeof(fch_apic_routing));
+
+ for (i = 0; i < ARRAY_SIZE(birman_fch); i++) {
+ entry = birman_fch + i;
+ fch_pic_routing[entry->intr_index] = entry->pic_irq_num;
+ fch_apic_routing[entry->intr_index] = entry->apic_irq_num;
+ }
+}
+
+static void pirq_setup(void)
+{
+ intr_data_ptr = fch_apic_routing;
+ picr_data_ptr = fch_pic_routing;
+}
+
+static void mainboard_init(void *chip_info)
+{
+ mainboard_program_gpios();
+}
+
+static void mainboard_enable(struct device *dev)
+{
+ init_tables();
+ /* Initialize the PIRQ data structures for consumption */
+ pirq_setup();
+}
+
+struct chip_operations mainboard_ops = {
+ .init = mainboard_init,
+ .enable_dev = mainboard_enable,
+};
diff --git a/src/mainboard/amd/birman/port_descriptors.c b/src/mainboard/amd/birman/port_descriptors.c
new file mode 100644
index 0000000000..f2ed5c54fe
--- /dev/null
+++ b/src/mainboard/amd/birman/port_descriptors.c
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <device/i2c_simple.h>
+#include <soc/gpio.h>
+#include <soc/platform_descriptors.h>
+#include <types.h>
+
+/* TODO: Update for birman */
+
+static const fsp_dxio_descriptor birman_dxio_descriptors[] = {
+ {
+ .engine_type = PCIE_ENGINE,
+ .port_present = true,
+ .start_logical_lane = 0,
+ .end_logical_lane = 0,
+ .device_number = 2,
+ .function_number = 1,
+ .link_speed_capability = GEN3,
+ .turn_off_unused_lanes = true,
+ .link_aspm = 2,
+ .link_hotplug = 3,
+ .clk_req = CLK_REQ3,
+ },
+ {
+ .engine_type = PCIE_ENGINE,
+ .port_present = true,
+ .start_logical_lane = 1,
+ .end_logical_lane = 1,
+ .device_number = 2,
+ .function_number = 2,
+ .link_speed_capability = GEN3,
+ .turn_off_unused_lanes = true,
+ .link_aspm = 2,
+ .link_hotplug = 3,
+ .clk_req = CLK_REQ1,
+ },
+ {
+ .engine_type = PCIE_ENGINE,
+ .port_present = true,
+ .start_logical_lane = 2,
+ .end_logical_lane = 3,
+ .device_number = 2,
+ .function_number = 3,
+ .link_speed_capability = GEN3,
+ .turn_off_unused_lanes = true,
+ .link_aspm = 2,
+ .link_hotplug = 3,
+ .gpio_group_id = GPIO_27,
+ .clk_req = CLK_REQ0,
+ },
+};
+
+static fsp_ddi_descriptor birman_ddi_descriptors[] = {
+ { /* DDI0 - eDP */
+ .connector_type = DDI_EDP,
+ .aux_index = DDI_AUX1,
+ .hdp_index = DDI_HDP1
+ },
+ { /* DDI1 - HDMI/DP */
+ .connector_type = DDI_HDMI,
+ .aux_index = DDI_AUX2,
+ .hdp_index = DDI_HDP2
+ },
+ { /* DDI2 - DP (type C) */
+ .connector_type = DDI_DP,
+ .aux_index = DDI_AUX3,
+ .hdp_index = DDI_HDP3,
+ },
+ { /* DDI3 - DP (type C) */
+ .connector_type = DDI_DP,
+ .aux_index = DDI_AUX4,
+ .hdp_index = DDI_HDP4,
+ },
+ { /* DDI4 - unused */
+ .connector_type = DDI_UNUSED_TYPE,
+ .aux_index = DDI_AUX5,
+ .hdp_index = DDI_HDP5,
+ }
+};
+
+static uint8_t get_ddi1_type(void)
+{
+ const uint8_t eeprom_i2c_bus = 2;
+ const uint8_t eeprom_i2c_address = 0x55;
+ const uint16_t eeprom_connector_type_offset = 2;
+ uint8_t eeprom_connector_type_data[2];
+ uint16_t connector_type;
+
+ if (i2c_2ba_read_bytes(eeprom_i2c_bus, eeprom_i2c_address,
+ eeprom_connector_type_offset, eeprom_connector_type_data,
+ sizeof(eeprom_connector_type_data))) {
+ printk(BIOS_NOTICE,
+ "Display connector type couldn't be determined. Disabling DDI1.\n");
+ return DDI_UNUSED_TYPE;
+ }
+
+ connector_type = eeprom_connector_type_data[1] | eeprom_connector_type_data[0] << 8;
+
+ switch (connector_type) {
+ case 0xc:
+ printk(BIOS_DEBUG, "Configuring DDI1 as HDMI.\n");
+ return DDI_HDMI;
+ break;
+ case 0x13:
+ printk(BIOS_DEBUG, "Configuring DDI1 as DP.\n");
+ return DDI_DP;
+ break;
+ case 0x14:
+ printk(BIOS_DEBUG, "Configuring DDI1 as eDP.\n");
+ return DDI_EDP;
+ break;
+ default:
+ printk(BIOS_WARNING, "Unexpected display connector type %x. Disabling DDI1.\n",
+ connector_type);
+ return DDI_UNUSED_TYPE;
+ }
+}
+
+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)
+{
+ birman_ddi_descriptors[1].connector_type = get_ddi1_type();
+
+ *dxio_descs = birman_dxio_descriptors;
+ *dxio_num = ARRAY_SIZE(birman_dxio_descriptors);
+ *ddi_descs = birman_ddi_descriptors;
+ *ddi_num = ARRAY_SIZE(birman_ddi_descriptors);
+}