From ad7b2e23ab5954f150a4b2f62378f1e7133e56c9 Mon Sep 17 00:00:00 2001 From: Sam Lewis Date: Mon, 3 Aug 2020 20:18:29 +1000 Subject: 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 Reviewed-on: https://review.coreboot.org/c/coreboot/+/44378 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Rudolph --- src/soc/ti/Kconfig | 1 + src/soc/ti/Makefile.inc | 1 + src/soc/ti/am335x/Kconfig | 18 +++ src/soc/ti/am335x/Makefile.inc | 56 ++++++++ src/soc/ti/am335x/bootblock.c | 16 +++ src/soc/ti/am335x/bootblock_media.c | 13 ++ src/soc/ti/am335x/cbmem.c | 9 ++ src/soc/ti/am335x/clock.h | 222 ++++++++++++++++++++++++++++++++ src/soc/ti/am335x/dmtimer.c | 12 ++ src/soc/ti/am335x/dmtimer.h | 13 ++ src/soc/ti/am335x/gpio.c | 77 +++++++++++ src/soc/ti/am335x/gpio.h | 58 +++++++++ src/soc/ti/am335x/header.c | 57 ++++++++ src/soc/ti/am335x/header.h | 50 ++++++++ src/soc/ti/am335x/header.ld | 8 ++ src/soc/ti/am335x/memlayout.ld | 28 ++++ src/soc/ti/am335x/monotonic_timer.c | 40 ++++++ src/soc/ti/am335x/nand.c | 9 ++ src/soc/ti/am335x/pinmux.c | 171 ++++++++++++++++++++++++ src/soc/ti/am335x/pinmux.h | 250 ++++++++++++++++++++++++++++++++++++ src/soc/ti/am335x/soc.c | 7 + src/soc/ti/am335x/uart.c | 185 ++++++++++++++++++++++++++ src/soc/ti/am335x/uart.h | 163 +++++++++++++++++++++++ 23 files changed, 1464 insertions(+) create mode 100644 src/soc/ti/Kconfig create mode 100644 src/soc/ti/Makefile.inc create mode 100644 src/soc/ti/am335x/Kconfig create mode 100644 src/soc/ti/am335x/Makefile.inc create mode 100644 src/soc/ti/am335x/bootblock.c create mode 100644 src/soc/ti/am335x/bootblock_media.c create mode 100644 src/soc/ti/am335x/cbmem.c create mode 100644 src/soc/ti/am335x/clock.h create mode 100644 src/soc/ti/am335x/dmtimer.c create mode 100644 src/soc/ti/am335x/dmtimer.h create mode 100644 src/soc/ti/am335x/gpio.c create mode 100644 src/soc/ti/am335x/gpio.h create mode 100644 src/soc/ti/am335x/header.c create mode 100644 src/soc/ti/am335x/header.h create mode 100644 src/soc/ti/am335x/header.ld create mode 100644 src/soc/ti/am335x/memlayout.ld create mode 100644 src/soc/ti/am335x/monotonic_timer.c create mode 100644 src/soc/ti/am335x/nand.c create mode 100644 src/soc/ti/am335x/pinmux.c create mode 100644 src/soc/ti/am335x/pinmux.h create mode 100644 src/soc/ti/am335x/soc.c create mode 100644 src/soc/ti/am335x/uart.c create mode 100644 src/soc/ti/am335x/uart.h (limited to 'src/soc/ti') diff --git a/src/soc/ti/Kconfig b/src/soc/ti/Kconfig new file mode 100644 index 0000000000..eb66519f2e --- /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 0000000000..357cc82e18 --- /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 0000000000..533a0de628 --- /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 0000000000..2865338217 --- /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 0000000000..985e1a1a0b --- /dev/null +++ b/src/soc/ti/am335x/bootblock.c @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +#include +#include + +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 0000000000..050e0b77da --- /dev/null +++ b/src/soc/ti/am335x/bootblock_media.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include + +/* 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 0000000000..3765874ebe --- /dev/null +++ b/src/soc/ti/am335x/cbmem.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include + +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 0000000000..38b4ece249 --- /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 + +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 0000000000..b3aa7a18ba --- /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 0000000000..ad8515fbba --- /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 + +#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 0000000000..d3d3581f86 --- /dev/null +++ b/src/soc/ti/am335x/gpio.c @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include +#include + +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(®s->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(®s->setdataout, bit); + else + write32(®s->cleardataout, bit); + clrbits32(®s->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(®s->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(®s->setdataout, bit); + else + write32(®s->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 0000000000..0877a6258c --- /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 + +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 0000000000..9edfdd062b --- /dev/null +++ b/src/soc/ti/am335x/header.c @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include + +#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 0000000000..a0a54ad0f3 --- /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 + +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 0000000000..84e01362b1 --- /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 0000000000..78528e63b7 --- /dev/null +++ b/src/soc/ti/am335x/memlayout.ld @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +#include + +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 0000000000..b57258b6c8 --- /dev/null +++ b/src/soc/ti/am335x/monotonic_timer.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include + +#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 0000000000..a7029a02d6 --- /dev/null +++ b/src/soc/ti/am335x/nand.c @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +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 0000000000..8cf888405f --- /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 + +static struct am335x_pinmux_regs *regs = + (struct am335x_pinmux_regs *)(uintptr_t)AM335X_PINMUX_REG_ADDR; + +void am335x_pinmux_uart0(void) +{ + write32(®s->uart0_rxd, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->uart0_txd, MODE(0) | PULLUDEN); +} + +void am335x_pinmux_uart1(void) +{ + write32(®s->uart1_rxd, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->uart1_txd, MODE(0) | PULLUDEN); +} + +void am335x_pinmux_uart2(void) +{ + // UART2_RXD + write32(®s->spi0_sclk, MODE(1) | PULLUP_EN | RXACTIVE); + // UART2_TXD + write32(®s->spi0_d0, MODE(1) | PULLUDEN); +} + +void am335x_pinmux_uart3(void) +{ + // UART3_RXD + write32(®s->spi0_cs1, MODE(1) | PULLUP_EN | RXACTIVE); + // UART3_TXD + write32(®s->ecap0_in_pwm0_out, MODE(1) | PULLUDEN); +} + +void am335x_pinmux_uart4(void) +{ + // UART4_RXD + write32(®s->gpmc_wait0, MODE(6) | PULLUP_EN | RXACTIVE); + // UART4_TXD + write32(®s->gpmc_wpn, MODE(6) | PULLUDEN); +} + +void am335x_pinmux_uart5(void) +{ + // UART5_RXD + write32(®s->lcd_data9, MODE(4) | PULLUP_EN | RXACTIVE); + // UART5_TXD + write32(®s->lcd_data8, MODE(4) | PULLUDEN); +} + +void am335x_pinmux_mmc0(int cd, int sk_evm) +{ + write32(®s->mmc0_dat0, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mmc0_dat1, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mmc0_dat2, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mmc0_dat3, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mmc0_clk, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mmc0_cmd, MODE(0) | RXACTIVE | PULLUP_EN); + if (!sk_evm) { + // MMC0_WP + write32(®s->mcasp0_aclkr, MODE(4) | RXACTIVE); + } + if (cd) { + // MMC0_CD + write32(®s->spi0_cs1, MODE(5) | RXACTIVE | PULLUP_EN); + } +} + +void am335x_pinmux_mmc1(void) +{ + // MMC1_DAT0 + write32(®s->gpmc_ad0, MODE(1) | RXACTIVE | PULLUP_EN); + // MMC1_DAT1 + write32(®s->gpmc_ad1, MODE(1) | RXACTIVE | PULLUP_EN); + // MMC1_DAT2 + write32(®s->gpmc_ad2, MODE(1) | RXACTIVE | PULLUP_EN); + // MMC1_DAT3 + write32(®s->gpmc_ad3, MODE(1) | RXACTIVE | PULLUP_EN); + // MMC1_CLK + write32(®s->gpmc_csn1, MODE(2) | RXACTIVE | PULLUP_EN); + // MMC1_CMD + write32(®s->gpmc_csn2, MODE(2) | RXACTIVE | PULLUP_EN); + // MMC1_WP + write32(®s->gpmc_csn0, MODE(7) | RXACTIVE | PULLUP_EN); + // MMC1_CD + write32(®s->gpmc_advn_ale, MODE(7) | RXACTIVE | PULLUP_EN); +} + +void am335x_pinmux_i2c0(void) +{ + write32(®s->i2c0_sda, MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL); + write32(®s->i2c0_scl, MODE(0) | RXACTIVE | PULLUDEN | SLEWCTRL); +} + +void am335x_pinmux_i2c1(void) +{ + // I2C_DATA + write32(®s->spi0_d1, MODE(2) | RXACTIVE | PULLUDEN | SLEWCTRL); + // I2C_SCLK + write32(®s->spi0_cs0, MODE(2) | RXACTIVE | PULLUDEN | SLEWCTRL); +} + +void am335x_pinmux_spi0(void) +{ + write32(®s->spi0_sclk, MODE(0) | RXACTIVE | PULLUDEN); + write32(®s->spi0_d0, MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN); + write32(®s->spi0_d1, MODE(0) | RXACTIVE | PULLUDEN); + write32(®s->spi0_cs0, MODE(0) | RXACTIVE | PULLUDEN | PULLUP_EN); +} + +void am335x_pinmux_gpio0_7(void) +{ + write32(®s->ecap0_in_pwm0_out, MODE(7) | PULLUDEN); +} + +void am335x_pinmux_rgmii1(void) +{ + write32(®s->mii1_txen, MODE(2)); + write32(®s->mii1_rxdv, MODE(2) | RXACTIVE); + write32(®s->mii1_txd0, MODE(2)); + write32(®s->mii1_txd1, MODE(2)); + write32(®s->mii1_txd2, MODE(2)); + write32(®s->mii1_txd3, MODE(2)); + write32(®s->mii1_txclk, MODE(2)); + write32(®s->mii1_rxclk, MODE(2) | RXACTIVE); + write32(®s->mii1_rxd0, MODE(2) | RXACTIVE); + write32(®s->mii1_rxd1, MODE(2) | RXACTIVE); + write32(®s->mii1_rxd2, MODE(2) | RXACTIVE); + write32(®s->mii1_rxd3, MODE(2) | RXACTIVE); +} + +void am335x_pinmux_mii1(void) +{ + write32(®s->mii1_rxerr, MODE(0) | RXACTIVE); + write32(®s->mii1_txen, MODE(0)); + write32(®s->mii1_rxdv, MODE(0) | RXACTIVE); + write32(®s->mii1_txd0, MODE(0)); + write32(®s->mii1_txd1, MODE(0)); + write32(®s->mii1_txd2, MODE(0)); + write32(®s->mii1_txd3, MODE(0)); + write32(®s->mii1_txclk, MODE(0) | RXACTIVE); + write32(®s->mii1_rxclk, MODE(0) | RXACTIVE); + write32(®s->mii1_rxd0, MODE(0) | RXACTIVE); + write32(®s->mii1_rxd1, MODE(0) | RXACTIVE); + write32(®s->mii1_rxd2, MODE(0) | RXACTIVE); + write32(®s->mii1_rxd3, MODE(0) | RXACTIVE); + write32(®s->mdio_data, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->mdio_clk, MODE(0) | PULLUP_EN); +} + +void am335x_pinmux_nand(void) +{ + write32(®s->gpmc_ad0, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad1, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad2, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad3, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad4, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad5, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad6, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_ad7, MODE(0) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_wait0, MODE(0) | RXACTIVE | PULLUP_EN); + write32(®s->gpmc_wpn, MODE(7) | PULLUP_EN | RXACTIVE); + write32(®s->gpmc_csn0, MODE(0) | PULLUDEN); + write32(®s->gpmc_advn_ale, MODE(0) | PULLUDEN); + write32(®s->gpmc_oen_ren, MODE(0) | PULLUDEN); + write32(®s->gpmc_wen, MODE(0) | PULLUDEN); + write32(®s->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 0000000000..c46d03dbc9 --- /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 + +// 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 0000000000..0362ed9c0c --- /dev/null +++ b/src/soc/ti/am335x/soc.c @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +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 0000000000..90095d47d9 --- /dev/null +++ b/src/soc/ti/am335x/uart.c @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include +#include +#include + +#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 0000000000..664d57d42b --- /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 + +#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 */ -- cgit v1.2.3