diff options
Diffstat (limited to 'arch/arm/imx-common')
-rw-r--r-- | arch/arm/imx-common/Kconfig | 14 | ||||
-rw-r--r-- | arch/arm/imx-common/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/imx-common/imx_bootaux.c | 72 | ||||
-rw-r--r-- | arch/arm/imx-common/rdc-sema.c | 183 |
4 files changed, 271 insertions, 0 deletions
diff --git a/arch/arm/imx-common/Kconfig b/arch/arm/imx-common/Kconfig index 229623922..1b7da5a 100644 --- a/arch/arm/imx-common/Kconfig +++ b/arch/arm/imx-common/Kconfig @@ -3,3 +3,17 @@ config IMX_CONFIG config ROM_UNIFIED_SECTIONS bool + +config IMX_RDC + bool "i.MX Resource domain controller driver" + depends on ARCH_MX6 || ARCH_MX7 + help + i.MX Resource domain controller is used to assign masters + and peripherals to differet domains. This can be used to + isolate resources. + +config IMX_BOOTAUX + bool "Support boot auxiliary core" + depends on ARCH_MX7 || ARCH_MX6 + help + bootaux [addr] to boot auxiliary core. diff --git a/arch/arm/imx-common/Makefile b/arch/arm/imx-common/Makefile index e7190c3..30e66ba 100644 --- a/arch/arm/imx-common/Makefile +++ b/arch/arm/imx-common/Makefile @@ -27,6 +27,8 @@ ifeq ($(SOC),$(filter $(SOC),mx6 mx7)) obj-y += cache.o init.o obj-$(CONFIG_CMD_SATA) += sata.o obj-$(CONFIG_IMX_VIDEO_SKIP) += video.o +obj-$(CONFIG_IMX_RDC) += rdc-sema.o +obj-$(CONFIG_IMX_BOOTAUX) += imx_bootaux.o obj-$(CONFIG_SECURE_BOOT) += hab.o endif ifeq ($(SOC),$(filter $(SOC),vf610)) diff --git a/arch/arm/imx-common/imx_bootaux.c b/arch/arm/imx-common/imx_bootaux.c new file mode 100644 index 0000000..69026df --- /dev/null +++ b/arch/arm/imx-common/imx_bootaux.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <command.h> + +/* Allow for arch specific config before we boot */ +static int __arch_auxiliary_core_up(u32 core_id, u32 boot_private_data) +{ + /* please define platform specific arch_auxiliary_core_up() */ + return CMD_RET_FAILURE; +} + +int arch_auxiliary_core_up(u32 core_id, u32 boot_private_data) + __attribute__((weak, alias("__arch_auxiliary_core_up"))); + +/* Allow for arch specific config before we boot */ +static int __arch_auxiliary_core_check_up(u32 core_id) +{ + /* please define platform specific arch_auxiliary_core_check_up() */ + return 0; +} + +int arch_auxiliary_core_check_up(u32 core_id) + __attribute__((weak, alias("__arch_auxiliary_core_check_up"))); + +/* + * To i.MX6SX and i.MX7D, the image supported by bootaux needs + * the reset vector at the head for the image, with SP and PC + * as the first two words. + * + * Per the cortex-M reference manual, the reset vector of M4 needs + * to exist at 0x0 (TCMUL). The PC and SP are the first two addresses + * of that vector. So to boot M4, the A core must build the M4's reset + * vector with getting the PC and SP from image and filling them to + * TCMUL. When M4 is kicked, it will load the PC and SP by itself. + * The TCMUL is mapped to (M4_BOOTROM_BASE_ADDR) at A core side for + * accessing the M4 TCMUL. + */ +int do_bootaux(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + ulong addr; + int ret, up; + + if (argc < 2) + return CMD_RET_USAGE; + + up = arch_auxiliary_core_check_up(0); + if (up) { + printf("## Auxiliary core is already up\n"); + return CMD_RET_SUCCESS; + } + + addr = simple_strtoul(argv[1], NULL, 16); + + printf("## Starting auxiliary core at 0x%08lX ...\n", addr); + + ret = arch_auxiliary_core_up(0, addr); + if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + bootaux, CONFIG_SYS_MAXARGS, 1, do_bootaux, + "Start auxiliary core", + "" +); diff --git a/arch/arm/imx-common/rdc-sema.c b/arch/arm/imx-common/rdc-sema.c new file mode 100644 index 0000000..dcb5c41 --- /dev/null +++ b/arch/arm/imx-common/rdc-sema.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/imx-common/rdc-sema.h> +#include <asm/arch/imx-rdc.h> +#include <asm-generic/errno.h> + +/* + * Check if the RDC Semaphore is required for this peripheral. + */ +static inline int imx_rdc_check_sema_required(int per_id) +{ + struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR; + u32 reg; + + reg = readl(&imx_rdc->pdap[per_id]); + /* + * No semaphore: + * Intial value or this peripheral is assigned to only one domain + */ + if (!(reg & RDC_PDAP_SREQ_MASK)) + return -ENOENT; + + return 0; +} + +/* + * Check the peripheral read / write access permission on Domain [dom_id]. + */ +int imx_rdc_check_permission(int per_id, int dom_id) +{ + struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR; + u32 reg; + + reg = readl(&imx_rdc->pdap[per_id]); + if (!(reg & RDC_PDAP_DRW_MASK(dom_id))) + return -EACCES; /*No access*/ + + return 0; +} + +/* + * Lock up the RDC semaphore for this peripheral if semaphore is required. + */ +int imx_rdc_sema_lock(int per_id) +{ + struct rdc_sema_regs *imx_rdc_sema; + int ret; + u8 reg; + + ret = imx_rdc_check_sema_required(per_id); + if (ret) + return ret; + + if (per_id < SEMA_GATES_NUM) + imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE1_BASE_ADDR; + else + imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE2_BASE_ADDR; + + do { + writeb(RDC_SEMA_PROC_ID, + &imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]); + reg = readb(&imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]); + if ((reg & RDC_SEMA_GATE_GTFSM_MASK) == RDC_SEMA_PROC_ID) + break; /* Get the Semaphore*/ + } while (1); + + return 0; +} + +/* + * Unlock the RDC semaphore for this peripheral if main CPU is the + * semaphore owner. + */ +int imx_rdc_sema_unlock(int per_id) +{ + struct rdc_sema_regs *imx_rdc_sema; + int ret; + u8 reg; + + ret = imx_rdc_check_sema_required(per_id); + if (ret) + return ret; + + if (per_id < SEMA_GATES_NUM) + imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE1_BASE_ADDR; + else + imx_rdc_sema = (struct rdc_sema_regs *)SEMAPHORE2_BASE_ADDR; + + reg = readb(&imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]); + if ((reg & RDC_SEMA_GATE_GTFSM_MASK) != RDC_SEMA_PROC_ID) + return 1; /*Not the semaphore owner */ + + writeb(0x0, &imx_rdc_sema->gate[per_id % SEMA_GATES_NUM]); + + return 0; +} + +/* + * Setup RDC setting for one peripheral + */ +int imx_rdc_setup_peri(rdc_peri_cfg_t p) +{ + struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR; + u32 reg = 0; + u32 share_count = 0; + u32 peri_id = p & RDC_PERI_MASK; + u32 domain = (p & RDC_DOMAIN_MASK) >> RDC_DOMAIN_SHIFT_BASE; + + /* No domain assigned */ + if (domain == 0) + return -EINVAL; + + reg |= domain; + + share_count = (domain & 0x3) + + ((domain >> 2) & 0x3) + + ((domain >> 4) & 0x3) + + ((domain >> 6) & 0x3); + + if (share_count > 0x3) + reg |= RDC_PDAP_SREQ_MASK; + + writel(reg, &imx_rdc->pdap[peri_id]); + + return 0; +} + +/* + * Setup RDC settings for multiple peripherals + */ +int imx_rdc_setup_peripherals(rdc_peri_cfg_t const *peripherals_list, + unsigned count) +{ + rdc_peri_cfg_t const *p = peripherals_list; + int i, ret; + + for (i = 0; i < count; i++) { + ret = imx_rdc_setup_peri(*p); + if (ret) + return ret; + p++; + } + + return 0; +} + +/* + * Setup RDC setting for one master + */ +int imx_rdc_setup_ma(rdc_ma_cfg_t p) +{ + struct rdc_regs *imx_rdc = (struct rdc_regs *)RDC_BASE_ADDR; + u32 master_id = (p & RDC_MASTER_MASK) >> RDC_MASTER_SHIFT; + u32 domain = (p & RDC_DOMAIN_MASK) >> RDC_DOMAIN_SHIFT_BASE; + + writel((domain & RDC_MDA_DID_MASK), &imx_rdc->mda[master_id]); + + return 0; +} + +/* + * Setup RDC settings for multiple masters + */ +int imx_rdc_setup_masters(rdc_ma_cfg_t const *masters_list, unsigned count) +{ + rdc_ma_cfg_t const *p = masters_list; + int i, ret; + + for (i = 0; i < count; i++) { + ret = imx_rdc_setup_ma(*p); + if (ret) + return ret; + p++; + } + + return 0; +} |