cpu/ti/am335x: Move from cpu to soc in tree

The AM335X is a SoC, so should be in the soc tree.

This moves all the existing am335x code to soc/ and updates any
references. It also adds a soc.c file as required for the ramstage.

Change-Id: Ic1ccb0e9b9c24a8b211b723b5f4cc26cdd0eaaab
Signed-off-by: Sam Lewis <sam.vr.lewis@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/44378
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
diff --git a/src/soc/ti/Kconfig b/src/soc/ti/Kconfig
new file mode 100644
index 0000000..eb66519
--- /dev/null
+++ b/src/soc/ti/Kconfig
@@ -0,0 +1 @@
+source "src/soc/ti/am335x/Kconfig"
diff --git a/src/soc/ti/Makefile.inc b/src/soc/ti/Makefile.inc
new file mode 100644
index 0000000..357cc82
--- /dev/null
+++ b/src/soc/ti/Makefile.inc
@@ -0,0 +1 @@
+subdirs-$(CONFIG_SOC_TI_AM335X) += am335x
diff --git a/src/soc/ti/am335x/Kconfig b/src/soc/ti/am335x/Kconfig
new file mode 100644
index 0000000..533a0de
--- /dev/null
+++ b/src/soc/ti/am335x/Kconfig
@@ -0,0 +1,18 @@
+config SOC_TI_AM335X
+	select ARCH_BOOTBLOCK_ARMV7
+	select ARCH_VERSTAGE_ARMV7
+	select ARCH_ROMSTAGE_ARMV7
+	select ARCH_RAMSTAGE_ARMV7
+	select HAVE_UART_SPECIAL
+	select UART_OVERRIDE_REFCLK
+	select BOOT_DEVICE_NOT_SPI_FLASH
+	bool
+	default n
+
+if SOC_TI_AM335X
+
+config MEMLAYOUT_LD_FILE
+	string
+	default "src/soc/ti/am335x/memlayout.ld"
+
+endif
diff --git a/src/soc/ti/am335x/Makefile.inc b/src/soc/ti/am335x/Makefile.inc
new file mode 100644
index 0000000..2865338
--- /dev/null
+++ b/src/soc/ti/am335x/Makefile.inc
@@ -0,0 +1,56 @@
+ifeq ($(CONFIG_SOC_TI_AM335X),y)
+bootblock-y	+= bootblock.c
+bootblock-y	+= bootblock_media.c
+bootblock-y	+= dmtimer.c
+bootblock-y	+= gpio.c
+bootblock-y	+= pinmux.c
+bootblock-y	+= monotonic_timer.c
+
+romstage-y	+= nand.c
+romstage-y	+= cbmem.c
+romstage-y	+= dmtimer.c
+romstage-y	+= monotonic_timer.c
+
+ramstage-y	+= dmtimer.c
+ramstage-y	+= monotonic_timer.c
+ramstage-y	+= nand.c
+ramstage-y  += soc.c
+
+bootblock-y	+= uart.c
+romstage-y	+= uart.c
+ramstage-y	+= uart.c
+
+$(call add-class,omap-header)
+$(eval $(call create_class_compiler,omap-header,arm))
+
+omap-header-generic-ccopts += -D__COREBOOT_ARM_ARCH__=7
+
+real-target: $(obj)/MLO
+
+header_ld := $(call src-to-obj,omap-header,$(dir)/header.ld)
+
+get_header_size= \
+	$(eval omap_header_info=$(shell $(CBFSTOOL) $(1) print | grep $(2))) \
+	$(shell echo $$(($(word 2,$(omap_header_info)) + \
+			 $(word 4,$(omap_header_info)))))
+
+$(obj)/omap-header.bin: $$(omap-header-objs) $(obj)/coreboot.rom
+	@printf "    CC         $(subst $(obj)/,,$(@))\n"
+	$(CC_omap-header) -nostdlib -nostartfiles -static -include $(obj)/config.h \
+		-Wl,--defsym,header_load_size=$(strip \
+			$(call get_header_size,$(obj)/coreboot.rom, \
+				$(CONFIG_CBFS_PREFIX)/romstage \
+			) \
+		) \
+		-o $@.tmp $< -T $(header_ld)
+	$(OBJCOPY_omap-header) --only-section=".header" -O binary $@.tmp $@
+
+$(obj)/MLO: $(obj)/coreboot.rom $(obj)/omap-header.bin
+	@printf "    HEADER     $(subst $(obj)/,,$(@))\n"
+	$(Q)cat $(obj)/omap-header.bin $(obj)/coreboot.rom > $@
+
+omap-header-y	+= header.c
+
+omap-header-srcs += $(CONFIG_MEMLAYOUT_LD_FILE)
+omap-header-y += header.ld
+endif
diff --git a/src/soc/ti/am335x/bootblock.c b/src/soc/ti/am335x/bootblock.c
new file mode 100644
index 0000000..985e1a1
--- /dev/null
+++ b/src/soc/ti/am335x/bootblock.c
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <types.h>
+
+#include <arch/cache.h>
+#include <bootblock_common.h>
+
+void bootblock_soc_init(void)
+{
+	uint32_t sctlr;
+
+	/* enable dcache */
+	sctlr = read_sctlr();
+	sctlr |= SCTLR_C;
+	write_sctlr(sctlr);
+}
diff --git a/src/soc/ti/am335x/bootblock_media.c b/src/soc/ti/am335x/bootblock_media.c
new file mode 100644
index 0000000..050e0b7
--- /dev/null
+++ b/src/soc/ti/am335x/bootblock_media.c
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <boot_device.h>
+#include <symbols.h>
+
+/* FIXME: No idea how big the internal SRAM actually is. */
+static const struct mem_region_device boot_dev =
+	MEM_REGION_DEV_RO_INIT(_dram, CONFIG_ROM_SIZE);
+
+const struct region_device *boot_device_ro(void)
+{
+	return &boot_dev.rdev;
+}
diff --git a/src/soc/ti/am335x/cbmem.c b/src/soc/ti/am335x/cbmem.c
new file mode 100644
index 0000000..3765874
--- /dev/null
+++ b/src/soc/ti/am335x/cbmem.c
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <cbmem.h>
+#include <symbols.h>
+
+void *cbmem_top_chipset(void)
+{
+	return _dram + (CONFIG_DRAM_SIZE_MB << 20);
+}
diff --git a/src/soc/ti/am335x/clock.h b/src/soc/ti/am335x/clock.h
new file mode 100644
index 0000000..38b4ece
--- /dev/null
+++ b/src/soc/ti/am335x/clock.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __SOC_TI_AM335X_CLOCK_H__
+#define __SOC_TI_AM335X_CLOCK_H__
+
+#include <stdint.h>
+
+enum {
+	CM_ST_NO_SLEEP = 0x0,
+	CM_ST_SW_SLEEP = 0x1,
+	CM_ST_SW_WKUP = 0x2
+};
+
+enum {
+	CM_MODULEMODE_DISABLED = 0x0,
+	CM_MODULEMODE_ENABLED = 0x2
+};
+
+enum {
+	CM_FCLK_DIS = 0x0 << 18,
+	CM_FCLK_EN = 0x1 << 18
+};
+
+/* Clock module peripheral registers */
+struct am335x_cm_per_regs {
+	uint32_t l4ls_st;		// 0x0
+	uint32_t l3s_st;		// 0x4
+	uint8_t _rsv0[4];		// 0x8-0xb
+	uint32_t l3_st;			// 0xc
+	uint8_t _rsv1[4];		// 0x10-0x13
+	uint32_t cpgmac0;		// 0x14
+	uint32_t lcdc;			// 0x18
+	uint32_t usb0;			// 0x1c
+	uint8_t _rsv2[4];		// 0x20-0x23
+	uint32_t tptc0;			// 0x24
+	uint32_t emif;			// 0x28
+	uint32_t ocmcram;		// 0x2c
+	uint32_t gpmc;			// 0x30
+	uint32_t mcasp0;		// 0x34
+	uint32_t uart5;			// 0x38
+	uint32_t mmc0;			// 0x3c
+	uint32_t elm;			// 0x40
+	uint32_t i2c2;			// 0x44
+	uint32_t i2c1;			// 0x48
+	uint32_t spi0;			// 0x4c
+	uint32_t spi1;			// 0x50
+	uint8_t _rsv3[0xc];		// 0x54-0x5f
+	uint32_t l4ls;			// 0x60
+	uint8_t _rsv4[4];		// 0x64-0x67
+	uint32_t mcasp1;		// 0x68
+	uint32_t uart1;			// 0x6c
+	uint32_t uart2;			// 0x70
+	uint32_t uart3;			// 0x74
+	uint32_t uart4;			// 0x78
+	uint32_t timer7;		// 0x7c
+	uint32_t timer2;		// 0x80
+	uint32_t timer3;		// 0x84
+	uint32_t timer4;		// 0x88
+	uint8_t _rsv5[0x20];		// 0x90-0xab
+	uint32_t gpio1;			// 0xac
+	uint32_t gpio2;			// 0xb0
+	uint32_t gpio3;			// 0xb4
+	uint8_t _rsv6[4];		// 0xb8-0xbb
+	uint32_t tpcc;			// 0xbc
+	uint32_t dcan0;			// 0xc0
+	uint32_t dcan1;			// 0xc4
+	uint8_t _rsv7[4];		// 0xc8-0xcb
+	uint32_t epwmss1;		// 0xcc
+	uint8_t _rsv8[4];		// 0xd0-0xd3
+	uint32_t epwmss0;		// 0xd4
+	uint32_t epwmss2;		// 0xd8
+	uint32_t l3_instr;		// 0xdc
+	uint32_t l3;			// 0xe0
+	uint32_t ieee5000;		// 0xe4
+	uint32_t pru_icss;		// 0xe8
+	uint32_t timer5;		// 0xec
+	uint32_t timer6;		// 0xf0
+	uint32_t mmc1;			// 0xf4
+	uint32_t mmc2;			// 0xf8
+	uint32_t tptc1;			// 0xfc
+	uint32_t tptc2;			// 0x100
+	uint8_t _rsv9[8];		// 0x104-0x10b
+	uint32_t spinlock;		// 0x10c
+	uint32_t mailbox0;		// 0x110
+	uint8_t _rsv10[8];		// 0x114-0x11b
+	uint32_t l4hs_st;		// 0x11c
+	uint32_t l4hs;			// 0x120
+	uint8_t _rsv11[8];		// 0x124-0x12b
+	uint32_t ocpwp_l3_st;		// 0x12c
+	uint32_t ocpwp;			// 0x130
+	uint8_t _rsv12[0xb];		// 0x134-0x13f
+	uint32_t pru_icss_st;		// 0x140
+	uint32_t cpsw_st;		// 0x144
+	uint32_t lcdc_st;		// 0x148
+	uint32_t clkdiv32k;		// 0x14c
+	uint32_t clk_24mhz_st;		// 0x150
+} __packed;
+static struct am335x_cm_per_regs * const am335x_cm_per = (void *)0x44e00000;
+
+/* Clock module wakeup registers */
+struct am335x_cm_wkup_regs {
+	uint32_t wkup_st;		// 0x0
+	uint32_t wkup_control;		// 0x4
+	uint32_t wkup_gpio0;		// 0x8
+	uint32_t wkup_l4wkup;		// 0xc
+	uint32_t wkup_timer0;		// 0x10
+	uint32_t wkup_debugss;		// 0x14
+	uint32_t l3_aon_st;		// 0x18
+	uint32_t autoidle_dpll_mpu;	// 0x1c
+	uint32_t idlest_dpll_mpu;	// 0x20
+	uint32_t ssc_deltamstep_dpll_mpu;	// 0x24
+	uint32_t ssc_modfreqdiv_dpll_mpu;	// 0x28
+	uint32_t clksel_dpll_mpu;	// 0x2c
+	uint32_t autoidle_dpll_ddr;	// 0x30
+	uint32_t idlest_dpll_ddr;	// 0x34
+	uint32_t ssc_deltamstep_dpll_ddr;	// 0x38
+	uint32_t ssc_modfreqdiv_dpll_ddr;	// 0x3c
+	uint32_t clksel_dpll_ddr;	// 0x40
+	uint32_t autoidle_dpll_disp;	// 0x44
+	uint32_t idlest_dpll_disp;	// 0x48
+	uint32_t ssc_deltamstep_dpll_disp;	// 0x4c
+	uint32_t ssc_modfreqdiv_dpll_disp;	// 0x50
+	uint32_t clksel_dpll_disp;	// 0x54
+	uint32_t autoidle_dpll_core;	// 0x58
+	uint32_t idlest_dpll_core;	// 0x5c
+	uint32_t ssc_deltamstep_dpll_core;	// 0x60
+	uint32_t ssc_modfreqdiv_dpll_core;	// 0x64
+	uint32_t clksel_dpll_core;	// 0x68
+	uint32_t autoidle_dpll_per;	// 0x6c
+	uint32_t idlest_dpll_per;	// 0x70
+	uint32_t ssc_deltamstep_dpll_per;	// 0x74
+	uint32_t ssc_modfreqdiv_dpll_per;	// 0x78
+	uint32_t clkdcoldo_dpll_per;	// 0x7c
+	uint32_t div_m4_dpll_core;	// 0x80
+	uint32_t div_m5_dpll_core;	// 0x84
+	uint32_t clkmode_dpll_mpu;	// 0x88
+	uint32_t clkmode_dpll_per;	// 0x8c
+	uint32_t clkmode_dpll_core;	// 0x90
+	uint32_t clkmode_dpll_ddr;	// 0x94
+	uint32_t clkmode_dpll_disp;	// 0x98
+	uint32_t clksel_dpll_periph;	// 0x9c
+	uint32_t div_m2_dpll_ddr;	// 0xa0
+	uint32_t div_m2_dpll_disp;	// 0xa4
+	uint32_t div_m2_dpll_mpu;	// 0xa8
+	uint32_t div_m2_dpll_per;	// 0xac
+	uint32_t wkup_wkup_m3;		// 0xb0
+	uint32_t wkup_uart0;		// 0xb4
+	uint32_t wkup_i2c0;		// 0xb8
+	uint32_t wkup_adc_tsc;		// 0xbc
+	uint32_t wkup_smartreflex0;	// 0xc0
+	uint32_t wkup_timer1;		// 0xc4
+	uint32_t wkup_smartreflex1;	// 0xc8
+	uint32_t l4_wkup_aon_st;	// 0xcc
+	uint8_t _rsv0[4];		// 0xd0-0xd3
+	uint32_t wkup_wdt1;		// 0xd4
+	uint32_t div_m6_dpll_core;	// 0xd8
+} __packed;
+static struct am335x_cm_wkup_regs * const am335x_cm_wkup = (void *)0x44e00400;
+
+/* Clock module pll registers */
+struct am335x_cm_dpll_regs {
+	uint8_t _rsv0[4];		// 0x0-0x3
+	uint32_t clksel_timer7_clk;	// 0x4
+	uint32_t clksel_timer2_clk;	// 0x8
+	uint32_t clksel_timer3_clk;	// 0xc
+	uint32_t clksel_timer4_clk;	// 0x10
+	uint32_t cm_mac_clksel;		// 0x14
+	uint32_t clksel_timer5_clk;	// 0x18
+	uint32_t clksel_timer6_clk;	// 0x1c
+	uint32_t cm_cpts_rft_clksel;	// 0x20
+	uint8_t _rsv1[4];		// 0x24-0x27
+	uint32_t clksel_timer1ms_clk;	// 0x28
+	uint32_t clksel_gfx_fclk;	// 0x2c
+	uint32_t clksel_pru_icss_ocp_clk;	// 0x30
+	uint32_t clksel_lcdc_pixel_clk;	// 0x34
+	uint32_t clksel_wdt1_clk;	// 0x38
+	uint32_t clksel_gpio0_dbclk;	// 0x3c
+} __packed;
+static struct am335x_cm_dpll_regs * const am335x_cm_dpll = (void *)0x44e00500;
+
+/* Clock module mpu registers */
+struct am335x_cm_mpu_regs {
+	uint32_t st;			// 0x0
+	uint32_t mpu;			// 0x4
+} __packed;
+static struct am335x_cm_mpu_regs * const am335x_cm_mpu = (void *)0x44e00600;
+
+/* Clock module device registers */
+struct am335x_cm_device_regs {
+	uint32_t cm_clkout_ctrl;	// 0x0
+} __packed;
+static struct am335x_cm_device_regs * const am335x_cm_device =
+		(void *)0x44e00700;
+
+/* Clock module RTC registers */
+struct am335x_cm_rtc_regs {
+	uint32_t rtc;			// 0x0
+	uint32_t st;			// 0x4
+} __packed;
+static struct am335x_cm_rtc_regs * const am335x_cm_rtc = (void *)0x44e00800;
+
+/* Clock module graphics controller registers */
+struct am335x_cm_gfx_regs {
+	uint32_t l3_st;			// 0x0
+	uint32_t gfx;			// 0x4
+	uint8_t _rsv0[4];		// 0x8-0xb
+	uint32_t l4ls_gfx_st;		// 0xc
+	uint32_t mmucfg;		// 0x10
+	uint32_t mmudata;		// 0x14
+} __packed;
+static struct am335x_cm_gfx_regs * const am335x_cm_gfx = (void *)0x44e00900;
+
+/* Clock module efuse registers */
+struct am335x_cm_cefuse_regs {
+	uint32_t st;			// 0x0
+	uint8_t _rsv0[0x1c];		// 0x4-0x1f
+	uint32_t cefuse;		// 0x20
+} __packed;
+static struct am335x_cm_cefuse_regs * const am335x_cm_cefuse =
+		(void *)0x44e00a00;
+
+#endif	/* __SOC_TI_AM335X_CLOCK_H__ */
diff --git a/src/soc/ti/am335x/dmtimer.c b/src/soc/ti/am335x/dmtimer.c
new file mode 100644
index 0000000..b3aa7a1
--- /dev/null
+++ b/src/soc/ti/am335x/dmtimer.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include "dmtimer.h"
+
+void dmtimer_start(int num)
+{
+}
+
+uint64_t dmtimer_raw_value(int num)
+{
+	return 0;
+}
diff --git a/src/soc/ti/am335x/dmtimer.h b/src/soc/ti/am335x/dmtimer.h
new file mode 100644
index 0000000..ad8515f
--- /dev/null
+++ b/src/soc/ti/am335x/dmtimer.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __SOC_TI_AM335X_DMTIMER_H__
+#define __SOC_TI_AM335X_DMTIMER_H__
+
+#include <stdint.h>
+
+#define OSC_HZ 24000000
+
+void dmtimer_start(int num);
+uint64_t dmtimer_raw_value(int num);
+
+#endif
diff --git a/src/soc/ti/am335x/gpio.c b/src/soc/ti/am335x/gpio.c
new file mode 100644
index 0000000..d3d3581
--- /dev/null
+++ b/src/soc/ti/am335x/gpio.c
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <device/mmio.h>
+#include <console/console.h>
+#include <soc/ti/am335x/gpio.h>
+#include <stdint.h>
+
+static struct am335x_gpio_regs *gpio_regs_and_bit(unsigned int gpio,
+						  uint32_t *bit)
+{
+	unsigned int bank = gpio / AM335X_GPIO_BITS_PER_BANK;
+
+	if (bank >= ARRAY_SIZE(am335x_gpio_banks)) {
+		printk(BIOS_ERR, "Bad gpio index %d.\n", gpio);
+		return NULL;
+	}
+	*bit = 1 << (gpio % 32);
+	return am335x_gpio_banks[bank];
+}
+
+void am335x_disable_gpio_irqs(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(am335x_gpio_banks); i++)
+		write32(&am335x_gpio_banks[i]->irqstatus_clr_0, 0xffffffff);
+}
+
+int gpio_direction_input(unsigned int gpio)
+{
+	uint32_t bit;
+	struct am335x_gpio_regs *regs = gpio_regs_and_bit(gpio, &bit);
+
+	if (!regs)
+		return -1;
+	setbits32(&regs->oe, bit);
+	return 0;
+}
+
+int gpio_direction_output(unsigned int gpio, int value)
+{
+	uint32_t bit;
+	struct am335x_gpio_regs *regs = gpio_regs_and_bit(gpio, &bit);
+
+	if (!regs)
+		return -1;
+	if (value)
+		write32(&regs->setdataout, bit);
+	else
+		write32(&regs->cleardataout, bit);
+	clrbits32(&regs->oe, bit);
+	return 0;
+}
+
+int gpio_get_value(unsigned int gpio)
+{
+	uint32_t bit;
+	struct am335x_gpio_regs *regs = gpio_regs_and_bit(gpio, &bit);
+
+	if (!regs)
+		return -1;
+	return (read32(&regs->datain) & bit) ? 1 : 0;
+}
+
+int gpio_set_value(unsigned int gpio, int value)
+{
+	uint32_t bit;
+	struct am335x_gpio_regs *regs = gpio_regs_and_bit(gpio, &bit);
+
+	if (!regs)
+		return -1;
+	if (value)
+		write32(&regs->setdataout, bit);
+	else
+		write32(&regs->cleardataout, bit);
+	return 0;
+}
diff --git a/src/soc/ti/am335x/gpio.h b/src/soc/ti/am335x/gpio.h
new file mode 100644
index 0000000..0877a62
--- /dev/null
+++ b/src/soc/ti/am335x/gpio.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __SOC_TI_AM335X_GPIO_H__
+#define __SOC_TI_AM335X_GPIO_H__
+
+#include <stdint.h>
+
+enum {
+	AM335X_GPIO_BITS_PER_BANK = 32
+};
+
+struct am335x_gpio_regs {
+	uint32_t revision;		// 0x0
+	uint8_t _rsv0[0xc];		// 0x4-0xf
+	uint32_t sysconfig;		// 0x10
+	uint8_t _rsv1[0xc];		// 0x14-0x1f
+	uint32_t eoi;			// 0x20
+	uint32_t irqstatus_raw_0;	// 0x24
+	uint32_t irqstatus_raw_1;	// 0x28
+	uint32_t irqstatus_0;		// 0x2c
+	uint32_t irqstatus_1;		// 0x30
+	uint32_t irqstatus_set_0;	// 0x34
+	uint32_t irqstatus_set_1;	// 0x38
+	uint32_t irqstatus_clr_0;	// 0x3c
+	uint32_t irqstatus_clk_1;	// 0x40
+	uint32_t irqwaken_0;		// 0x44
+	uint32_t irqwaken_1;		// 0x48
+	uint8_t _rsv2[0xc8];		// 0x4c-0x113
+	uint32_t sysstatus;		// 0x114
+	uint8_t _rsv3[0x18];		// 0x118-0x12f
+	uint32_t ctrl;			// 0x130
+	uint32_t oe;			// 0x134
+	uint32_t datain;		// 0x138
+	uint32_t dataout;		// 0x13c
+	uint32_t leveldetect0;		// 0x140
+	uint32_t leveldetect1;		// 0x144
+	uint32_t risingdetect;		// 0x148
+	uint32_t fallingdetect;		// 0x14c
+	uint32_t debouncenable;		// 0x150
+	uint32_t debouncingtime;	// 0x154
+	uint8_t _rsv4[0x38];		// 0x158-0x18f
+	uint32_t cleardataout;		// 0x190
+	uint32_t setdataout;		// 0x194
+} __packed;
+
+static struct am335x_gpio_regs * const am335x_gpio_banks[] = {
+	(void *)0x44e07000, (void *)0x4804c000,
+	(void *)0x481ac000, (void *)0x481ae000
+};
+
+void am335x_disable_gpio_irqs(void);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio, int value);
+int gpio_get_value(unsigned int gpio);
+int gpio_set_value(unsigned int gpio, int value);
+
+#endif	/* __SOC_TI_AM335X_CLOCK_H__ */
diff --git a/src/soc/ti/am335x/header.c b/src/soc/ti/am335x/header.c
new file mode 100644
index 0000000..9edfdd0
--- /dev/null
+++ b/src/soc/ti/am335x/header.c
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <stdint.h>
+#include <symbols.h>
+
+#include "header.h"
+
+struct config_headers {
+	// The table of contents.
+	struct configuration_header_toc_item toc_chsettings;
+	struct configuration_header_toc_item toc_end;
+
+	// An inert instance of chsettings.
+	struct configuration_header_settings chsettings;
+} __packed;
+
+struct omap_image_headers {
+	union {
+		struct config_headers config_headers;
+		uint8_t bytes[512];
+	};
+	struct gp_device_header image_header;
+};
+
+// A symbol which defines how much of the image the iROM should load.
+extern char header_load_size;
+
+struct omap_image_headers headers __attribute__((section(".header"))) = {
+	.config_headers = {
+		.toc_chsettings = {
+			.start = offsetof(struct omap_image_headers,
+					  config_headers.chsettings),
+			.size = sizeof(struct configuration_header_settings),
+			.reserved = { 0, 0, 0 },
+			.filename = "CHSETTINGS\0"
+		},
+		.toc_end = {
+			.start = 0xffffffff,
+			.size = 0xffffffff,
+			.reserved = { 0xffffffff, 0xffffffff, 0xffffffff },
+			.filename = { 0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff,
+				      0xff, 0xff, 0xff, 0xff }
+		},
+		.chsettings = {
+			.key = 0xc0c0c0c1,
+			.valid = 0,
+			.version = 1,
+			.reserved = 0,
+			.flags = 0
+		}
+	},
+	.image_header = {
+		.size = (uintptr_t)&header_load_size,
+		.destination = (uintptr_t)_dram
+	}
+};
diff --git a/src/soc/ti/am335x/header.h b/src/soc/ti/am335x/header.h
new file mode 100644
index 0000000..a0a54ad
--- /dev/null
+++ b/src/soc/ti/am335x/header.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __SOC_TI_AM335X_HEADER_H
+#define __SOC_TI_AM335X_HEADER_H
+
+#include <stdint.h>
+
+struct configuration_header_toc_item {
+	// Offset from the start address of the TOC to the actual address of
+	// a section.
+	uint32_t start;
+
+	// Size of a section.
+	uint32_t size;
+
+	// Reserved.
+	uint32_t reserved[3];
+
+	// 12-character name of a section, including the zero (\0) terminator.
+	char filename[12];
+} __packed;
+
+struct configuration_header_settings {
+	// Key used for section verification.
+	uint32_t key;
+
+	// Enables or disables the section.
+	// 00h: Disable.
+	// Other: Enable.
+	uint8_t valid;
+
+	// Configuration header version.
+	uint8_t version;
+
+	// Reserved.
+	uint16_t reserved;
+
+	// Flags. It's not clear what this is used for.
+	uint32_t flags;
+} __packed;
+
+struct gp_device_header {
+	// Size of the image.
+	uint32_t size;
+
+	// Address to store the image/code entry point.
+	uint32_t destination;
+} __packed;
+
+#endif
diff --git a/src/soc/ti/am335x/header.ld b/src/soc/ti/am335x/header.ld
new file mode 100644
index 0000000..84e0136
--- /dev/null
+++ b/src/soc/ti/am335x/header.ld
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+#define OMAP_HEADER 1
+#include "memlayout.ld"
diff --git a/src/soc/ti/am335x/memlayout.ld b/src/soc/ti/am335x/memlayout.ld
new file mode 100644
index 0000000..78528e6
--- /dev/null
+++ b/src/soc/ti/am335x/memlayout.ld
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <memlayout.h>
+
+#include <arch/header.ld>
+
+SECTIONS
+{
+	DRAM_START(0x40000000)
+	BOOTBLOCK(0x402f0400, 20K)
+	ROMSTAGE(0x402f5400, 88K)
+	FMAP_CACHE(0x4030b400, 2K)
+	STACK(0x4030be00, 4K)
+	RAMSTAGE(0x80200000, 192K)
+
+	/* TODO: Implement MMU support and move TTB to a better location. */
+	TTB(0x81000000, 16K)
+
+#ifdef OMAP_HEADER
+	.header : {
+		*(.header);
+	} : to_load
+
+	/DISCARD/ : {
+		*(*)
+	}
+#endif
+}
diff --git a/src/soc/ti/am335x/monotonic_timer.c b/src/soc/ti/am335x/monotonic_timer.c
new file mode 100644
index 0000000..b57258b
--- /dev/null
+++ b/src/soc/ti/am335x/monotonic_timer.c
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <stdint.h>
+#include <delay.h>
+#include <timer.h>
+
+#include "dmtimer.h"
+
+static struct monotonic_counter {
+	int initialized;
+	struct mono_time time;
+	uint64_t last_value;
+} mono_counter;
+
+static const uint32_t clocks_per_usec = OSC_HZ/1000000;
+
+void timer_monotonic_get(struct mono_time *mt)
+{
+	uint64_t current_tick;
+	uint64_t usecs_elapsed;
+
+	if (!mono_counter.initialized) {
+		init_timer();
+		mono_counter.last_value = dmtimer_raw_value(0);
+		mono_counter.initialized = 1;
+	}
+
+	current_tick = dmtimer_raw_value(0);
+	usecs_elapsed = (current_tick - mono_counter.last_value) /
+							clocks_per_usec;
+
+	/* Update current time and tick values only if a full tick occurred. */
+	if (usecs_elapsed) {
+		mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
+		mono_counter.last_value = current_tick;
+	}
+
+	/* Save result. */
+	*mt = mono_counter.time;
+}
diff --git a/src/soc/ti/am335x/nand.c b/src/soc/ti/am335x/nand.c
new file mode 100644
index 0000000..a7029a0
--- /dev/null
+++ b/src/soc/ti/am335x/nand.c
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <boot_device.h>
+
+const struct region_device *boot_device_ro(void)
+{
+	/* FIXME: add support for reading coreboot from NAND */
+	return NULL;
+}
diff --git a/src/soc/ti/am335x/pinmux.c b/src/soc/ti/am335x/pinmux.c
new file mode 100644
index 0000000..8cf8884
--- /dev/null
+++ b/src/soc/ti/am335x/pinmux.c
@@ -0,0 +1,171 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "pinmux.h"
+
+#include <device/mmio.h>
+
+static struct am335x_pinmux_regs *regs =
+	(struct am335x_pinmux_regs *)(uintptr_t)AM335X_PINMUX_REG_ADDR;
+
+void am335x_pinmux_uart0(void)
+{
+	write32(&regs->uart0_rxd, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->uart0_txd, MODE(0) | PULLUDEN);
+}
+
+void am335x_pinmux_uart1(void)
+{
+	write32(&regs->uart1_rxd, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->uart1_txd, MODE(0) | PULLUDEN);
+}
+
+void am335x_pinmux_uart2(void)
+{
+	// UART2_RXD
+	write32(&regs->spi0_sclk, MODE(1) | PULLUP_EN | RXACTIVE);
+	// UART2_TXD
+	write32(&regs->spi0_d0, MODE(1) | PULLUDEN);
+}
+
+void am335x_pinmux_uart3(void)
+{
+	// UART3_RXD
+	write32(&regs->spi0_cs1, MODE(1) | PULLUP_EN | RXACTIVE);
+	// UART3_TXD
+	write32(&regs->ecap0_in_pwm0_out, MODE(1) | PULLUDEN);
+}
+
+void am335x_pinmux_uart4(void)
+{
+	// UART4_RXD
+	write32(&regs->gpmc_wait0, MODE(6) | PULLUP_EN | RXACTIVE);
+	// UART4_TXD
+	write32(&regs->gpmc_wpn, MODE(6) | PULLUDEN);
+}
+
+void am335x_pinmux_uart5(void)
+{
+	// UART5_RXD
+	write32(&regs->lcd_data9, MODE(4) | PULLUP_EN | RXACTIVE);
+	// UART5_TXD
+	write32(&regs->lcd_data8, MODE(4) | PULLUDEN);
+}
+
+void am335x_pinmux_mmc0(int cd, int sk_evm)
+{
+	write32(&regs->mmc0_dat0, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mmc0_dat1, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mmc0_dat2, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mmc0_dat3, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mmc0_clk, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mmc0_cmd, MODE(0) | RXACTIVE | PULLUP_EN);
+	if (!sk_evm) {
+		// MMC0_WP
+		write32(&regs->mcasp0_aclkr, MODE(4) | RXACTIVE);
+	}
+	if (cd) {
+		// MMC0_CD
+		write32(&regs->spi0_cs1, MODE(5) | RXACTIVE | PULLUP_EN);
+	}
+}
+
+void am335x_pinmux_mmc1(void)
+{
+	// MMC1_DAT0
+	write32(&regs->gpmc_ad0, MODE(1) | RXACTIVE | PULLUP_EN);
+	// MMC1_DAT1
+	write32(&regs->gpmc_ad1, MODE(1) | RXACTIVE | PULLUP_EN);
+	// MMC1_DAT2
+	write32(&regs->gpmc_ad2, MODE(1) | RXACTIVE | PULLUP_EN);
+	// MMC1_DAT3
+	write32(&regs->gpmc_ad3, MODE(1) | RXACTIVE | PULLUP_EN);
+	// MMC1_CLK
+	write32(&regs->gpmc_csn1, MODE(2) | RXACTIVE | PULLUP_EN);
+	// MMC1_CMD
+	write32(&regs->gpmc_csn2, MODE(2) | RXACTIVE | PULLUP_EN);
+	// MMC1_WP
+	write32(&regs->gpmc_csn0, MODE(7) | RXACTIVE | PULLUP_EN);
+	// MMC1_CD
+	write32(&regs->gpmc_advn_ale, MODE(7) | RXACTIVE | PULLUP_EN);
+}
+
+void am335x_pinmux_i2c0(void)
+{
+	write32(&regs->i2c0_sda, MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL);
+	write32(&regs->i2c0_scl, MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL);
+}
+
+void am335x_pinmux_i2c1(void)
+{
+	// I2C_DATA
+	write32(&regs->spi0_d1, MODE(2) | RXACTIVE | PULLUDEN | SLEWCTRL);
+	// I2C_SCLK
+	write32(&regs->spi0_cs0, MODE(2) | RXACTIVE | PULLUDEN | SLEWCTRL);
+}
+
+void am335x_pinmux_spi0(void)
+{
+	write32(&regs->spi0_sclk, MODE(0) | RXACTIVE | PULLUDEN);
+	write32(&regs->spi0_d0, MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN);
+	write32(&regs->spi0_d1, MODE(0) | RXACTIVE | PULLUDEN);
+	write32(&regs->spi0_cs0, MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN);
+}
+
+void am335x_pinmux_gpio0_7(void)
+{
+	write32(&regs->ecap0_in_pwm0_out, MODE(7) | PULLUDEN);
+}
+
+void am335x_pinmux_rgmii1(void)
+{
+	write32(&regs->mii1_txen, MODE(2));
+	write32(&regs->mii1_rxdv, MODE(2) | RXACTIVE);
+	write32(&regs->mii1_txd0, MODE(2));
+	write32(&regs->mii1_txd1, MODE(2));
+	write32(&regs->mii1_txd2, MODE(2));
+	write32(&regs->mii1_txd3, MODE(2));
+	write32(&regs->mii1_txclk, MODE(2));
+	write32(&regs->mii1_rxclk, MODE(2) | RXACTIVE);
+	write32(&regs->mii1_rxd0, MODE(2) | RXACTIVE);
+	write32(&regs->mii1_rxd1, MODE(2) | RXACTIVE);
+	write32(&regs->mii1_rxd2, MODE(2) | RXACTIVE);
+	write32(&regs->mii1_rxd3, MODE(2) | RXACTIVE);
+}
+
+void am335x_pinmux_mii1(void)
+{
+	write32(&regs->mii1_rxerr, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_txen, MODE(0));
+	write32(&regs->mii1_rxdv, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_txd0, MODE(0));
+	write32(&regs->mii1_txd1, MODE(0));
+	write32(&regs->mii1_txd2, MODE(0));
+	write32(&regs->mii1_txd3, MODE(0));
+	write32(&regs->mii1_txclk, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_rxclk, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_rxd0, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_rxd1, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_rxd2, MODE(0) | RXACTIVE);
+	write32(&regs->mii1_rxd3, MODE(0) | RXACTIVE);
+	write32(&regs->mdio_data, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->mdio_clk, MODE(0) | PULLUP_EN);
+}
+
+void am335x_pinmux_nand(void)
+{
+	write32(&regs->gpmc_ad0, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad1, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad2, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad3, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad4, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad5, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad6, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_ad7, MODE(0) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_wait0, MODE(0) | RXACTIVE | PULLUP_EN);
+	write32(&regs->gpmc_wpn, MODE(7) | PULLUP_EN | RXACTIVE);
+	write32(&regs->gpmc_csn0, MODE(0) | PULLUDEN);
+	write32(&regs->gpmc_advn_ale, MODE(0) | PULLUDEN);
+	write32(&regs->gpmc_oen_ren, MODE(0) | PULLUDEN);
+	write32(&regs->gpmc_wen, MODE(0) | PULLUDEN);
+	write32(&regs->gpmc_be0n_cle, MODE(0) | PULLUDEN);
+}
diff --git a/src/soc/ti/am335x/pinmux.h b/src/soc/ti/am335x/pinmux.h
new file mode 100644
index 0000000..c46d03d
--- /dev/null
+++ b/src/soc/ti/am335x/pinmux.h
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef __SOC_TI_AM335X_PINMUX_H
+#define __SOC_TI_AM335X_PINMUX_H
+
+#include <stdint.h>
+
+// PAD Control Fields
+#define SLEWCTRL	(0x1 << 6)
+#define RXACTIVE	(0x1 << 5)
+#define PULLDOWN_EN	(0x0 << 4) // Pull down
+#define PULLUP_EN	(0x1 << 4) // Pull up
+#define PULLUDEN	(0x0 << 3) // Pull up enabled
+#define PULLUDDIS	(0x1 << 3) // Pull up disabled
+#define MODE(val)	val
+
+void am335x_pinmux_uart0(void);
+void am335x_pinmux_uart1(void);
+void am335x_pinmux_uart2(void);
+void am335x_pinmux_uart3(void);
+void am335x_pinmux_uart4(void);
+void am335x_pinmux_uart5(void);
+
+void am335x_pinmux_mmc0(int cd, int sk_evm);
+void am335x_pinmux_mmc1(void);
+
+void am335x_pinmux_i2c0(void);
+void am335x_pinmux_i2c1(void);
+
+void am335x_pinmux_spi0(void);
+
+void am335x_pinmux_gpio0_7(void);
+
+void am335x_pinmux_rgmii1(void);
+void am335x_pinmux_mii1(void);
+
+void am335x_pinmux_nand(void);
+
+#define AM335X_PINMUX_REG_ADDR 0x44e10800
+
+struct am335x_pinmux_regs {
+	uint32_t gpmc_ad0;
+	uint32_t gpmc_ad1;
+	uint32_t gpmc_ad2;
+	uint32_t gpmc_ad3;
+	uint32_t gpmc_ad4;
+	uint32_t gpmc_ad5;
+	uint32_t gpmc_ad6;
+	uint32_t gpmc_ad7;
+	uint32_t gpmc_ad8;
+	uint32_t gpmc_ad9;
+	uint32_t gpmc_ad10;
+	uint32_t gpmc_ad11;
+	uint32_t gpmc_ad12;
+	uint32_t gpmc_ad13;
+	uint32_t gpmc_ad14;
+	uint32_t gpmc_ad15;
+	uint32_t gpmc_a0;
+	uint32_t gpmc_a1;
+	uint32_t gpmc_a2;
+	uint32_t gpmc_a3;
+	uint32_t gpmc_a4;
+	uint32_t gpmc_a5;
+	uint32_t gpmc_a6;
+	uint32_t gpmc_a7;
+	uint32_t gpmc_a8;
+	uint32_t gpmc_a9;
+	uint32_t gpmc_a10;
+	uint32_t gpmc_a11;
+	uint32_t gpmc_wait0;
+	uint32_t gpmc_wpn;
+	uint32_t gpmc_be1n;
+	uint32_t gpmc_csn0;
+	uint32_t gpmc_csn1;
+	uint32_t gpmc_csn2;
+	uint32_t gpmc_csn3;
+	uint32_t gpmc_clk;
+	uint32_t gpmc_advn_ale;
+	uint32_t gpmc_oen_ren;
+	uint32_t gpmc_wen;
+	uint32_t gpmc_be0n_cle;
+	uint32_t lcd_data0;
+	uint32_t lcd_data1;
+	uint32_t lcd_data2;
+	uint32_t lcd_data3;
+	uint32_t lcd_data4;
+	uint32_t lcd_data5;
+	uint32_t lcd_data6;
+	uint32_t lcd_data7;
+	uint32_t lcd_data8;
+	uint32_t lcd_data9;
+	uint32_t lcd_data10;
+	uint32_t lcd_data11;
+	uint32_t lcd_data12;
+	uint32_t lcd_data13;
+	uint32_t lcd_data14;
+	uint32_t lcd_data15;
+	uint32_t lcd_vsync;
+	uint32_t lcd_hsync;
+	uint32_t lcd_pclk;
+	uint32_t lcd_ac_bias_en;
+	uint32_t mmc0_dat3;
+	uint32_t mmc0_dat2;
+	uint32_t mmc0_dat1;
+	uint32_t mmc0_dat0;
+	uint32_t mmc0_clk;
+	uint32_t mmc0_cmd;
+	uint32_t mii1_col;
+	uint32_t mii1_crs;
+	uint32_t mii1_rxerr;
+	uint32_t mii1_txen;
+	uint32_t mii1_rxdv;
+	uint32_t mii1_txd3;
+	uint32_t mii1_txd2;
+	uint32_t mii1_txd1;
+	uint32_t mii1_txd0;
+	uint32_t mii1_txclk;
+	uint32_t mii1_rxclk;
+	uint32_t mii1_rxd3;
+	uint32_t mii1_rxd2;
+	uint32_t mii1_rxd1;
+	uint32_t mii1_rxd0;
+	uint32_t rmii1_refclk;
+	uint32_t mdio_data;
+	uint32_t mdio_clk;
+	uint32_t spi0_sclk;
+	uint32_t spi0_d0;
+	uint32_t spi0_d1;
+	uint32_t spi0_cs0;
+	uint32_t spi0_cs1;
+	uint32_t ecap0_in_pwm0_out;
+	uint32_t uart0_ctsn;
+	uint32_t uart0_rtsn;
+	uint32_t uart0_rxd;
+	uint32_t uart0_txd;
+	uint32_t uart1_ctsn;
+	uint32_t uart1_rtsn;
+	uint32_t uart1_rxd;
+	uint32_t uart1_txd;
+	uint32_t i2c0_sda;
+	uint32_t i2c0_scl;
+	uint32_t mcasp0_aclkx;
+	uint32_t mcasp0_fsx;
+	uint32_t mcasp0_axr0;
+	uint32_t mcasp0_ahclkr;
+	uint32_t mcasp0_aclkr;
+	uint32_t mcasp0_fsr;
+	uint32_t mcasp0_axr1;
+	uint32_t mcasp0_ahclkx;
+	uint32_t xdma_event_intr0;
+	uint32_t xdma_event_intr1;
+	uint32_t nresetin_out;
+	uint32_t porz;
+	uint32_t nnmi;
+	uint32_t osc0_in;
+	uint32_t osc0_out;
+	uint32_t rsvd1;
+	uint32_t tms;
+	uint32_t tdi;
+	uint32_t tdo;
+	uint32_t tck;
+	uint32_t ntrst;
+	uint32_t emu0;
+	uint32_t emu1;
+	uint32_t osc1_in;
+	uint32_t osc1_out;
+	uint32_t pmic_power_en;
+	uint32_t rtc_porz;
+	uint32_t rsvd2;
+	uint32_t ext_wakeup;
+	uint32_t enz_kaldo_1p8v;
+	uint32_t usb0_dm;
+	uint32_t usb0_dp;
+	uint32_t usb0_ce;
+	uint32_t usb0_id;
+	uint32_t usb0_vbus;
+	uint32_t usb0_drvvbus;
+	uint32_t usb1_dm;
+	uint32_t usb1_dp;
+	uint32_t usb1_ce;
+	uint32_t usb1_id;
+	uint32_t usb1_vbus;
+	uint32_t usb1_drvvbus;
+	uint32_t ddr_resetn;
+	uint32_t ddr_csn0;
+	uint32_t ddr_cke;
+	uint32_t ddr_ck;
+	uint32_t ddr_nck;
+	uint32_t ddr_casn;
+	uint32_t ddr_rasn;
+	uint32_t ddr_wen;
+	uint32_t ddr_ba0;
+	uint32_t ddr_ba1;
+	uint32_t ddr_ba2;
+	uint32_t ddr_a0;
+	uint32_t ddr_a1;
+	uint32_t ddr_a2;
+	uint32_t ddr_a3;
+	uint32_t ddr_a4;
+	uint32_t ddr_a5;
+	uint32_t ddr_a6;
+	uint32_t ddr_a7;
+	uint32_t ddr_a8;
+	uint32_t ddr_a9;
+	uint32_t ddr_a10;
+	uint32_t ddr_a11;
+	uint32_t ddr_a12;
+	uint32_t ddr_a13;
+	uint32_t ddr_a14;
+	uint32_t ddr_a15;
+	uint32_t ddr_odt;
+	uint32_t ddr_d0;
+	uint32_t ddr_d1;
+	uint32_t ddr_d2;
+	uint32_t ddr_d3;
+	uint32_t ddr_d4;
+	uint32_t ddr_d5;
+	uint32_t ddr_d6;
+	uint32_t ddr_d7;
+	uint32_t ddr_d8;
+	uint32_t ddr_d9;
+	uint32_t ddr_d10;
+	uint32_t ddr_d11;
+	uint32_t ddr_d12;
+	uint32_t ddr_d13;
+	uint32_t ddr_d14;
+	uint32_t ddr_d15;
+	uint32_t ddr_dqm0;
+	uint32_t ddr_dqm1;
+	uint32_t ddr_dqs0;
+	uint32_t ddr_dqsn0;
+	uint32_t ddr_dqs1;
+	uint32_t ddr_dqsn1;
+	uint32_t ddr_vref;
+	uint32_t ddr_vtp;
+	uint32_t ddr_strben0;
+	uint32_t ddr_strben1;
+	uint32_t ain7;
+	uint32_t ain6;
+	uint32_t ain5;
+	uint32_t ain4;
+	uint32_t ain3;
+	uint32_t ain2;
+	uint32_t ain1;
+	uint32_t ain0;
+	uint32_t vrefp;
+	uint32_t vrefn;
+};
+
+#endif
diff --git a/src/soc/ti/am335x/soc.c b/src/soc/ti/am335x/soc.c
new file mode 100644
index 0000000..0362ed9
--- /dev/null
+++ b/src/soc/ti/am335x/soc.c
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/device.h>
+
+struct chip_operations soc_ti_am335x_ops = {
+	CHIP_NAME("TI AM335X")
+};
diff --git a/src/soc/ti/am335x/uart.c b/src/soc/ti/am335x/uart.c
new file mode 100644
index 0000000..90095d4
--- /dev/null
+++ b/src/soc/ti/am335x/uart.c
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <types.h>
+#include <console/uart.h>
+#include <device/mmio.h>
+#include <boot/coreboot_tables.h>
+#include <soc/ti/am335x/uart.h>
+
+#define EFR_ENHANCED_EN		(1 << 4)
+#define FCR_FIFO_EN		(1 << 0)
+#define MCR_TCR_TLR		(1 << 6)
+#define SYSC_SOFTRESET		(1 << 1)
+#define SYSS_RESETDONE		(1 << 0)
+
+#define LSR_RXFIFOE		(1 << 0)
+#define LSR_TXFIFOE		(1 << 5)
+
+/*
+ * Initialise the serial port with the given baudrate divisor. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ */
+static void am335x_uart_init(struct am335x_uart *uart, uint16_t div)
+{
+	uint16_t lcr_orig, efr_orig, mcr_orig;
+
+	/* reset the UART */
+	write16(&uart->sysc, uart->sysc | SYSC_SOFTRESET);
+	while (!(read16(&uart->syss) & SYSS_RESETDONE))
+		;
+
+	/* 1. switch to register config mode B */
+	lcr_orig = read16(&uart->lcr);
+	write16(&uart->lcr, 0xbf);
+
+	/*
+	 * 2. Set EFR ENHANCED_EN bit. To access this bit, registers must
+	 * be in TCR_TLR submode, meaning EFR[4] = 1 and MCR[6] = 1.
+	 */
+	efr_orig = read16(&uart->efr);
+	write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
+
+	/* 3. Switch to register config mode A */
+	write16(&uart->lcr, 0x80);
+
+	/* 4. Enable register submode TCR_TLR to access the UARTi.UART_TLR */
+	mcr_orig = read16(&uart->mcr);
+	write16(&uart->mcr, mcr_orig | MCR_TCR_TLR);
+
+	/* 5. Enable the FIFO. For now we'll ignore FIFO triggers and DMA */
+	write16(&uart->fcr, FCR_FIFO_EN);
+
+	/* 6. Switch to configuration mode B */
+	write16(&uart->lcr, 0xbf);
+	/* Skip steps 7 and 8 (setting up FIFO triggers for DMA) */
+
+	/* 9. Restore original EFR value */
+	write16(&uart->efr, efr_orig);
+
+	/* 10. Switch to config mode A */
+	write16(&uart->lcr, 0x80);
+
+	/* 11. Restore original MCR value */
+	write16(&uart->mcr, mcr_orig);
+
+	/* 12. Restore original LCR value */
+	write16(&uart->lcr, lcr_orig);
+
+	/* Protocol, baud rate and interrupt settings */
+
+	/* 1. Disable UART access to DLL and DLH registers */
+	write16(&uart->mdr1, read16(&uart->mdr1) | 0x7);
+
+	/* 2. Switch to config mode B */
+	write16(&uart->lcr, 0xbf);
+
+	/* 3. Enable access to IER[7:4] */
+	write16(&uart->efr, efr_orig | EFR_ENHANCED_EN);
+
+	/* 4. Switch to operational mode */
+	write16(&uart->lcr, 0x0);
+
+	/* 5. Clear IER */
+	write16(&uart->ier, 0x0);
+
+	/* 6. Switch to config mode B */
+	write16(&uart->lcr, 0xbf);
+
+	/* 7. Set dll and dlh to the desired values (table 19-25) */
+	write16(&uart->dlh, (div >> 8));
+	write16(&uart->dll, (div & 0xff));
+
+	/* 8. Switch to operational mode to access ier */
+	write16(&uart->lcr, 0x0);
+
+	/* 9. Clear ier to disable all interrupts */
+	write16(&uart->ier, 0x0);
+
+	/* 10. Switch to config mode B */
+	write16(&uart->lcr, 0xbf);
+
+	/* 11. Restore efr */
+	write16(&uart->efr, efr_orig);
+
+	/* 12. Set protocol formatting 8n1 (8 bit data, no parity, 1 stop bit) */
+	write16(&uart->lcr, 0x3);
+
+	/* 13. Load the new UART mode */
+	write16(&uart->mdr1, 0x0);
+}
+
+/*
+ * Read a single byte from the serial port. Returns 1 on success, 0
+ * otherwise. When the function is successful, the character read is
+ * written into its argument c.
+ */
+static unsigned char am335x_uart_rx_byte(struct am335x_uart *uart)
+{
+	while (!(read16(&uart->lsr) & LSR_RXFIFOE));
+
+	return read8(&uart->rhr);
+}
+
+/*
+ * Output a single byte to the serial port.
+ */
+static void am335x_uart_tx_byte(struct am335x_uart *uart, unsigned char data)
+{
+	while (!(read16(&uart->lsr) & LSR_TXFIFOE));
+
+	return write8(&uart->thr, data);
+}
+
+unsigned int uart_platform_refclk(void)
+{
+	return 48000000;
+}
+
+uintptr_t uart_platform_base(int idx)
+{
+	const unsigned int bases[] = {
+		0x44e09000, 0x48022000, 0x48024000,
+		0x481a6000, 0x481a8000, 0x481aa000
+	};
+	if (idx < ARRAY_SIZE(bases))
+		return bases[idx];
+	return 0;
+}
+
+void uart_init(int idx)
+{
+	struct am335x_uart *uart = uart_platform_baseptr(idx);
+	uint16_t div = (uint16_t) uart_baudrate_divisor(
+		get_uart_baudrate(), uart_platform_refclk(), 16);
+	am335x_uart_init(uart, div);
+}
+
+unsigned char uart_rx_byte(int idx)
+{
+	struct am335x_uart *uart = uart_platform_baseptr(idx);
+	return am335x_uart_rx_byte(uart);
+}
+
+void uart_tx_byte(int idx, unsigned char data)
+{
+	struct am335x_uart *uart = uart_platform_baseptr(idx);
+	am335x_uart_tx_byte(uart, data);
+}
+
+void uart_tx_flush(int idx)
+{
+}
+
+void uart_fill_lb(void *data)
+{
+	struct lb_serial serial;
+	serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
+	serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
+	serial.baud = get_uart_baudrate();
+	serial.regwidth = 2;
+	serial.input_hertz = uart_platform_refclk();
+	serial.uart_pci_addr = CONFIG_UART_PCI_ADDR;
+	lb_add_serial(&serial, data);
+
+	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
+}
diff --git a/src/soc/ti/am335x/uart.h b/src/soc/ti/am335x/uart.h
new file mode 100644
index 0000000..664d57d
--- /dev/null
+++ b/src/soc/ti/am335x/uart.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef AM335X_UART_H
+#define AM335X_UART_H
+
+#include <stdint.h>
+
+#define AM335X_UART0_BASE	0x44e09000
+#define AM335X_UART1_BASE	0x48020000
+#define AM335X_UART2_BASE	0x48024000
+#define AM335X_UART3_BASE	0x481A6000
+#define AM335X_UART4_BASE	0x481A8000
+#define AM335X_UART5_BASE	0x481AA000
+
+/*
+ * The meaning of some AM335x UART register offsets changes depending on read
+ * or write operation as well as various modes. See section 19.3.7.1.2 for
+ * register access submode description and 19.5.1 for register descriptions.
+ */
+struct am335x_uart {
+	union {
+		/* operational mode */
+		uint16_t rhr;		/* receiver holding (read) */
+		uint16_t thr;		/* transmit holding (write) */
+		/* config mode A and B */
+		uint16_t dll;		/* divisor latches low */
+	};
+	uint8_t rsvd_0x02[2];
+	union {
+		/* operational mode */
+		uint16_t ier;		/* interrupt enable */
+		/* config mode A and B */
+		uint16_t dlh;		/* divisor latches high */
+	};
+	uint8_t rsvd_0x06[2];
+	union {
+		/* operational mode, config mode A */
+		uint16_t iir;		/* interrupt ID (read) */
+		uint16_t fcr;		/* FIFO control (write) */
+		/* config mode B */
+		uint16_t efr;
+	};
+	uint8_t rsvd_0x0a[2];
+	uint16_t lcr;			/* line control */
+	uint8_t rsvd_0x0e[2];
+
+	/* 0x10 */
+	union {
+		/* operational mode, config mode A */
+		uint16_t mcr;		/* modem control */
+		/* config mode B */
+		uint16_t xon1;		/* XON1 character (UART mode) */
+		uint16_t addr1;		/* address 1 (IrDA mode)  */
+	};
+	uint8_t rsvd_0x12[2];
+	union {
+		/* operational mode, config mode A */
+		uint16_t lsr;		/* line status, read-only */
+		/* config mode B */
+		uint16_t xon2;		/* XON2 character (UART mode) */
+		uint16_t addr2;		/* IrDA mode (IrDA mode) */
+	};
+	uint8_t rsvd_0x16[2];
+
+	/*
+	 * Bytes 0x18 and 0x1c depend on submode TCR_TLR. When EFR[4] = 1 and
+	 * MCR[6] = 1, transmission control register and trigger level register
+	 * will be read/written. If not, the modem status register and the
+	 * scratchpad register will be affected by read/write.
+	 */
+	union {
+		/* operational mode and config mode A */
+		uint16_t msr;		/* modem status */
+		/* config mode B */
+		uint16_t xoff1;		/* xoff1 character (UART MODE) */
+		/* submode TCR_TLR */
+		uint16_t tcr;		/* transmission control */
+	};
+	uint8_t rsvd_0x1a[2];
+	union {
+		uint16_t spr;		/* scratchpad */
+		/* config mode B */
+		uint16_t xoff2;		/* xoff2 character (UART mode) */
+		/* submode TCR_TLR */
+		uint16_t tlr;		/* trigger level */
+	};
+	uint8_t rsvd_0x1e[2];
+
+	/* 0x20 */
+	uint16_t mdr1;			/* mode definition 1 */
+	uint8_t rsvd_0x22[2];
+	uint16_t mdr2;			/* mode definition 2 */
+	uint8_t rsvd_0x26[2];
+	union {
+		uint16_t sflsr;		/* status FIFO line status reg (read) */
+		uint16_t txfll;		/* transmit frame length low (write) */
+	};
+	uint8_t rsvd_0x2a[2];
+	union {
+		uint16_t resume;	/* resume halted operation (read) */
+		uint16_t txflh;		/* transmit frame length high (write) */
+	};
+	uint8_t rsvd_0x2e[2];
+
+	/* 0x30 */
+	union {
+		uint16_t sfregl;	/* status FIFO low (read) */
+		uint16_t rxfll;		/* received frame length low (write) */
+	};
+	uint8_t rsvd_0x32[2];
+	union {
+		uint16_t sfregh;	/* status FIFO high (read) */
+		uint16_t rxflh;		/* received frame length high (write) */
+	};
+	uint8_t rsvd_0x36[2];
+	uint16_t blr;			/* BOF control */
+	uint8_t rsvd_0x3a[2];
+	uint16_t acreg;			/* auxiliary control */
+	uint8_t rsvd_0x3e[2];
+
+	/* 0x40 */
+	uint16_t scr;			/* supplementary control */
+	uint8_t rsvd_0x42[2];
+	uint16_t ssr;			/* supplementary status */
+	uint8_t rsvd_0x46[2];
+
+	uint16_t eblr;			/* BOF length (operational mode only) */
+	uint8_t rsvd_0x4a[6];
+
+	/* 0x50 */
+	uint16_t mvr;			/* module version (read-only) */
+	uint8_t rsvd_0x52[2];
+	uint16_t sysc;			/* system config */
+	uint8_t rsvd_0x56[2];
+	uint16_t syss;			/* system status (read-only) */
+	uint8_t rsvd_0x5a[2];
+	uint16_t wer;			/* wake-up enable */
+	uint8_t rsvd_0x5e[2];
+
+	/* 0x60 */
+	uint16_t cfps;			/* carrier prescale frequency */
+	uint8_t rsvd_0x62[2];
+	uint16_t rxfifo_lvl;		/* received FIFO level */
+	uint8_t rsvd_0x66[2];
+	uint16_t txfifo_lvl;		/* transmit FIFO level */
+	uint8_t rsvd_0x6a[2];
+	uint16_t ier2;			/* RX/TX FIFO empty interrupt enable */
+	uint8_t rsvd_0x6e[2];
+
+	/* 0x70 */
+	uint16_t isr2;			/* RX/TX FIFO empty interrupt status */
+	uint8_t rsvd_0x72[2];
+	uint16_t freq_sel;		/* frequency select */
+	uint8_t rsvd_0x76[10];
+
+	/* 0x80 */
+	uint16_t mdr3;			/* mode definition register 3 */
+	uint8_t rsvd_0x82[2];
+	uint16_t txdma;			/* TX DMA threshold */
+
+} __packed;
+
+#endif	/* AM335X_UART_H */