diff options
Diffstat (limited to 'arch/arm/mach-k3/am64x/am642_init.c')
-rw-r--r-- | arch/arm/mach-k3/am64x/am642_init.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/arch/arm/mach-k3/am64x/am642_init.c b/arch/arm/mach-k3/am64x/am642_init.c new file mode 100644 index 0000000..41812b7 --- /dev/null +++ b/arch/arm/mach-k3/am64x/am642_init.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AM642: SoC specific initialization + * + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/ + * Keerthy <j-keerthy@ti.com> + * Dave Gerlach <d-gerlach@ti.com> + */ + +#include <fdt_support.h> +#include <spl.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <linux/soc/ti/ti_sci_protocol.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/pinctrl.h> +#include <mmc.h> +#include <dm/root.h> +#include <command.h> + +#include "../sysfw-loader.h" +#include "../common.h" + +#define CTRLMMR_MCU_RST_CTRL 0x04518170 + +#define CTRLMMR_MCU_RST_SRC (MCU_CTRL_MMR0_BASE + 0x18178) +#define COLD_BOOT 0 +#define SW_POR_MCU BIT(24) +#define SW_POR_MAIN BIT(25) + +static void ctrl_mmr_unlock(void) +{ + /* Unlock all PADCFG_MMR1 module registers */ + mmr_unlock(PADCFG_MMR1_BASE, 1); + + /* Unlock all MCU_CTRL_MMR0 module registers */ + mmr_unlock(MCU_CTRL_MMR0_BASE, 0); + mmr_unlock(MCU_CTRL_MMR0_BASE, 1); + mmr_unlock(MCU_CTRL_MMR0_BASE, 2); + mmr_unlock(MCU_CTRL_MMR0_BASE, 3); + mmr_unlock(MCU_CTRL_MMR0_BASE, 4); + mmr_unlock(MCU_CTRL_MMR0_BASE, 6); + + /* Unlock all CTRL_MMR0 module registers */ + mmr_unlock(CTRL_MMR0_BASE, 0); + mmr_unlock(CTRL_MMR0_BASE, 1); + mmr_unlock(CTRL_MMR0_BASE, 2); + mmr_unlock(CTRL_MMR0_BASE, 3); + mmr_unlock(CTRL_MMR0_BASE, 5); + mmr_unlock(CTRL_MMR0_BASE, 6); + + /* Unlock all MCU_PADCFG_MMR1 module registers */ + mmr_unlock(MCU_PADCFG_MMR1_BASE, 1); +} + +/* + * This uninitialized global variable would normal end up in the .bss section, + * but the .bss is cleared between writing and reading this variable, so move + * it to the .data section. + */ +u32 bootindex __section(".data"); +static struct rom_extended_boot_data bootdata __section(".data"); + +static void store_boot_info_from_rom(void) +{ + bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX); + memcpy(&bootdata, (uintptr_t *)ROM_EXTENDED_BOOT_DATA_INFO, + sizeof(struct rom_extended_boot_data)); +} + +#if defined(CONFIG_K3_LOAD_SYSFW) && CONFIG_IS_ENABLED(DM_MMC) +void k3_mmc_stop_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc->saved_clock = mmc->clock; + mmc_set_clock(mmc, 0, true); + } +} + +void k3_mmc_restart_clock(void) +{ + if (spl_boot_device() == BOOT_DEVICE_MMC1) { + struct mmc *mmc = find_mmc_device(0); + + if (!mmc) + return; + + mmc_set_clock(mmc, mmc->saved_clock, false); + } +} +#else +void k3_mmc_stop_clock(void) {} +void k3_mmc_restart_clock(void) {} +#endif + +#ifdef CONFIG_SPL_OF_LIST +void do_dt_magic(void) +{ + int ret, rescan; + + /* Perform board detection */ + do_board_detect(); + + /* + * Board detection has been done. + * Let us see if another dtb wouldn't be a better match + * for our board + */ + if (IS_ENABLED(CONFIG_CPU_V7R)) { + ret = fdtdec_resetup(&rescan); + if (!ret && rescan) { + dm_uninit(); + dm_init_and_scan(true); + } + } +} +#endif + +#if CONFIG_IS_ENABLED(USB_STORAGE) +static int fixup_usb_boot(const void *fdt_blob) +{ + int ret = 0; + + switch (spl_boot_device()) { + case BOOT_DEVICE_USB: + /* + * If the boot mode is host, fixup the dr_mode to host + * before cdns3 bind takes place + */ + ret = fdt_find_and_setprop((void *)fdt_blob, + "/bus@f4000/cdns-usb@f900000/usb@f400000", + "dr_mode", "host", 5, 0); + if (ret) + printf("%s: fdt_find_and_setprop() failed:%d\n", + __func__, ret); + fallthrough; + default: + break; + } + + return ret; +} + +int fdtdec_board_setup(const void *fdt_blob) +{ + /* Can use the pointer from the function parameters */ + return fixup_usb_boot(fdt_blob); +} +#endif + +#if defined(CONFIG_ESM_K3) +static void enable_mcu_esm_reset(void) +{ + /* Set CTRLMMR_MCU_RST_CTRL:MCU_ESM_ERROR_RST_EN_Z to '0' (low active) */ + u32 stat = readl(CTRLMMR_MCU_RST_CTRL); + + stat &= 0xFFFDFFFF; + writel(stat, CTRLMMR_MCU_RST_CTRL); +} +#endif + +void board_init_f(ulong dummy) +{ +#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM64_DDRSS) || defined(CONFIG_ESM_K3) + struct udevice *dev; + int ret; + int rst_src; +#endif + +#if defined(CONFIG_CPU_V7R) + setup_k3_mpu_regions(); +#endif + + /* + * Cannot delay this further as there is a chance that + * K3_BOOT_PARAM_TABLE_INDEX can be over written by SPL MALLOC section. + */ + store_boot_info_from_rom(); + + ctrl_mmr_unlock(); + + /* Init DM early */ + spl_early_init(); + + preloader_console_init(); + +#if defined(CONFIG_K3_LOAD_SYSFW) + /* + * Process pinctrl for serial3 a.k.a. MAIN UART1 module and continue + * regardless of the result of pinctrl. Do this without probing the + * device, but instead by searching the device that would request the + * given sequence number if probed. The UART will be used by the system + * firmware (SYSFW) image for various purposes and SYSFW depends on us + * to initialize its pin settings. + */ + ret = uclass_find_device_by_seq(UCLASS_SERIAL, 3, &dev); + if (!ret) + pinctrl_select_state(dev, "default"); + + /* + * Load, start up, and configure system controller firmware. + * This will determine whether or not ROM has already loaded + * system firmware and if so, will only perform needed config + * and not attempt to load firmware again. + */ + k3_sysfw_loader(is_rom_loaded_sysfw(&bootdata), k3_mmc_stop_clock, + k3_mmc_restart_clock); +#endif + +#if defined(CONFIG_CPU_V7R) + /* + * Errata ID i2331 CPSW: A device lockup can occur during the second + * read of any CPSW subsystem register after any MAIN domain power on + * reset (POR). A MAIN domain POR occurs using the hardware MCU_PORz + * signal, or via software using CTRLMMR_RST_CTRL.SW_MAIN_POR or + * CTRLMMR_MCU_RST_CTRL.SW_MAIN_POR. After these resets, the processor + * and internal bus structures may get into a state which is only + * recoverable with full device reset using MCU_PORz. + * Workaround(s): To avoid the lockup, a warm reset should be issued + * after a MAIN domain POR and before any access to the CPSW registers. + * The warm reset realigns internal clocks and prevents the lockup from + * happening. + */ + ret = uclass_get_device_by_driver(UCLASS_FIRMWARE, DM_DRIVER_GET(ti_sci), &dev); + if (ret) + printf("\n%s:uclass device error [%d]\n",__func__,ret); + + rst_src = readl(CTRLMMR_MCU_RST_SRC); + if (rst_src == COLD_BOOT || rst_src & (SW_POR_MCU | SW_POR_MAIN)) { + printf("Resetting on cold boot to workaround ErrataID:i2331\n"); + printf("Please resend tiboot3.bin in case of UART/DFU boot\n"); + do_reset(NULL, 0, 0, NULL); + } +#endif + + /* Output System Firmware version info */ + k3_sysfw_print_ver(); + + do_dt_magic(); + +#if defined(CONFIG_ESM_K3) + /* Probe/configure ESM0 */ + ret = uclass_get_device_by_name(UCLASS_MISC, "esm@420000", &dev); + if (ret) + printf("esm main init failed: %d\n", ret); + + /* Probe/configure MCUESM */ + ret = uclass_get_device_by_name(UCLASS_MISC, "esm@4100000", &dev); + if (ret) + printf("esm mcu init failed: %d\n", ret); + + enable_mcu_esm_reset(); +#endif + +#if defined(CONFIG_K3_AM64_DDRSS) + ret = uclass_get_device(UCLASS_RAM, 0, &dev); + if (ret) + panic("DRAM init failed: %d\n", ret); +#endif + if (IS_ENABLED(CONFIG_SPL_ETH) && IS_ENABLED(CONFIG_TI_AM65_CPSW_NUSS) && + spl_boot_device() == BOOT_DEVICE_ETHERNET) { + struct udevice *cpswdev; + + if (uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(am65_cpsw_nuss), &cpswdev)) + printf("Failed to probe am65_cpsw_nuss driver\n"); + } +} + +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + switch (boot_device) { + case BOOT_DEVICE_MMC1: + return MMCSD_MODE_EMMCBOOT; + + case BOOT_DEVICE_MMC2: + return MMCSD_MODE_FS; + + default: + return MMCSD_MODE_RAW; + } +} + +u32 spl_boot_device(void) +{ + return get_boot_device(); +} |