mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-24 19:08:50 +09:00
![Lokesh Vutla](/assets/img/avatar_default.png)
The J721E SoC belongs to the K3 Multicore SoC architecture platform, providing advanced system integration to enable lower system costs of automotive applications such as infotainment, cluster, premium Audio, Gateway, industrial and a range of broad market applications. This SoC is designed around reducing the system cost by eliminating the need of an external system MCU and is targeted towards ASIL-B/C certification/requirements in addition to allowing complex software and system use-cases. Some highlights of this SoC are: * Dual Cortex-A72s in a single cluster, three clusters of lockstep capable dual Cortex-R5F MCUs, Deep-learning Matrix Multiply Accelerator(MMA), C7x floating point Vector DSP, Two C66x floating point DSPs. * 3D GPU PowerVR Rogue 8XE GE8430 * Vision Processing Accelerator (VPAC) with image signal processor and Depth and Motion Processing Accelerator (DMPAC) * Two Gigabit Industrial Communication Subsystems (ICSSG), each with dual PRUs and dual RTUs * Two CSI2.0 4L RX plus one CSI2.0 4L TX, one eDP/DP, One DSI Tx, and up to two DPI interfaces. * Integrated Ethernet switch supporting up to a total of 8 external ports in addition to legacy Ethernet switch of up to 2 ports. * System MMU (SMMU) Version 3.0 and advanced virtualisation capabilities. * Upto 4 PCIe-GEN3 controllers, 2 USB3.0 Dual-role device subsystems, 16 MCANs, 12 McASP, eMMC and SD, UFS, OSPI/HyperBus memory controller, QSPI, I3C and I2C, eCAP/eQEP, eHRPWM, MLB among other peripherals. * Two hardware accelerator block containing AES/DES/SHA/MD5 called SA2UL management. * Configurable L3 Cache and IO-coherent architecture with high data throughput capable distributed DMA architecture under NAVSS * Centralized System Controller for Security, Power, and Resource Management (DMSC) See J721E Technical Reference Manual (SPRUIL1, May 2019) for further details: http://www.ti.com/lit/pdf/spruil1 Add base support for J721E SoC Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com> Signed-off-by: Andreas Dannenberg <dannenberg@ti.com> Signed-off-by: Nishanth Menon <nm@ti.com>
273 lines
7.3 KiB
C
273 lines
7.3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* K3: Architecture initialization
|
|
*
|
|
* Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
|
|
* Lokesh Vutla <lokeshvutla@ti.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <spl.h>
|
|
#include <asm/arch/hardware.h>
|
|
#include <asm/arch/sysfw-loader.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
#include "common.h"
|
|
#include <dm.h>
|
|
#include <dm/uclass-internal.h>
|
|
#include <dm/pinctrl.h>
|
|
#include <linux/soc/ti/ti_sci_protocol.h>
|
|
|
|
#ifdef CONFIG_SPL_BUILD
|
|
static void mmr_unlock(u32 base, u32 partition)
|
|
{
|
|
/* Translate the base address */
|
|
phys_addr_t part_base = base + partition * CTRL_MMR0_PARTITION_SIZE;
|
|
|
|
/* Unlock the requested partition if locked using two-step sequence */
|
|
writel(CTRLMMR_LOCK_KICK0_UNLOCK_VAL, part_base + CTRLMMR_LOCK_KICK0);
|
|
writel(CTRLMMR_LOCK_KICK1_UNLOCK_VAL, part_base + CTRLMMR_LOCK_KICK1);
|
|
}
|
|
|
|
static void ctrl_mmr_unlock(void)
|
|
{
|
|
/* Unlock all WKUP_CTRL_MMR0 module registers */
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 0);
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 1);
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 2);
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 3);
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 6);
|
|
mmr_unlock(WKUP_CTRL_MMR0_BASE, 7);
|
|
|
|
/* 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, 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, 6);
|
|
mmr_unlock(CTRL_MMR0_BASE, 7);
|
|
}
|
|
|
|
/*
|
|
* 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 __attribute__((section(".data")));
|
|
|
|
static void store_boot_index_from_rom(void)
|
|
{
|
|
bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX);
|
|
}
|
|
|
|
void board_init_f(ulong dummy)
|
|
{
|
|
#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS)
|
|
struct udevice *dev;
|
|
int ret;
|
|
#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_index_from_rom();
|
|
|
|
/* Make all control module registers accessible */
|
|
ctrl_mmr_unlock();
|
|
|
|
#ifdef CONFIG_CPU_V7R
|
|
setup_k3_mpu_regions();
|
|
#endif
|
|
|
|
/* Init DM early in-order to invoke system controller */
|
|
spl_early_init();
|
|
|
|
#ifdef CONFIG_K3_LOAD_SYSFW
|
|
/*
|
|
* Process pinctrl for the serial0 a.k.a. WKUP_UART0 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, 0, true, &dev);
|
|
if (!ret)
|
|
pinctrl_select_state(dev, "default");
|
|
|
|
/*
|
|
* Load, start up, and configure system controller firmware. Provide
|
|
* the U-Boot console init function to the SYSFW post-PM configuration
|
|
* callback hook, effectively switching on (or over) the console
|
|
* output.
|
|
*/
|
|
k3_sysfw_loader(preloader_console_init);
|
|
#else
|
|
/* Prepare console output */
|
|
preloader_console_init();
|
|
#endif
|
|
|
|
/* Perform EEPROM-based board detection */
|
|
do_board_detect();
|
|
|
|
#ifdef CONFIG_K3_AM654_DDRSS
|
|
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
|
|
if (ret)
|
|
panic("DRAM init failed: %d\n", ret);
|
|
#endif
|
|
}
|
|
|
|
u32 spl_boot_mode(const u32 boot_device)
|
|
{
|
|
#if defined(CONFIG_SUPPORT_EMMC_BOOT)
|
|
u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
|
|
|
|
u32 bootmode = (devstat & CTRLMMR_MAIN_DEVSTAT_BOOTMODE_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_BOOTMODE_SHIFT;
|
|
|
|
/* eMMC boot0 mode is only supported for primary boot */
|
|
if (bootindex == K3_PRIMARY_BOOTMODE &&
|
|
bootmode == BOOT_DEVICE_MMC1)
|
|
return MMCSD_MODE_EMMCBOOT;
|
|
#endif
|
|
|
|
/* Everything else use filesystem if available */
|
|
#if defined(CONFIG_SPL_FS_FAT) || defined(CONFIG_SPL_FS_EXT4)
|
|
return MMCSD_MODE_FS;
|
|
#else
|
|
return MMCSD_MODE_RAW;
|
|
#endif
|
|
}
|
|
|
|
static u32 __get_backup_bootmedia(u32 devstat)
|
|
{
|
|
u32 bkup_boot = (devstat & CTRLMMR_MAIN_DEVSTAT_BKUP_BOOTMODE_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_BKUP_BOOTMODE_SHIFT;
|
|
|
|
switch (bkup_boot) {
|
|
case BACKUP_BOOT_DEVICE_USB:
|
|
return BOOT_DEVICE_USB;
|
|
case BACKUP_BOOT_DEVICE_UART:
|
|
return BOOT_DEVICE_UART;
|
|
case BACKUP_BOOT_DEVICE_ETHERNET:
|
|
return BOOT_DEVICE_ETHERNET;
|
|
case BACKUP_BOOT_DEVICE_MMC2:
|
|
{
|
|
u32 port = (devstat & CTRLMMR_MAIN_DEVSTAT_BKUP_MMC_PORT_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_BKUP_MMC_PORT_SHIFT;
|
|
if (port == 0x0)
|
|
return BOOT_DEVICE_MMC1;
|
|
return BOOT_DEVICE_MMC2;
|
|
}
|
|
case BACKUP_BOOT_DEVICE_SPI:
|
|
return BOOT_DEVICE_SPI;
|
|
case BACKUP_BOOT_DEVICE_HYPERFLASH:
|
|
return BOOT_DEVICE_HYPERFLASH;
|
|
case BACKUP_BOOT_DEVICE_I2C:
|
|
return BOOT_DEVICE_I2C;
|
|
};
|
|
|
|
return BOOT_DEVICE_RAM;
|
|
}
|
|
|
|
static u32 __get_primary_bootmedia(u32 devstat)
|
|
{
|
|
u32 bootmode = (devstat & CTRLMMR_MAIN_DEVSTAT_BOOTMODE_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_BOOTMODE_SHIFT;
|
|
|
|
if (bootmode == BOOT_DEVICE_OSPI || bootmode == BOOT_DEVICE_QSPI)
|
|
bootmode = BOOT_DEVICE_SPI;
|
|
|
|
if (bootmode == BOOT_DEVICE_MMC2) {
|
|
u32 port = (devstat & CTRLMMR_MAIN_DEVSTAT_MMC_PORT_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_MMC_PORT_SHIFT;
|
|
if (port == 0x0)
|
|
bootmode = BOOT_DEVICE_MMC1;
|
|
} else if (bootmode == BOOT_DEVICE_MMC1) {
|
|
u32 port = (devstat & CTRLMMR_MAIN_DEVSTAT_EMMC_PORT_MASK) >>
|
|
CTRLMMR_MAIN_DEVSTAT_EMMC_PORT_SHIFT;
|
|
if (port == 0x1)
|
|
bootmode = BOOT_DEVICE_MMC2;
|
|
}
|
|
|
|
return bootmode;
|
|
}
|
|
|
|
u32 spl_boot_device(void)
|
|
{
|
|
u32 devstat = readl(CTRLMMR_MAIN_DEVSTAT);
|
|
|
|
if (bootindex == K3_PRIMARY_BOOTMODE)
|
|
return __get_primary_bootmedia(devstat);
|
|
else
|
|
return __get_backup_bootmedia(devstat);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SYS_K3_SPL_ATF
|
|
|
|
#define AM6_DEV_MCU_RTI0 134
|
|
#define AM6_DEV_MCU_RTI1 135
|
|
#define AM6_DEV_MCU_ARMSS0_CPU0 159
|
|
#define AM6_DEV_MCU_ARMSS0_CPU1 245
|
|
|
|
void release_resources_for_core_shutdown(void)
|
|
{
|
|
struct udevice *dev;
|
|
struct ti_sci_handle *ti_sci;
|
|
struct ti_sci_dev_ops *dev_ops;
|
|
struct ti_sci_proc_ops *proc_ops;
|
|
int ret;
|
|
u32 i;
|
|
|
|
const u32 put_device_ids[] = {
|
|
AM6_DEV_MCU_RTI0,
|
|
AM6_DEV_MCU_RTI1,
|
|
};
|
|
|
|
/* Get handle to Device Management and Security Controller (SYSFW) */
|
|
ret = uclass_get_device_by_name(UCLASS_FIRMWARE, "dmsc", &dev);
|
|
if (ret)
|
|
panic("Failed to get handle to SYSFW (%d)\n", ret);
|
|
|
|
ti_sci = (struct ti_sci_handle *)(ti_sci_get_handle_from_sysfw(dev));
|
|
dev_ops = &ti_sci->ops.dev_ops;
|
|
proc_ops = &ti_sci->ops.proc_ops;
|
|
|
|
/* Iterate through list of devices to put (shutdown) */
|
|
for (i = 0; i < ARRAY_SIZE(put_device_ids); i++) {
|
|
u32 id = put_device_ids[i];
|
|
|
|
ret = dev_ops->put_device(ti_sci, id);
|
|
if (ret)
|
|
panic("Failed to put device %u (%d)\n", id, ret);
|
|
}
|
|
|
|
const u32 put_core_ids[] = {
|
|
AM6_DEV_MCU_ARMSS0_CPU1,
|
|
AM6_DEV_MCU_ARMSS0_CPU0, /* Handle CPU0 after CPU1 */
|
|
};
|
|
|
|
/* Iterate through list of cores to put (shutdown) */
|
|
for (i = 0; i < ARRAY_SIZE(put_core_ids); i++) {
|
|
u32 id = put_core_ids[i];
|
|
|
|
/*
|
|
* Queue up the core shutdown request. Note that this call
|
|
* needs to be followed up by an actual invocation of an WFE
|
|
* or WFI CPU instruction.
|
|
*/
|
|
ret = proc_ops->proc_shutdown_no_wait(ti_sci, id);
|
|
if (ret)
|
|
panic("Failed sending core %u shutdown message (%d)\n",
|
|
id, ret);
|
|
}
|
|
}
|
|
#endif
|