diff options
Diffstat (limited to 'plat/nvidia/tegra/common')
26 files changed, 457 insertions, 3653 deletions
diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index 13ca6aaa2..6c8c4f018 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -1,14 +1,16 @@ /* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ + #include <arch.h> #include <asm_macros.S> #include <assert_macros.S> -#include <cpu_macros.S> -#include <cortex_a53.h> #include <cortex_a57.h> +#include <cpu_macros.S> + #include <platform_def.h> #include <tegra_def.h> #include <tegra_platform.h> @@ -18,21 +20,16 @@ /******************************************************************************* * Implementation defined ACTLR_EL3 bit definitions ******************************************************************************/ -#define ACTLR_EL3_L2ACTLR_BIT (U(1) << 6) -#define ACTLR_EL3_L2ECTLR_BIT (U(1) << 5) -#define ACTLR_EL3_L2CTLR_BIT (U(1) << 4) -#define ACTLR_EL3_CPUECTLR_BIT (U(1) << 1) -#define ACTLR_EL3_CPUACTLR_BIT (U(1) << 0) -#define ACTLR_EL3_ENABLE_ALL_MASK (ACTLR_EL3_L2ACTLR_BIT | \ - ACTLR_EL3_L2ECTLR_BIT | \ - ACTLR_EL3_L2CTLR_BIT | \ - ACTLR_EL3_CPUECTLR_BIT | \ - ACTLR_EL3_CPUACTLR_BIT) -#define ACTLR_EL3_ENABLE_ALL_ACCESS (ACTLR_EL3_L2ACTLR_BIT | \ - ACTLR_EL3_L2ECTLR_BIT | \ - ACTLR_EL3_L2CTLR_BIT | \ - ACTLR_EL3_CPUECTLR_BIT | \ - ACTLR_EL3_CPUACTLR_BIT) +#define ACTLR_ELx_L2ACTLR_BIT (U(1) << 6) +#define ACTLR_ELx_L2ECTLR_BIT (U(1) << 5) +#define ACTLR_ELx_L2CTLR_BIT (U(1) << 4) +#define ACTLR_ELx_CPUECTLR_BIT (U(1) << 1) +#define ACTLR_ELx_CPUACTLR_BIT (U(1) << 0) +#define ACTLR_ELx_ENABLE_ALL_ACCESS (ACTLR_ELx_L2ACTLR_BIT | \ + ACTLR_ELx_L2ECTLR_BIT | \ + ACTLR_ELx_L2CTLR_BIT | \ + ACTLR_ELx_CPUECTLR_BIT | \ + ACTLR_ELx_CPUACTLR_BIT) /* Global functions */ .globl plat_is_my_cpu_primary @@ -43,6 +40,7 @@ .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush + .weak plat_core_pos_by_mpidr .globl tegra_secure_entrypoint .globl plat_reset_handler @@ -93,15 +91,11 @@ * ------------------------------------------------------- */ mrs x0, actlr_el3 - mov x1, #ACTLR_EL3_ENABLE_ALL_MASK - bic x0, x0, x1 - mov x1, #ACTLR_EL3_ENABLE_ALL_ACCESS + mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS orr x0, x0, x1 msr actlr_el3, x0 mrs x0, actlr_el2 - mov x1, #ACTLR_EL3_ENABLE_ALL_MASK - bic x0, x0, x1 - mov x1, #ACTLR_EL3_ENABLE_ALL_ACCESS + mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS orr x0, x0, x1 msr actlr_el2, x0 isb @@ -148,17 +142,14 @@ endfunc plat_is_my_cpu_primary * unsigned int plat_my_core_pos(void); * * result: CorePos = CoreId + (ClusterId * cpus per cluster) + * Registers clobbered: x0, x8 * ---------------------------------------------------------- */ func plat_my_core_pos + mov x8, x30 mrs x0, mpidr_el1 - and x1, x0, #MPIDR_CPU_MASK - and x0, x0, #MPIDR_CLUSTER_MASK - lsr x0, x0, #MPIDR_AFFINITY_BITS - mov x2, #PLATFORM_MAX_CPUS_PER_CLUSTER - mul x0, x0, x2 - add x0, x1, x0 - ret + bl plat_core_pos_by_mpidr + ret x8 endfunc plat_my_core_pos /* ----------------------------------------------------- @@ -177,23 +168,6 @@ func plat_get_my_entrypoint endfunc plat_get_my_entrypoint /* ----------------------------------------------------- - * int platform_get_core_pos(int mpidr); - * - * result: CorePos = (ClusterId * cpus per cluster) + - * CoreId - * ----------------------------------------------------- - */ -func platform_get_core_pos - and x1, x0, #MPIDR_CPU_MASK - and x0, x0, #MPIDR_CLUSTER_MASK - lsr x0, x0, #MPIDR_AFFINITY_BITS - mov x2, #PLATFORM_MAX_CPUS_PER_CLUSTER - mul x0, x0, x2 - add x0, x1, x0 - ret -endfunc platform_get_core_pos - - /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions @@ -241,7 +215,8 @@ func plat_reset_handler */ mov x0, x17 mov x1, x18 - mov x2, #BL31_SIZE + adr x2, __RELA_END__ + sub x2, x2, x18 _loop16: cmp x2, #16 b.lo _loop1 @@ -281,6 +256,42 @@ _end: mov x0, x20 ret endfunc plat_reset_handler + /* ------------------------------------------------------ + * int32_t plat_core_pos_by_mpidr(u_register_t mpidr) + * + * This function implements a part of the critical + * interface between the psci generic layer and the + * platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error + * code (-1) is returned in case the MPIDR is invalid. + * + * Clobbers: x0-x3 + * ------------------------------------------------------ + */ +func plat_core_pos_by_mpidr + lsr x1, x0, #MPIDR_AFF0_SHIFT + and x1, x1, #MPIDR_AFFLVL_MASK /* core id */ + lsr x2, x0, #MPIDR_AFF1_SHIFT + and x2, x2, #MPIDR_AFFLVL_MASK /* cluster id */ + + /* core_id >= PLATFORM_MAX_CPUS_PER_CLUSTER */ + mov x0, #-1 + cmp x1, #(PLATFORM_MAX_CPUS_PER_CLUSTER - 1) + b.gt 1f + + /* cluster_id >= PLATFORM_CLUSTER_COUNT */ + cmp x2, #(PLATFORM_CLUSTER_COUNT - 1) + b.gt 1f + + /* CorePos = CoreId + (ClusterId * cpus per cluster) */ + mov x3, #PLATFORM_MAX_CPUS_PER_CLUSTER + mul x3, x3, x2 + add x0, x1, x3 + +1: + ret +endfunc plat_core_pos_by_mpidr + /* ---------------------------------------- * Secure entrypoint function for CPU boot * ---------------------------------------- diff --git a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c deleted file mode 100644 index d7db604cc..000000000 --- a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <arch_helpers.h> -#include <assert.h> -#include <bpmp.h> -#include <common/debug.h> -#include <drivers/delay_timer.h> -#include <errno.h> -#include <lib/mmio.h> -#include <plat/common/platform.h> -#include <stdbool.h> -#include <string.h> -#include <tegra_def.h> - -#define BPMP_TIMEOUT 500 /* 500ms */ - -static uint32_t channel_base[NR_CHANNELS]; -static uint32_t bpmp_init_state = BPMP_INIT_PENDING; - -static uint32_t channel_field(unsigned int ch) -{ - return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch); -} - -static bool master_free(unsigned int ch) -{ - return channel_field(ch) == MA_FREE(ch); -} - -static bool master_acked(unsigned int ch) -{ - return channel_field(ch) == MA_ACKD(ch); -} - -static void signal_slave(unsigned int ch) -{ - mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch)); -} - -static void free_master(unsigned int ch) -{ - mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, - MA_ACKD(ch) ^ MA_FREE(ch)); -} - -/* should be called with local irqs disabled */ -int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz, - void *ib_data, int ib_sz) -{ - unsigned int ch = (unsigned int)plat_my_core_pos(); - mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch]; - int32_t ret = -ETIMEDOUT, timeout = 0; - - if (bpmp_init_state == BPMP_INIT_COMPLETE) { - - /* loop until BPMP is free */ - for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { - if (master_free(ch) == true) { - break; - } - - mdelay(1); - } - - if (timeout != BPMP_TIMEOUT) { - - /* generate the command struct */ - p->code = mrq; - p->flags = DO_ACK; - (void)memcpy((void *)p->data, ob_data, (size_t)ob_sz); - - /* signal command ready to the BPMP */ - signal_slave(ch); - mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET, - (1U << INT_SHR_SEM_OUTBOX_FULL)); - - /* loop until the command is executed */ - for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { - if (master_acked(ch) == true) { - break; - } - - mdelay(1); - } - - if (timeout != BPMP_TIMEOUT) { - - /* get the command response */ - (void)memcpy(ib_data, (const void *)p->data, - (size_t)ib_sz); - - /* return error code */ - ret = p->code; - - /* free this channel */ - free_master(ch); - } - } - - } else { - /* return error code */ - ret = -EINVAL; - } - - if (timeout == BPMP_TIMEOUT) { - ERROR("Timed out waiting for bpmp's response\n"); - } - - return ret; -} - -int tegra_bpmp_init(void) -{ - uint32_t val, base, timeout = BPMP_TIMEOUT; - unsigned int ch; - int ret = 0; - - if (bpmp_init_state == BPMP_INIT_PENDING) { - - /* check if the bpmp processor is alive. */ - do { - val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); - if (val != SIGN_OF_LIFE) { - mdelay(1); - timeout--; - } - - } while ((val != SIGN_OF_LIFE) && (timeout > 0U)); - - if (val == SIGN_OF_LIFE) { - - /* check if clock for the atomics block is enabled */ - val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V); - if ((val & CAR_ENABLE_ATOMICS) == 0) { - ERROR("Clock to the atomics block is disabled\n"); - } - - /* check if the atomics block is out of reset */ - val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V); - if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) { - ERROR("Reset to the atomics block is asserted\n"); - } - - /* base address to get the result from Atomics */ - base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; - - /* channel area is setup by BPMP before signaling handshake */ - for (ch = 0; ch < NR_CHANNELS; ch++) { - - /* issue command to get the channel base address */ - mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | - ATOMIC_CMD_GET); - - /* get the base address for the channel */ - channel_base[ch] = mmio_read_32(base); - - /* increment result register offset */ - base += 4U; - } - - /* mark state as "initialized" */ - bpmp_init_state = BPMP_INIT_COMPLETE; - - /* the channel values have to be visible across all cpus */ - flush_dcache_range((uint64_t)channel_base, - sizeof(channel_base)); - flush_dcache_range((uint64_t)&bpmp_init_state, - sizeof(bpmp_init_state)); - - INFO("%s: done\n", __func__); - - } else { - ERROR("BPMP not powered on\n"); - - /* bpmp is not present in the system */ - bpmp_init_state = BPMP_NOT_PRESENT; - - /* communication timed out */ - ret = -ETIMEDOUT; - } - } - - return ret; -} - -void tegra_bpmp_suspend(void) -{ - /* freeze the interface */ - if (bpmp_init_state == BPMP_INIT_COMPLETE) { - bpmp_init_state = BPMP_SUSPEND_ENTRY; - flush_dcache_range((uint64_t)&bpmp_init_state, - sizeof(bpmp_init_state)); - } -} - -void tegra_bpmp_resume(void) -{ - uint32_t val, timeout = 0; - - if (bpmp_init_state == BPMP_SUSPEND_ENTRY) { - - /* check if the bpmp processor is alive. */ - do { - - val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); - if (val != SIGN_OF_LIFE) { - mdelay(1); - timeout++; - } - - } while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT)); - - if (val == SIGN_OF_LIFE) { - - INFO("%s: BPMP took %d ms to resume\n", __func__, timeout); - - /* mark state as "initialized" */ - bpmp_init_state = BPMP_INIT_COMPLETE; - - /* state has to be visible across all cpus */ - flush_dcache_range((uint64_t)&bpmp_init_state, - sizeof(bpmp_init_state)); - } else { - ERROR("BPMP not powered on\n"); - } - } -} diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c deleted file mode 100644 index ae899c424..000000000 --- a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> -#include <bpmp_ipc.h> -#include <common/debug.h> -#include <drivers/delay_timer.h> -#include <errno.h> -#include <lib/mmio.h> -#include <lib/utils_def.h> -#include <stdbool.h> -#include <string.h> -#include <tegra_def.h> - -#include "intf.h" -#include "ivc.h" - -/** - * Holds IVC channel data - */ -struct ccplex_bpmp_channel_data { - /* Buffer for incoming data */ - struct frame_data *ib; - - /* Buffer for outgoing data */ - struct frame_data *ob; -}; - -static struct ccplex_bpmp_channel_data s_channel; -static struct ivc ivc_ccplex_bpmp_channel; - -/* - * Helper functions to access the HSP doorbell registers - */ -static inline uint32_t hsp_db_read(uint32_t reg) -{ - return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg)); -} - -static inline void hsp_db_write(uint32_t reg, uint32_t val) -{ - mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val); -} - -/******************************************************************************* - * IVC wrappers for CCPLEX <-> BPMP communication. - ******************************************************************************/ - -static void tegra_bpmp_ring_bpmp_doorbell(void); - -/* - * Get the next frame where data can be written. - */ -static struct frame_data *tegra_bpmp_get_next_out_frame(void) -{ - struct frame_data *frame; - const struct ivc *ch = &ivc_ccplex_bpmp_channel; - - frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch); - if (frame == NULL) { - ERROR("%s: Error in getting next frame, exiting\n", __func__); - } else { - s_channel.ob = frame; - } - - return frame; -} - -static void tegra_bpmp_signal_slave(void) -{ - (void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel); - tegra_bpmp_ring_bpmp_doorbell(); -} - -static int32_t tegra_bpmp_free_master(void) -{ - return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel); -} - -static bool tegra_bpmp_slave_acked(void) -{ - struct frame_data *frame; - bool ret = true; - - frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel); - if (frame == NULL) { - ret = false; - } else { - s_channel.ib = frame; - } - - return ret; -} - -static struct frame_data *tegra_bpmp_get_cur_in_frame(void) -{ - return s_channel.ib; -} - -/* - * Enables BPMP to ring CCPlex doorbell - */ -static void tegra_bpmp_enable_ccplex_doorbell(void) -{ - uint32_t reg; - - reg = hsp_db_read(HSP_DBELL_1_ENABLE); - reg |= HSP_MASTER_BPMP_BIT; - hsp_db_write(HSP_DBELL_1_ENABLE, reg); -} - -/* - * CCPlex rings the BPMP doorbell - */ -static void tegra_bpmp_ring_bpmp_doorbell(void) -{ - /* - * Any writes to this register has the same effect, - * uses master ID of the write transaction and set - * corresponding flag. - */ - hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT); -} - -/* - * Returns true if CCPLex can ring BPMP doorbell, otherwise false. - * This also signals that BPMP is up and ready. - */ -static bool tegra_bpmp_can_ccplex_ring_doorbell(void) -{ - uint32_t reg; - - /* check if ccplex can communicate with bpmp */ - reg = hsp_db_read(HSP_DBELL_3_ENABLE); - - return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U); -} - -static int32_t tegra_bpmp_wait_for_slave_ack(void) -{ - uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; - - while (!tegra_bpmp_slave_acked() && (timeout != 0U)) { - udelay(1); - timeout--; - }; - - return ((timeout == 0U) ? -ETIMEDOUT : 0); -} - -/* - * Notification from the ivc layer - */ -static void tegra_bpmp_ivc_notify(const struct ivc *ivc) -{ - (void)(ivc); - - tegra_bpmp_ring_bpmp_doorbell(); -} - -/* - * Atomic send/receive API, which means it waits until slave acks - */ -static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out, - uint32_t size_out, void *p_in, uint32_t size_in) -{ - struct frame_data *frame = tegra_bpmp_get_next_out_frame(); - const struct frame_data *f_in = NULL; - int32_t ret = 0; - void *p_fdata; - - if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) || - (frame == NULL)) { - ERROR("%s: invalid parameters, exiting\n", __func__); - ret = -EINVAL; - } - - if (ret == 0) { - - /* prepare the command frame */ - frame->mrq = mrq; - frame->flags = FLAG_DO_ACK; - p_fdata = frame->data; - (void)memcpy(p_fdata, p_out, (size_t)size_out); - - /* signal the slave */ - tegra_bpmp_signal_slave(); - - /* wait for slave to ack */ - ret = tegra_bpmp_wait_for_slave_ack(); - if (ret != 0) { - ERROR("failed waiting for the slave to ack\n"); - } - - /* retrieve the response frame */ - if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL) && - (ret == 0)) { - - f_in = tegra_bpmp_get_cur_in_frame(); - if (f_in != NULL) { - ERROR("Failed to get next input frame!\n"); - } else { - (void)memcpy(p_in, p_fdata, (size_t)size_in); - } - } - - if (ret == 0) { - ret = tegra_bpmp_free_master(); - if (ret != 0) { - ERROR("Failed to free master\n"); - } - } - } - - return ret; -} - -/* - * Initializes the BPMP<--->CCPlex communication path. - */ -int32_t tegra_bpmp_ipc_init(void) -{ - size_t msg_size; - uint32_t frame_size, timeout; - int32_t error = 0; - - /* allow bpmp to ring CCPLEX's doorbell */ - tegra_bpmp_enable_ccplex_doorbell(); - - /* wait for BPMP to actually ring the doorbell */ - timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; - while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) { - udelay(1); /* bpmp turn-around time */ - timeout--; - } - - if (timeout == 0U) { - ERROR("%s: BPMP firmware is not ready\n", __func__); - return -ENOTSUP; - } - - INFO("%s: BPMP handshake completed\n", __func__); - - msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES); - frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size); - if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) { - ERROR("%s: carveout size is not sufficient\n", __func__); - return -EINVAL; - } - - error = tegra_ivc_init(&ivc_ccplex_bpmp_channel, - (uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE, - (uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE, - 1U, frame_size, tegra_bpmp_ivc_notify); - if (error != 0) { - - ERROR("%s: IVC init failed (%d)\n", __func__, error); - - } else { - - /* reset channel */ - tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel); - - /* wait for notification from BPMP */ - while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) { - /* - * Interrupt BPMP with doorbell each time after - * tegra_ivc_channel_notified() returns non zero - * value. - */ - tegra_bpmp_ring_bpmp_doorbell(); - } - - INFO("%s: All communication channels initialized\n", __func__); - } - - return error; -} - -/* Handler to reset a hardware module */ -int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id) -{ - int32_t ret; - struct mrq_reset_request req = { - .cmd = (uint32_t)CMD_RESET_MODULE, - .reset_id = rst_id - }; - - /* only GPCDMA/XUSB_PADCTL resets are supported */ - assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) || - (rst_id == TEGRA_RESET_ID_GPCDMA)); - - ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req, - (uint32_t)sizeof(req), NULL, 0); - if (ret != 0) { - ERROR("%s: failed for module %d with error %d\n", __func__, - rst_id, ret); - } - - return ret; -} - -int tegra_bpmp_ipc_enable_clock(uint32_t clk_id) -{ - int ret; - struct mrq_clk_request req; - - /* only SE clocks are supported */ - if (clk_id != TEGRA_CLK_SE) { - return -ENOTSUP; - } - - /* prepare the MRQ_CLK command */ - req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id); - - ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req), - NULL, 0); - if (ret != 0) { - ERROR("%s: failed for module %d with error %d\n", __func__, - clk_id, ret); - } - - return ret; -} - -int tegra_bpmp_ipc_disable_clock(uint32_t clk_id) -{ - int ret; - struct mrq_clk_request req; - - /* only SE clocks are supported */ - if (clk_id != TEGRA_CLK_SE) { - return -ENOTSUP; - } - - /* prepare the MRQ_CLK command */ - req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id); - - ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req), - NULL, 0); - if (ret != 0) { - ERROR("%s: failed for module %d with error %d\n", __func__, - clk_id, ret); - } - - return ret; -} diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h b/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h deleted file mode 100644 index 7059c3701..000000000 --- a/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef INTF_H -#define INTF_H - -/** - * Flags used in IPC req - */ -#define FLAG_DO_ACK (U(1) << 0) -#define FLAG_RING_DOORBELL (U(1) << 1) - -/* Bit 1 is designated for CCPlex in secure world */ -#define HSP_MASTER_CCPLEX_BIT (U(1) << 1) -/* Bit 19 is designated for BPMP in non-secure world */ -#define HSP_MASTER_BPMP_BIT (U(1) << 19) -/* Timeout to receive response from BPMP is 1 sec */ -#define TIMEOUT_RESPONSE_FROM_BPMP_US U(1000000) /* in microseconds */ - -/** - * IVC protocol defines and command/response frame - */ - -/** - * IVC specific defines - */ -#define IVC_CMD_SZ_BYTES U(128) -#define IVC_DATA_SZ_BYTES U(120) - -/** - * Holds frame data for an IPC request - */ -struct frame_data { - /* Identification as to what kind of data is being transmitted */ - uint32_t mrq; - - /* Flags for slave as to how to respond back */ - uint32_t flags; - - /* Actual data being sent */ - uint8_t data[IVC_DATA_SZ_BYTES]; -}; - -/** - * Commands send to the BPMP firmware - */ - -/** - * MRQ command codes - */ -#define MRQ_RESET U(20) -#define MRQ_CLK U(22) - -/** - * Reset sub-commands - */ -#define CMD_RESET_ASSERT U(1) -#define CMD_RESET_DEASSERT U(2) -#define CMD_RESET_MODULE U(3) - -/** - * Used by the sender of an #MRQ_RESET message to request BPMP to - * assert or deassert a given reset line. - */ -struct __attribute__((packed)) mrq_reset_request { - /* reset action to perform (mrq_reset_commands) */ - uint32_t cmd; - /* id of the reset to affected */ - uint32_t reset_id; -}; - -/** - * MRQ_CLK sub-commands - * - */ -enum { - CMD_CLK_GET_RATE = 1, - CMD_CLK_SET_RATE = 2, - CMD_CLK_ROUND_RATE = 3, - CMD_CLK_GET_PARENT = 4, - CMD_CLK_SET_PARENT = 5, - CMD_CLK_IS_ENABLED = 6, - CMD_CLK_ENABLE = 7, - CMD_CLK_DISABLE = 8, - CMD_CLK_GET_ALL_INFO = 14, - CMD_CLK_GET_MAX_CLK_ID = 15, - CMD_CLK_MAX, -}; - -/** - * Used by the sender of an #MRQ_CLK message to control clocks. The - * clk_request is split into several sub-commands. Some sub-commands - * require no additional data. Others have a sub-command specific - * payload - * - * |sub-command |payload | - * |----------------------------|-----------------------| - * |CMD_CLK_GET_RATE |- | - * |CMD_CLK_SET_RATE |clk_set_rate | - * |CMD_CLK_ROUND_RATE |clk_round_rate | - * |CMD_CLK_GET_PARENT |- | - * |CMD_CLK_SET_PARENT |clk_set_parent | - * |CMD_CLK_IS_ENABLED |- | - * |CMD_CLK_ENABLE |- | - * |CMD_CLK_DISABLE |- | - * |CMD_CLK_GET_ALL_INFO |- | - * |CMD_CLK_GET_MAX_CLK_ID |- | - * - */ -struct mrq_clk_request { - /** - * sub-command and clock id concatenated to 32-bit word. - * - bits[31..24] is the sub-cmd. - * - bits[23..0] is the clock id - */ - uint32_t cmd_and_id; -}; - -/** - * Macro to prepare the MRQ_CLK sub-command - */ -#define make_mrq_clk_cmd(cmd, id) (((cmd) << 24) | (id & 0xFFFFFF)) - -#endif /* INTF_H */ diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c deleted file mode 100644 index 57daf6aeb..000000000 --- a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <arch_helpers.h> -#include <assert.h> -#include <common/debug.h> -#include <errno.h> -#include <stddef.h> -#include <string.h> - -#include "ivc.h" - -/* - * IVC channel reset protocol. - * - * Each end uses its tx_channel.state to indicate its synchronization state. - */ -enum { - /* - * This value is zero for backwards compatibility with services that - * assume channels to be initially zeroed. Such channels are in an - * initially valid state, but cannot be asynchronously reset, and must - * maintain a valid state at all times. - * - * The transmitting end can enter the established state from the sync or - * ack state when it observes the receiving endpoint in the ack or - * established state, indicating that has cleared the counters in our - * rx_channel. - */ - ivc_state_established = U(0), - - /* - * If an endpoint is observed in the sync state, the remote endpoint is - * allowed to clear the counters it owns asynchronously with respect to - * the current endpoint. Therefore, the current endpoint is no longer - * allowed to communicate. - */ - ivc_state_sync = U(1), - - /* - * When the transmitting end observes the receiving end in the sync - * state, it can clear the w_count and r_count and transition to the ack - * state. If the remote endpoint observes us in the ack state, it can - * return to the established state once it has cleared its counters. - */ - ivc_state_ack = U(2) -}; - -/* - * This structure is divided into two-cache aligned parts, the first is only - * written through the tx_channel pointer, while the second is only written - * through the rx_channel pointer. This delineates ownership of the cache lines, - * which is critical to performance and necessary in non-cache coherent - * implementations. - */ -struct ivc_channel_header { - struct { - /* fields owned by the transmitting end */ - uint32_t w_count; - uint32_t state; - uint32_t w_rsvd[IVC_CHHDR_TX_FIELDS - 2]; - }; - struct { - /* fields owned by the receiving end */ - uint32_t r_count; - uint32_t r_rsvd[IVC_CHHDR_RX_FIELDS - 1]; - }; -}; - -static inline bool ivc_channel_empty(const struct ivc *ivc, - volatile const struct ivc_channel_header *ch) -{ - /* - * This function performs multiple checks on the same values with - * security implications, so sample the counters' current values in - * shared memory to ensure that these checks use the same values. - */ - uint32_t wr_count = ch->w_count; - uint32_t rd_count = ch->r_count; - bool ret = false; - - (void)ivc; - - /* - * Perform an over-full check to prevent denial of service attacks where - * a server could be easily fooled into believing that there's an - * extremely large number of frames ready, since receivers are not - * expected to check for full or over-full conditions. - * - * Although the channel isn't empty, this is an invalid case caused by - * a potentially malicious peer, so returning empty is safer, because it - * gives the impression that the channel has gone silent. - */ - if (((wr_count - rd_count) > ivc->nframes) || (wr_count == rd_count)) { - ret = true; - } - - return ret; -} - -static inline bool ivc_channel_full(const struct ivc *ivc, - volatile const struct ivc_channel_header *ch) -{ - uint32_t wr_count = ch->w_count; - uint32_t rd_count = ch->r_count; - - (void)ivc; - - /* - * Invalid cases where the counters indicate that the queue is over - * capacity also appear full. - */ - return ((wr_count - rd_count) >= ivc->nframes); -} - -static inline uint32_t ivc_channel_avail_count(const struct ivc *ivc, - volatile const struct ivc_channel_header *ch) -{ - uint32_t wr_count = ch->w_count; - uint32_t rd_count = ch->r_count; - - (void)ivc; - - /* - * This function isn't expected to be used in scenarios where an - * over-full situation can lead to denial of service attacks. See the - * comment in ivc_channel_empty() for an explanation about special - * over-full considerations. - */ - return (wr_count - rd_count); -} - -static inline void ivc_advance_tx(struct ivc *ivc) -{ - ivc->tx_channel->w_count++; - - if (ivc->w_pos == (ivc->nframes - (uint32_t)1U)) { - ivc->w_pos = 0U; - } else { - ivc->w_pos++; - } -} - -static inline void ivc_advance_rx(struct ivc *ivc) -{ - ivc->rx_channel->r_count++; - - if (ivc->r_pos == (ivc->nframes - (uint32_t)1U)) { - ivc->r_pos = 0U; - } else { - ivc->r_pos++; - } -} - -static inline int32_t ivc_check_read(const struct ivc *ivc) -{ - /* - * tx_channel->state is set locally, so it is not synchronized with - * state from the remote peer. The remote peer cannot reset its - * transmit counters until we've acknowledged its synchronization - * request, so no additional synchronization is required because an - * asynchronous transition of rx_channel->state to ivc_state_ack is not - * allowed. - */ - if (ivc->tx_channel->state != ivc_state_established) { - return -ECONNRESET; - } - - /* - * Avoid unnecessary invalidations when performing repeated accesses to - * an IVC channel by checking the old queue pointers first. - * Synchronization is only necessary when these pointers indicate empty - * or full. - */ - if (!ivc_channel_empty(ivc, ivc->rx_channel)) { - return 0; - } - - return ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0; -} - -static inline int32_t ivc_check_write(const struct ivc *ivc) -{ - if (ivc->tx_channel->state != ivc_state_established) { - return -ECONNRESET; - } - - if (!ivc_channel_full(ivc, ivc->tx_channel)) { - return 0; - } - - return ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0; -} - -bool tegra_ivc_can_read(const struct ivc *ivc) -{ - return ivc_check_read(ivc) == 0; -} - -bool tegra_ivc_can_write(const struct ivc *ivc) -{ - return ivc_check_write(ivc) == 0; -} - -bool tegra_ivc_tx_empty(const struct ivc *ivc) -{ - return ivc_channel_empty(ivc, ivc->tx_channel); -} - -static inline uintptr_t calc_frame_offset(uint32_t frame_index, - uint32_t frame_size, uint32_t frame_offset) -{ - return ((uintptr_t)frame_index * (uintptr_t)frame_size) + - (uintptr_t)frame_offset; -} - -static void *ivc_frame_pointer(const struct ivc *ivc, - volatile const struct ivc_channel_header *ch, - uint32_t frame) -{ - assert(frame < ivc->nframes); - return (void *)((uintptr_t)(&ch[1]) + - calc_frame_offset(frame, ivc->frame_size, 0)); -} - -int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read) -{ - const void *src; - int32_t result; - - if (buf == NULL) { - return -EINVAL; - } - - if (max_read > ivc->frame_size) { - return -E2BIG; - } - - result = ivc_check_read(ivc); - if (result != 0) { - return result; - } - - /* - * Order observation of w_pos potentially indicating new data before - * data read. - */ - dmbish(); - - src = ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos); - - (void)memcpy(buf, src, max_read); - - ivc_advance_rx(ivc); - - /* - * Ensure our write to r_pos occurs before our read from w_pos. - */ - dmbish(); - - /* - * Notify only upon transition from full to non-full. - * The available count can only asynchronously increase, so the - * worst possible side-effect will be a spurious notification. - */ - if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) { - ivc->notify(ivc); - } - - return (int32_t)max_read; -} - -/* directly peek at the next frame rx'ed */ -void *tegra_ivc_read_get_next_frame(const struct ivc *ivc) -{ - if (ivc_check_read(ivc) != 0) { - return NULL; - } - - /* - * Order observation of w_pos potentially indicating new data before - * data read. - */ - dmbld(); - - return ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos); -} - -int32_t tegra_ivc_read_advance(struct ivc *ivc) -{ - /* - * No read barriers or synchronization here: the caller is expected to - * have already observed the channel non-empty. This check is just to - * catch programming errors. - */ - int32_t result = ivc_check_read(ivc); - if (result != 0) { - return result; - } - - ivc_advance_rx(ivc); - - /* - * Ensure our write to r_pos occurs before our read from w_pos. - */ - dmbish(); - - /* - * Notify only upon transition from full to non-full. - * The available count can only asynchronously increase, so the - * worst possible side-effect will be a spurious notification. - */ - if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) { - ivc->notify(ivc); - } - - return 0; -} - -int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size) -{ - void *p; - int32_t result; - - if ((buf == NULL) || (ivc == NULL)) { - return -EINVAL; - } - - if (size > ivc->frame_size) { - return -E2BIG; - } - - result = ivc_check_write(ivc); - if (result != 0) { - return result; - } - - p = ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos); - - (void)memset(p, 0, ivc->frame_size); - (void)memcpy(p, buf, size); - - /* - * Ensure that updated data is visible before the w_pos counter - * indicates that it is ready. - */ - dmbst(); - - ivc_advance_tx(ivc); - - /* - * Ensure our write to w_pos occurs before our read from r_pos. - */ - dmbish(); - - /* - * Notify only upon transition from empty to non-empty. - * The available count can only asynchronously decrease, so the - * worst possible side-effect will be a spurious notification. - */ - if (ivc_channel_avail_count(ivc, ivc->tx_channel) == 1U) { - ivc->notify(ivc); - } - - return (int32_t)size; -} - -/* directly poke at the next frame to be tx'ed */ -void *tegra_ivc_write_get_next_frame(const struct ivc *ivc) -{ - if (ivc_check_write(ivc) != 0) { - return NULL; - } - - return ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos); -} - -/* advance the tx buffer */ -int32_t tegra_ivc_write_advance(struct ivc *ivc) -{ - int32_t result = ivc_check_write(ivc); - - if (result != 0) { - return result; - } - - /* - * Order any possible stores to the frame before update of w_pos. - */ - dmbst(); - - ivc_advance_tx(ivc); - - /* - * Ensure our write to w_pos occurs before our read from r_pos. - */ - dmbish(); - - /* - * Notify only upon transition from empty to non-empty. - * The available count can only asynchronously decrease, so the - * worst possible side-effect will be a spurious notification. - */ - if (ivc_channel_avail_count(ivc, ivc->tx_channel) == (uint32_t)1U) { - ivc->notify(ivc); - } - - return 0; -} - -void tegra_ivc_channel_reset(const struct ivc *ivc) -{ - ivc->tx_channel->state = ivc_state_sync; - ivc->notify(ivc); -} - -/* - * =============================================================== - * IVC State Transition Table - see tegra_ivc_channel_notified() - * =============================================================== - * - * local remote action - * ----- ------ ----------------------------------- - * SYNC EST <none> - * SYNC ACK reset counters; move to EST; notify - * SYNC SYNC reset counters; move to ACK; notify - * ACK EST move to EST; notify - * ACK ACK move to EST; notify - * ACK SYNC reset counters; move to ACK; notify - * EST EST <none> - * EST ACK <none> - * EST SYNC reset counters; move to ACK; notify - * - * =============================================================== - */ -int32_t tegra_ivc_channel_notified(struct ivc *ivc) -{ - uint32_t peer_state; - - /* Copy the receiver's state out of shared memory. */ - peer_state = ivc->rx_channel->state; - - if (peer_state == (uint32_t)ivc_state_sync) { - /* - * Order observation of ivc_state_sync before stores clearing - * tx_channel. - */ - dmbld(); - - /* - * Reset tx_channel counters. The remote end is in the SYNC - * state and won't make progress until we change our state, - * so the counters are not in use at this time. - */ - ivc->tx_channel->w_count = 0U; - ivc->rx_channel->r_count = 0U; - - ivc->w_pos = 0U; - ivc->r_pos = 0U; - - /* - * Ensure that counters appear cleared before new state can be - * observed. - */ - dmbst(); - - /* - * Move to ACK state. We have just cleared our counters, so it - * is now safe for the remote end to start using these values. - */ - ivc->tx_channel->state = ivc_state_ack; - - /* - * Notify remote end to observe state transition. - */ - ivc->notify(ivc); - - } else if ((ivc->tx_channel->state == (uint32_t)ivc_state_sync) && - (peer_state == (uint32_t)ivc_state_ack)) { - /* - * Order observation of ivc_state_sync before stores clearing - * tx_channel. - */ - dmbld(); - - /* - * Reset tx_channel counters. The remote end is in the ACK - * state and won't make progress until we change our state, - * so the counters are not in use at this time. - */ - ivc->tx_channel->w_count = 0U; - ivc->rx_channel->r_count = 0U; - - ivc->w_pos = 0U; - ivc->r_pos = 0U; - - /* - * Ensure that counters appear cleared before new state can be - * observed. - */ - dmbst(); - - /* - * Move to ESTABLISHED state. We know that the remote end has - * already cleared its counters, so it is safe to start - * writing/reading on this channel. - */ - ivc->tx_channel->state = ivc_state_established; - - /* - * Notify remote end to observe state transition. - */ - ivc->notify(ivc); - - } else if (ivc->tx_channel->state == (uint32_t)ivc_state_ack) { - /* - * At this point, we have observed the peer to be in either - * the ACK or ESTABLISHED state. Next, order observation of - * peer state before storing to tx_channel. - */ - dmbld(); - - /* - * Move to ESTABLISHED state. We know that we have previously - * cleared our counters, and we know that the remote end has - * cleared its counters, so it is safe to start writing/reading - * on this channel. - */ - ivc->tx_channel->state = ivc_state_established; - - /* - * Notify remote end to observe state transition. - */ - ivc->notify(ivc); - - } else { - /* - * There is no need to handle any further action. Either the - * channel is already fully established, or we are waiting for - * the remote end to catch up with our current state. Refer - * to the diagram in "IVC State Transition Table" above. - */ - } - - return ((ivc->tx_channel->state == (uint32_t)ivc_state_established) ? 0 : -EAGAIN); -} - -size_t tegra_ivc_align(size_t size) -{ - return (size + (IVC_ALIGN - 1U)) & ~(IVC_ALIGN - 1U); -} - -size_t tegra_ivc_total_queue_size(size_t queue_size) -{ - if ((queue_size & (IVC_ALIGN - 1U)) != 0U) { - ERROR("queue_size (%d) must be %d-byte aligned\n", - (int32_t)queue_size, IVC_ALIGN); - return 0; - } - return queue_size + sizeof(struct ivc_channel_header); -} - -static int32_t check_ivc_params(uintptr_t queue_base1, uintptr_t queue_base2, - uint32_t nframes, uint32_t frame_size) -{ - assert((offsetof(struct ivc_channel_header, w_count) - & (IVC_ALIGN - 1U)) == 0U); - assert((offsetof(struct ivc_channel_header, r_count) - & (IVC_ALIGN - 1U)) == 0U); - assert((sizeof(struct ivc_channel_header) & (IVC_ALIGN - 1U)) == 0U); - - if (((uint64_t)nframes * (uint64_t)frame_size) >= 0x100000000ULL) { - ERROR("nframes * frame_size overflows\n"); - return -EINVAL; - } - - /* - * The headers must at least be aligned enough for counters - * to be accessed atomically. - */ - if ((queue_base1 & (IVC_ALIGN - 1U)) != 0U) { - ERROR("ivc channel start not aligned: %lx\n", queue_base1); - return -EINVAL; - } - if ((queue_base2 & (IVC_ALIGN - 1U)) != 0U) { - ERROR("ivc channel start not aligned: %lx\n", queue_base2); - return -EINVAL; - } - - if ((frame_size & (IVC_ALIGN - 1U)) != 0U) { - ERROR("frame size not adequately aligned: %u\n", - frame_size); - return -EINVAL; - } - - if (queue_base1 < queue_base2) { - if ((queue_base1 + ((uint64_t)frame_size * nframes)) > queue_base2) { - ERROR("queue regions overlap: %lx + %x, %x\n", - queue_base1, frame_size, - frame_size * nframes); - return -EINVAL; - } - } else { - if ((queue_base2 + ((uint64_t)frame_size * nframes)) > queue_base1) { - ERROR("queue regions overlap: %lx + %x, %x\n", - queue_base2, frame_size, - frame_size * nframes); - return -EINVAL; - } - } - - return 0; -} - -int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base, - uint32_t nframes, uint32_t frame_size, - ivc_notify_function notify) -{ - int32_t result; - - /* sanity check input params */ - if ((ivc == NULL) || (notify == NULL)) { - return -EINVAL; - } - - result = check_ivc_params(rx_base, tx_base, nframes, frame_size); - if (result != 0) { - return result; - } - - /* - * All sizes that can be returned by communication functions should - * fit in a 32-bit integer. - */ - if (frame_size > (1u << 31)) { - return -E2BIG; - } - - ivc->rx_channel = (struct ivc_channel_header *)rx_base; - ivc->tx_channel = (struct ivc_channel_header *)tx_base; - ivc->notify = notify; - ivc->frame_size = frame_size; - ivc->nframes = nframes; - ivc->w_pos = 0U; - ivc->r_pos = 0U; - - INFO("%s: done\n", __func__); - - return 0; -} diff --git a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h b/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h deleted file mode 100644 index 42e6a1f7c..000000000 --- a/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef IVC_H -#define IVC_H - -#include <lib/utils_def.h> -#include <stdint.h> -#include <stddef.h> - -#define IVC_ALIGN U(64) -#define IVC_CHHDR_TX_FIELDS U(16) -#define IVC_CHHDR_RX_FIELDS U(16) - -struct ivc; -struct ivc_channel_header; - -/* callback handler for notify on receiving a response */ -typedef void (* ivc_notify_function)(const struct ivc *); - -struct ivc { - struct ivc_channel_header *rx_channel; - struct ivc_channel_header *tx_channel; - uint32_t w_pos; - uint32_t r_pos; - ivc_notify_function notify; - uint32_t nframes; - uint32_t frame_size; -}; - -int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base, - uint32_t nframes, uint32_t frame_size, - ivc_notify_function notify); -size_t tegra_ivc_total_queue_size(size_t queue_size); -size_t tegra_ivc_align(size_t size); -int32_t tegra_ivc_channel_notified(struct ivc *ivc); -void tegra_ivc_channel_reset(const struct ivc *ivc); -int32_t tegra_ivc_write_advance(struct ivc *ivc); -void *tegra_ivc_write_get_next_frame(const struct ivc *ivc); -int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size); -int32_t tegra_ivc_read_advance(struct ivc *ivc); -void *tegra_ivc_read_get_next_frame(const struct ivc *ivc); -int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read); -bool tegra_ivc_tx_empty(const struct ivc *ivc); -bool tegra_ivc_can_write(const struct ivc *ivc); -bool tegra_ivc_can_read(const struct ivc *ivc); - -#endif /* IVC_H */ diff --git a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c deleted file mode 100644 index 8f5555459..000000000 --- a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> - -#include <arch_helpers.h> -#include <cortex_a53.h> -#include <common/debug.h> -#include <drivers/delay_timer.h> -#include <lib/mmio.h> - -#include <flowctrl.h> -#include <lib/utils_def.h> -#include <pmc.h> -#include <tegra_def.h> - -#define CLK_RST_DEV_L_SET 0x300 -#define CLK_RST_DEV_L_CLR 0x304 -#define CLK_BPMP_RST (1 << 1) - -#define EVP_BPMP_RESET_VECTOR 0x200 - -static const uint64_t flowctrl_offset_cpu_csr[4] = { - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16) -}; - -static const uint64_t flowctrl_offset_halt_cpu[4] = { - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16) -}; - -static const uint64_t flowctrl_offset_cc4_ctrl[4] = { - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8), - (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12) -}; - -static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val) -{ - mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val); - val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]); -} - -static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val) -{ - mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val); - val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]); -} - -static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val) -{ - mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val); - val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]); -} - -static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr) -{ - uint32_t val; - - val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ | - FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ | - FLOWCTRL_WAITEVENT; - tegra_fc_halt_cpu(cpu_id, val); - - val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | - FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id); - tegra_fc_cpu_csr(cpu_id, val | csr); -} - -/******************************************************************************* - * After this, no core can wake from C7 until the action is reverted. - * If a wake up event is asserted, the FC state machine will stall until - * the action is reverted. - ******************************************************************************/ -void tegra_fc_ccplex_pgexit_lock(void) -{ - unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; - uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;; - uint32_t icept_cpu_flags[] = { - INTERCEPT_EXIT_PG_CORE0, - INTERCEPT_EXIT_PG_CORE1, - INTERCEPT_EXIT_PG_CORE2, - INTERCEPT_EXIT_PG_CORE3 - }; - - /* set the intercept flags */ - for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) { - - /* skip current CPU */ - if (i == cpu) - continue; - - /* enable power gate exit intercept locks */ - flags |= icept_cpu_flags[i]; - } - - tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags); - (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); -} - -/******************************************************************************* - * Revert the ccplex powergate exit locks - ******************************************************************************/ -void tegra_fc_ccplex_pgexit_unlock(void) -{ - /* clear lock bits, clear pending interrupts */ - tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING); - (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); -} - -/******************************************************************************* - * Powerdn the current CPU - ******************************************************************************/ -void tegra_fc_cpu_powerdn(uint32_t mpidr) -{ - int cpu = mpidr & MPIDR_CPU_MASK; - - VERBOSE("CPU%d powering down...\n", cpu); - tegra_fc_prepare_suspend(cpu, 0); -} - -/******************************************************************************* - * Suspend the current CPU cluster - ******************************************************************************/ -void tegra_fc_cluster_idle(uint32_t mpidr) -{ - int cpu = mpidr & MPIDR_CPU_MASK; - uint32_t val; - - VERBOSE("Entering cluster idle state...\n"); - - tegra_fc_cc4_ctrl(cpu, 0); - - /* hardware L2 flush is faster for A53 only */ - tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, - !!MPIDR_AFFLVL1_VAL(mpidr)); - - /* suspend the CPU cluster */ - val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT; - tegra_fc_prepare_suspend(cpu, val); -} - -/******************************************************************************* - * Power down the current CPU cluster - ******************************************************************************/ -void tegra_fc_cluster_powerdn(uint32_t mpidr) -{ - int cpu = mpidr & MPIDR_CPU_MASK; - uint32_t val; - - VERBOSE("Entering cluster powerdn state...\n"); - - tegra_fc_cc4_ctrl(cpu, 0); - - /* hardware L2 flush is faster for A53 only */ - tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, - read_midr() == CORTEX_A53_MIDR); - - /* power down the CPU cluster */ - val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; - tegra_fc_prepare_suspend(cpu, val); -} - -/******************************************************************************* - * Check if cluster idle or power down state is allowed from this CPU - ******************************************************************************/ -bool tegra_fc_is_ccx_allowed(void) -{ - unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; - uint32_t val; - bool ccx_allowed = true; - - for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) { - - /* skip current CPU */ - if (i == cpu) - continue; - - /* check if all other CPUs are already halted */ - val = mmio_read_32(flowctrl_offset_cpu_csr[i]); - if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) { - ccx_allowed = false; - } - } - - return ccx_allowed; -} - -/******************************************************************************* - * Suspend the entire SoC - ******************************************************************************/ -void tegra_fc_soc_powerdn(uint32_t mpidr) -{ - int cpu = mpidr & MPIDR_CPU_MASK; - uint32_t val; - - VERBOSE("Entering SoC powerdn state...\n"); - - tegra_fc_cc4_ctrl(cpu, 0); - - tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1); - - val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; - tegra_fc_prepare_suspend(cpu, val); - - /* overwrite HALT register */ - tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); -} - -/******************************************************************************* - * Power up the CPU - ******************************************************************************/ -void tegra_fc_cpu_on(int cpu) -{ - tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE); - tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK); -} - -/******************************************************************************* - * Power down the CPU - ******************************************************************************/ -void tegra_fc_cpu_off(int cpu) -{ - uint32_t val; - - /* - * Flow controller powers down the CPU during wfi. The CPU would be - * powered on when it receives any interrupt. - */ - val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | - FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu); - tegra_fc_cpu_csr(cpu, val); - tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); - tegra_fc_cc4_ctrl(cpu, 0); -} - -/******************************************************************************* - * Inform the BPMP that we have completed the cluster power up - ******************************************************************************/ -void tegra_fc_lock_active_cluster(void) -{ - uint32_t val; - - val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); - val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK; - tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val); - val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); -} - -/******************************************************************************* - * Power ON BPMP processor - ******************************************************************************/ -void tegra_fc_bpmp_on(uint32_t entrypoint) -{ - /* halt BPMP */ - tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); - - /* Assert BPMP reset */ - mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); - - /* Set reset address (stored in PMC_SCRATCH39) */ - mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint); - while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) - ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ - - /* Wait for 2us before de-asserting the reset signal. */ - udelay(2); - - /* De-assert BPMP reset */ - mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST); - - /* Un-halt BPMP */ - tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0); -} - -/******************************************************************************* - * Power OFF BPMP processor - ******************************************************************************/ -void tegra_fc_bpmp_off(void) -{ - /* halt BPMP */ - tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); - - /* Assert BPMP reset */ - mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); - - /* Clear reset address */ - mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0); - while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) - ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ -} - -/******************************************************************************* - * Route legacy FIQ to the GICD - ******************************************************************************/ -void tegra_fc_enable_fiq_to_ccplex_routing(void) -{ - uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); - - /* set the bit to pass FIQs to the GICD */ - tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE); -} - -/******************************************************************************* - * Disable routing legacy FIQ to the GICD - ******************************************************************************/ -void tegra_fc_disable_fiq_to_ccplex_routing(void) -{ - uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); - - /* clear the bit to pass FIQs to the GICD */ - tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE); -} diff --git a/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c b/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c deleted file mode 100644 index d68cdfd4b..000000000 --- a/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <arch_helpers.h> -#include <common/debug.h> -#include <drivers/delay_timer.h> -#include <errno.h> -#include <gpcdma.h> -#include <lib/mmio.h> -#include <lib/utils_def.h> -#include <platform_def.h> -#include <stdbool.h> -#include <tegra_def.h> - -/* DMA channel registers */ -#define DMA_CH_CSR U(0x0) -#define DMA_CH_CSR_WEIGHT_SHIFT U(10) -#define DMA_CH_CSR_XFER_MODE_SHIFT U(21) -#define DMA_CH_CSR_DMA_MODE_MEM2MEM U(4) -#define DMA_CH_CSR_DMA_MODE_FIXEDPATTERN U(6) -#define DMA_CH_CSR_IRQ_MASK_ENABLE (U(1) << 15) -#define DMA_CH_CSR_RUN_ONCE (U(1) << 27) -#define DMA_CH_CSR_ENABLE (U(1) << 31) - -#define DMA_CH_STAT U(0x4) -#define DMA_CH_STAT_BUSY (U(1) << 31) - -#define DMA_CH_SRC_PTR U(0xC) - -#define DMA_CH_DST_PTR U(0x10) - -#define DMA_CH_HI_ADR_PTR U(0x14) -#define DMA_CH_HI_ADR_PTR_SRC_MASK U(0xFF) -#define DMA_CH_HI_ADR_PTR_DST_SHIFT U(16) -#define DMA_CH_HI_ADR_PTR_DST_MASK U(0xFF) - -#define DMA_CH_MC_SEQ U(0x18) -#define DMA_CH_MC_SEQ_REQ_CNT_SHIFT U(25) -#define DMA_CH_MC_SEQ_REQ_CNT_VAL U(0x10) -#define DMA_CH_MC_SEQ_BURST_SHIFT U(23) -#define DMA_CH_MC_SEQ_BURST_16_WORDS U(0x3) - -#define DMA_CH_WORD_COUNT U(0x20) -#define DMA_CH_FIXED_PATTERN U(0x34) -#define DMA_CH_TZ U(0x38) -#define DMA_CH_TZ_ACCESS_ENABLE U(0) -#define DMA_CH_TZ_ACCESS_DISABLE U(3) - -#define MAX_TRANSFER_SIZE (1U*1024U*1024U*1024U) /* 1GB */ -#define GPCDMA_TIMEOUT_MS U(100) -#define GPCDMA_RESET_BIT (U(1) << 1) - -static bool init_done; - -static void tegra_gpcdma_write32(uint32_t offset, uint32_t val) -{ - mmio_write_32(TEGRA_GPCDMA_BASE + offset, val); -} - -static uint32_t tegra_gpcdma_read32(uint32_t offset) -{ - return mmio_read_32(TEGRA_GPCDMA_BASE + offset); -} - -static void tegra_gpcdma_init(void) -{ - /* assert reset for DMA engine */ - mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_SET_REG_OFFSET, - GPCDMA_RESET_BIT); - - udelay(2); - - /* de-assert reset for DMA engine */ - mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_CLR_REG_OFFSET, - GPCDMA_RESET_BIT); -} - -static void tegra_gpcdma_memcpy_priv(uint64_t dst_addr, uint64_t src_addr, - uint32_t num_bytes, uint32_t mode) -{ - uint32_t val, timeout = 0; - int32_t ret = 0; - - /* sanity check byte count */ - if ((num_bytes > MAX_TRANSFER_SIZE) || ((num_bytes & 0x3U) != U(0))) { - ret = -EINVAL; - } - - /* initialise GPCDMA block */ - if (!init_done) { - tegra_gpcdma_init(); - init_done = true; - } - - /* make sure channel isn't busy */ - val = tegra_gpcdma_read32(DMA_CH_STAT); - if ((val & DMA_CH_STAT_BUSY) == DMA_CH_STAT_BUSY) { - ERROR("DMA channel is busy\n"); - ret = -EBUSY; - } - - if (ret == 0) { - - /* disable any DMA transfers */ - tegra_gpcdma_write32(DMA_CH_CSR, 0); - - /* enable DMA access to TZDRAM */ - tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_ENABLE); - - /* configure MC sequencer */ - val = (DMA_CH_MC_SEQ_REQ_CNT_VAL << DMA_CH_MC_SEQ_REQ_CNT_SHIFT) | - (DMA_CH_MC_SEQ_BURST_16_WORDS << DMA_CH_MC_SEQ_BURST_SHIFT); - tegra_gpcdma_write32(DMA_CH_MC_SEQ, val); - - /* reset fixed pattern */ - tegra_gpcdma_write32(DMA_CH_FIXED_PATTERN, 0); - - /* populate src and dst address registers */ - tegra_gpcdma_write32(DMA_CH_SRC_PTR, (uint32_t)src_addr); - tegra_gpcdma_write32(DMA_CH_DST_PTR, (uint32_t)dst_addr); - - val = (uint32_t)((src_addr >> 32) & DMA_CH_HI_ADR_PTR_SRC_MASK); - val |= (uint32_t)(((dst_addr >> 32) & DMA_CH_HI_ADR_PTR_DST_MASK) << - DMA_CH_HI_ADR_PTR_DST_SHIFT); - tegra_gpcdma_write32(DMA_CH_HI_ADR_PTR, val); - - /* transfer size (in words) */ - tegra_gpcdma_write32(DMA_CH_WORD_COUNT, ((num_bytes >> 2) - 1U)); - - /* populate value for CSR */ - val = (mode << DMA_CH_CSR_XFER_MODE_SHIFT) | - DMA_CH_CSR_RUN_ONCE | (U(1) << DMA_CH_CSR_WEIGHT_SHIFT) | - DMA_CH_CSR_IRQ_MASK_ENABLE; - tegra_gpcdma_write32(DMA_CH_CSR, val); - - /* enable transfer */ - val = tegra_gpcdma_read32(DMA_CH_CSR); - val |= DMA_CH_CSR_ENABLE; - tegra_gpcdma_write32(DMA_CH_CSR, val); - - /* wait till transfer completes */ - do { - - /* read the status */ - val = tegra_gpcdma_read32(DMA_CH_STAT); - if ((val & DMA_CH_STAT_BUSY) != DMA_CH_STAT_BUSY) { - break; - } - - mdelay(1); - timeout++; - - } while (timeout < GPCDMA_TIMEOUT_MS); - - /* flag timeout error */ - if (timeout == GPCDMA_TIMEOUT_MS) { - ERROR("DMA transfer timed out\n"); - } - - dsbsy(); - - /* disable DMA access to TZDRAM */ - tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_DISABLE); - isb(); - } -} - -/******************************************************************************* - * Memcpy using GPCDMA block (Mem2Mem copy) - ******************************************************************************/ -void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr, - uint32_t num_bytes) -{ - tegra_gpcdma_memcpy_priv(dst_addr, src_addr, num_bytes, - DMA_CH_CSR_DMA_MODE_MEM2MEM); -} - -/******************************************************************************* - * Memset using GPCDMA block (Fixed pattern write) - ******************************************************************************/ -void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes) -{ - tegra_gpcdma_memcpy_priv(dst_addr, 0, num_bytes, - DMA_CH_CSR_DMA_MODE_FIXEDPATTERN); -} diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c deleted file mode 100644 index 92fa273b5..000000000 --- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> -#include <string.h> - -#include <arch_helpers.h> -#include <common/debug.h> -#include <lib/mmio.h> -#include <lib/utils.h> -#include <lib/xlat_tables/xlat_tables_v2.h> - -#include <memctrl.h> -#include <memctrl_v1.h> -#include <tegra_def.h> - -/* Video Memory base and size (live values) */ -static uint64_t video_mem_base; -static uint64_t video_mem_size; - -/* - * Init SMMU. - */ -void tegra_memctrl_setup(void) -{ - /* - * Setup the Memory controller to allow only secure accesses to - * the TZDRAM carveout - */ - INFO("Tegra Memory Controller (v1)\n"); - - /* allow translations for all MC engines */ - tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_0_0, - (unsigned int)MC_SMMU_TRANSLATION_ENABLE); - tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_1_0, - (unsigned int)MC_SMMU_TRANSLATION_ENABLE); - tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_2_0, - (unsigned int)MC_SMMU_TRANSLATION_ENABLE); - tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_3_0, - (unsigned int)MC_SMMU_TRANSLATION_ENABLE); - tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_4_0, - (unsigned int)MC_SMMU_TRANSLATION_ENABLE); - - tegra_mc_write_32(MC_SMMU_ASID_SECURITY_0, MC_SMMU_ASID_SECURITY); - - tegra_mc_write_32(MC_SMMU_TLB_CONFIG_0, MC_SMMU_TLB_CONFIG_0_RESET_VAL); - tegra_mc_write_32(MC_SMMU_PTC_CONFIG_0, MC_SMMU_PTC_CONFIG_0_RESET_VAL); - - /* flush PTC and TLB */ - tegra_mc_write_32(MC_SMMU_PTC_FLUSH_0, MC_SMMU_PTC_FLUSH_ALL); - (void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */ - tegra_mc_write_32(MC_SMMU_TLB_FLUSH_0, MC_SMMU_TLB_FLUSH_ALL); - - /* enable SMMU */ - tegra_mc_write_32(MC_SMMU_CONFIG_0, - MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE); - (void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */ - - /* video memory carveout */ - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, - (uint32_t)(video_mem_base >> 32)); - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)video_mem_base); - tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size); -} - -/* - * Restore Memory Controller settings after "System Suspend" - */ -void tegra_memctrl_restore_settings(void) -{ - tegra_memctrl_setup(); -} - -/* - * Secure the BL31 DRAM aperture. - * - * phys_base = physical base of TZDRAM aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - /* - * Setup the Memory controller to allow only secure accesses to - * the TZDRAM carveout - */ - INFO("Configuring TrustZone DRAM Memory Carveout\n"); - - tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base); - tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20); -} - -/* - * Secure the BL31 TZRAM aperture. - * - * phys_base = physical base of TZRAM aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - /* - * The v1 hardware controller does not have any registers - * for setting up the on-chip TZRAM. - */ -} - -static void tegra_clear_videomem(uintptr_t non_overlap_area_start, - unsigned long long non_overlap_area_size) -{ - int ret; - - /* - * Map the NS memory first, clean it and then unmap it. - */ - ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */ - non_overlap_area_start, /* VA */ - non_overlap_area_size, /* size */ - MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */ - assert(ret == 0); - - zeromem((void *)non_overlap_area_start, non_overlap_area_size); - flush_dcache_range(non_overlap_area_start, non_overlap_area_size); - - mmap_remove_dynamic_region(non_overlap_area_start, - non_overlap_area_size); -} - -/* - * Program the Video Memory carveout region - * - * phys_base = physical base of aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - uintptr_t vmem_end_old = video_mem_base + (video_mem_size << 20); - uintptr_t vmem_end_new = phys_base + size_in_bytes; - unsigned long long non_overlap_area_size; - - /* - * Setup the Memory controller to restrict CPU accesses to the Video - * Memory region - */ - INFO("Configuring Video Memory Carveout\n"); - - /* - * Configure Memory Controller directly for the first time. - */ - if (video_mem_base == 0) - goto done; - - /* - * Clear the old regions now being exposed. The following cases - * can occur - - * - * 1. clear whole old region (no overlap with new region) - * 2. clear old sub-region below new base - * 3. clear old sub-region above new end - */ - INFO("Cleaning previous Video Memory Carveout\n"); - - if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) { - tegra_clear_videomem(video_mem_base, video_mem_size << 20); - } else { - if (video_mem_base < phys_base) { - non_overlap_area_size = phys_base - video_mem_base; - tegra_clear_videomem(video_mem_base, non_overlap_area_size); - } - if (vmem_end_old > vmem_end_new) { - non_overlap_area_size = vmem_end_old - vmem_end_new; - tegra_clear_videomem(vmem_end_new, non_overlap_area_size); - } - } - -done: - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(phys_base >> 32)); - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base); - tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20); - - /* store new values */ - video_mem_base = phys_base; - video_mem_size = size_in_bytes >> 20; -} - -/* - * During boot, USB3 and flash media (SDMMC/SATA) devices need access to - * IRAM. Because these clients connect to the MC and do not have a direct - * path to the IRAM, the MC implements AHB redirection during boot to allow - * path to IRAM. In this mode, accesses to a programmed memory address aperture - * are directed to the AHB bus, allowing access to the IRAM. The AHB aperture - * is defined by the IRAM_BASE_LO and IRAM_BASE_HI registers, which are - * initialized to disable this aperture. - * - * Once bootup is complete, we must program IRAM base to 0xffffffff and - * IRAM top to 0x00000000, thus disabling access to IRAM. DRAM is then - * potentially accessible in this address range. These aperture registers - * also have an access_control/lock bit. After disabling the aperture, the - * access_control register should be programmed to lock the registers. - */ -void tegra_memctrl_disable_ahb_redirection(void) -{ - /* program the aperture registers */ - tegra_mc_write_32(MC_IRAM_BASE_LO, 0xFFFFFFFF); - tegra_mc_write_32(MC_IRAM_TOP_LO, 0); - tegra_mc_write_32(MC_IRAM_BASE_TOP_HI, 0); - - /* lock the aperture registers */ - tegra_mc_write_32(MC_IRAM_REG_CTRL, MC_DISABLE_IRAM_CFG_WRITES); -} - -void tegra_memctrl_clear_pending_interrupts(void) -{ - uint32_t mcerr; - - /* check if there are any pending interrupts */ - mcerr = mmio_read_32(TEGRA_MC_BASE + MC_INTSTATUS); - - if (mcerr != (uint32_t)0U) { /* should not see error here */ - WARN("MC_INTSTATUS = 0x%x (should be zero)\n", mcerr); - mmio_write_32((TEGRA_MC_BASE + MC_INTSTATUS), mcerr); - } -} diff --git a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c b/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c deleted file mode 100644 index 2f31906d8..000000000 --- a/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. - * Copyright (c) 2019, NVIDIA Corporation. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> -#include <string.h> - -#include <arch_helpers.h> -#include <common/bl_common.h> -#include <common/debug.h> -#include <lib/mmio.h> -#include <lib/utils.h> -#include <lib/xlat_tables/xlat_tables_v2.h> - -#include <mce.h> -#include <memctrl.h> -#include <memctrl_v2.h> -#include <smmu.h> -#include <tegra_def.h> -#include <tegra_platform.h> - -/* Video Memory base and size (live values) */ -static uint64_t video_mem_base; -static uint64_t video_mem_size_mb; - -/* - * The following platform setup functions are weakly defined. They - * provide typical implementations that will be overridden by a SoC. - */ -#pragma weak plat_memctrl_tzdram_setup - -void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes) -{ - ; /* do nothing */ -} - -/* - * Init Memory controller during boot. - */ -void tegra_memctrl_setup(void) -{ - uint32_t val; - const uint32_t *mc_streamid_override_regs; - uint32_t num_streamid_override_regs; - const mc_streamid_security_cfg_t *mc_streamid_sec_cfgs; - uint32_t num_streamid_sec_cfgs; - const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings(); - uint32_t i; - - INFO("Tegra Memory Controller (v2)\n"); - - /* Program the SMMU pagesize */ - tegra_smmu_init(); - - /* Get the settings from the platform */ - assert(plat_mc_settings != NULL); - mc_streamid_override_regs = plat_mc_settings->streamid_override_cfg; - num_streamid_override_regs = plat_mc_settings->num_streamid_override_cfgs; - mc_streamid_sec_cfgs = plat_mc_settings->streamid_security_cfg; - num_streamid_sec_cfgs = plat_mc_settings->num_streamid_security_cfgs; - - /* Program all the Stream ID overrides */ - for (i = 0; i < num_streamid_override_regs; i++) - tegra_mc_streamid_write_32(mc_streamid_override_regs[i], - MC_STREAM_ID_MAX); - - /* Program the security config settings for all Stream IDs */ - for (i = 0; i < num_streamid_sec_cfgs; i++) { - val = mc_streamid_sec_cfgs[i].override_enable << 16 | - mc_streamid_sec_cfgs[i].override_client_inputs << 8 | - mc_streamid_sec_cfgs[i].override_client_ns_flag << 0; - tegra_mc_streamid_write_32(mc_streamid_sec_cfgs[i].offset, val); - } - - /* - * All requests at boot time, and certain requests during - * normal run time, are physically addressed and must bypass - * the SMMU. The client hub logic implements a hardware bypass - * path around the Translation Buffer Units (TBU). During - * boot-time, the SMMU_BYPASS_CTRL register (which defaults to - * TBU_BYPASS mode) will be used to steer all requests around - * the uninitialized TBUs. During normal operation, this register - * is locked into TBU_BYPASS_SID config, which routes requests - * with special StreamID 0x7f on the bypass path and all others - * through the selected TBU. This is done to disable SMMU Bypass - * mode, as it could be used to circumvent SMMU security checks. - */ - tegra_mc_write_32(MC_SMMU_BYPASS_CONFIG, - MC_SMMU_BYPASS_CONFIG_SETTINGS); - - /* - * Re-configure MSS to allow ROC to deal with ordering of the - * Memory Controller traffic. This is needed as the Memory Controller - * boots with MSS having all control, but ROC provides a performance - * boost as compared to MSS. - */ - if (plat_mc_settings->reconfig_mss_clients != NULL) { - plat_mc_settings->reconfig_mss_clients(); - } - - /* Program overrides for MC transactions */ - if (plat_mc_settings->set_txn_overrides != NULL) { - plat_mc_settings->set_txn_overrides(); - } -} - -/* - * Restore Memory Controller settings after "System Suspend" - */ -void tegra_memctrl_restore_settings(void) -{ - const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings(); - - assert(plat_mc_settings != NULL); - - /* - * Re-configure MSS to allow ROC to deal with ordering of the - * Memory Controller traffic. This is needed as the Memory Controller - * resets during System Suspend with MSS having all control, but ROC - * provides a performance boost as compared to MSS. - */ - if (plat_mc_settings->reconfig_mss_clients != NULL) { - plat_mc_settings->reconfig_mss_clients(); - } - - /* Program overrides for MC transactions */ - if (plat_mc_settings->set_txn_overrides != NULL) { - plat_mc_settings->set_txn_overrides(); - } - - /* video memory carveout region */ - if (video_mem_base != 0ULL) { - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, - (uint32_t)video_mem_base); - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, - (uint32_t)(video_mem_base >> 32)); - tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb); - - /* - * MCE propagates the VideoMem configuration values across the - * CCPLEX. - */ - mce_update_gsc_videomem(); - } -} - -/* - * Secure the BL31 DRAM aperture. - * - * phys_base = physical base of TZDRAM aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - /* - * Perform platform specific steps. - */ - plat_memctrl_tzdram_setup(phys_base, size_in_bytes); -} - -/* - * Secure the BL31 TZRAM aperture. - * - * phys_base = physical base of TZRAM aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - uint32_t index; - uint32_t total_128kb_blocks = size_in_bytes >> 17; - uint32_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12; - uint32_t val; - - INFO("Configuring TrustZone SRAM Memory Carveout\n"); - - /* - * Reset the access configuration registers to restrict access - * to the TZRAM aperture - */ - for (index = MC_TZRAM_CLIENT_ACCESS0_CFG0; - index < ((uint32_t)MC_TZRAM_CARVEOUT_CFG + (uint32_t)MC_GSC_CONFIG_REGS_SIZE); - index += 4U) { - tegra_mc_write_32(index, 0); - } - - /* - * Enable CPU access configuration registers to access the TZRAM aperture - */ - if (!tegra_chipid_is_t186()) { - val = tegra_mc_read_32(MC_TZRAM_CLIENT_ACCESS1_CFG0); - val |= TZRAM_ALLOW_MPCORER | TZRAM_ALLOW_MPCOREW; - tegra_mc_write_32(MC_TZRAM_CLIENT_ACCESS1_CFG0, val); - } - - /* - * Set the TZRAM base. TZRAM base must be 4k aligned, at least. - */ - assert((phys_base & (uint64_t)0xFFF) == 0U); - tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base); - tegra_mc_write_32(MC_TZRAM_BASE_HI, - (uint32_t)(phys_base >> 32) & MC_GSC_BASE_HI_MASK); - - /* - * Set the TZRAM size - * - * total size = (number of 128KB blocks) + (number of remaining 4KB - * blocks) - * - */ - val = (residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) | - total_128kb_blocks; - tegra_mc_write_32(MC_TZRAM_SIZE, val); - - /* - * Lock the configuration settings by disabling TZ-only lock - * and locking the configuration against any future changes - * at all. - */ - val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG); - val &= (uint32_t)~MC_GSC_ENABLE_TZ_LOCK_BIT; - val |= MC_GSC_LOCK_CFG_SETTINGS_BIT; - if (!tegra_chipid_is_t186()) { - val |= MC_GSC_ENABLE_CPU_SECURE_BIT; - } - tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val); - - /* - * MCE propagates the security configuration values across the - * CCPLEX. - */ - mce_update_gsc_tzram(); -} - -static void tegra_lock_videomem_nonoverlap(uint64_t phys_base, - uint64_t size_in_bytes) -{ - uint32_t index; - uint64_t total_128kb_blocks = size_in_bytes >> 17; - uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12; - uint64_t val; - - /* - * Reset the access configuration registers to restrict access to - * old Videomem aperture - */ - for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0; - index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE); - index += 4U) { - tegra_mc_write_32(index, 0); - } - - /* - * Set the base. It must be 4k aligned, at least. - */ - assert((phys_base & (uint64_t)0xFFF) == 0U); - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base); - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, - (uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK); - - /* - * Set the aperture size - * - * total size = (number of 128KB blocks) + (number of remaining 4KB - * blocks) - * - */ - val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) | - total_128kb_blocks); - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val); - - /* - * Lock the configuration settings by enabling TZ-only lock and - * locking the configuration against any future changes from NS - * world. - */ - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG, - (uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT); - - /* - * MCE propagates the GSC configuration values across the - * CCPLEX. - */ -} - -static void tegra_unlock_videomem_nonoverlap(void) -{ - /* Clear the base */ - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0); - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0); - - /* Clear the size */ - tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0); -} - -static void tegra_clear_videomem(uintptr_t non_overlap_area_start, - unsigned long long non_overlap_area_size) -{ - int ret; - - /* - * Map the NS memory first, clean it and then unmap it. - */ - ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */ - non_overlap_area_start, /* VA */ - non_overlap_area_size, /* size */ - MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */ - assert(ret == 0); - - zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size); - flush_dcache_range(non_overlap_area_start, non_overlap_area_size); - - (void)mmap_remove_dynamic_region(non_overlap_area_start, - non_overlap_area_size); -} - -/* - * Program the Video Memory carveout region - * - * phys_base = physical base of aperture - * size_in_bytes = size of aperture in bytes - */ -void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes) -{ - uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20); - uintptr_t vmem_end_new = phys_base + size_in_bytes; - unsigned long long non_overlap_area_size; - - /* - * Setup the Memory controller to restrict CPU accesses to the Video - * Memory region - */ - INFO("Configuring Video Memory Carveout\n"); - - /* - * Configure Memory Controller directly for the first time. - */ - if (video_mem_base == 0U) - goto done; - - /* - * Lock the non overlapping memory being cleared so that other masters - * do not accidently write to it. The memory would be unlocked once - * the non overlapping region is cleared and the new memory - * settings take effect. - */ - tegra_lock_videomem_nonoverlap(video_mem_base, - video_mem_size_mb << 20); - - /* - * Clear the old regions now being exposed. The following cases - * can occur - - * - * 1. clear whole old region (no overlap with new region) - * 2. clear old sub-region below new base - * 3. clear old sub-region above new end - */ - INFO("Cleaning previous Video Memory Carveout\n"); - - if ((phys_base > vmem_end_old) || (video_mem_base > vmem_end_new)) { - tegra_clear_videomem(video_mem_base, - video_mem_size_mb << 20U); - } else { - if (video_mem_base < phys_base) { - non_overlap_area_size = phys_base - video_mem_base; - tegra_clear_videomem(video_mem_base, non_overlap_area_size); - } - if (vmem_end_old > vmem_end_new) { - non_overlap_area_size = vmem_end_old - vmem_end_new; - tegra_clear_videomem(vmem_end_new, non_overlap_area_size); - } - } - -done: - /* program the Videomem aperture */ - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base); - tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, - (uint32_t)(phys_base >> 32)); - tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20); - - /* unlock the previous locked nonoverlapping aperture */ - tegra_unlock_videomem_nonoverlap(); - - /* store new values */ - video_mem_base = phys_base; - video_mem_size_mb = size_in_bytes >> 20; - - /* - * MCE propagates the VideoMem configuration values across the - * CCPLEX. - */ - mce_update_gsc_videomem(); -} - -/* - * This feature exists only for v1 of the Tegra Memory Controller. - */ -void tegra_memctrl_disable_ahb_redirection(void) -{ - ; /* do nothing */ -} - -void tegra_memctrl_clear_pending_interrupts(void) -{ - ; /* do nothing */ -} diff --git a/plat/nvidia/tegra/common/drivers/pmc/pmc.c b/plat/nvidia/tegra/common/drivers/pmc/pmc.c deleted file mode 100644 index 6c5a73baf..000000000 --- a/plat/nvidia/tegra/common/drivers/pmc/pmc.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> - -#include <arch_helpers.h> -#include <common/debug.h> -#include <lib/mmio.h> - -#include <pmc.h> -#include <tegra_def.h> - -#define RESET_ENABLE 0x10U - -/* Module IDs used during power ungate procedure */ -static const uint32_t pmc_cpu_powergate_id[4] = { - 14, /* CPU 0 */ - 9, /* CPU 1 */ - 10, /* CPU 2 */ - 11 /* CPU 3 */ -}; - -/******************************************************************************* - * Power ungate CPU to start the boot process. CPU reset vectors must be - * populated before calling this function. - ******************************************************************************/ -void tegra_pmc_cpu_on(int32_t cpu) -{ - uint32_t val; - - /* - * Check if CPU is already power ungated - */ - val = tegra_pmc_read_32(PMC_PWRGATE_STATUS); - if ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U) { - /* - * The PMC deasserts the START bit when it starts the power - * ungate process. Loop till no power toggle is in progress. - */ - do { - val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE); - } while ((val & PMC_TOGGLE_START) != 0U); - - /* - * Start the power ungate procedure - */ - val = pmc_cpu_powergate_id[cpu] | PMC_TOGGLE_START; - tegra_pmc_write_32(PMC_PWRGATE_TOGGLE, val); - - /* - * The PMC deasserts the START bit when it starts the power - * ungate process. Loop till powergate START bit is asserted. - */ - do { - val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE); - } while ((val & (1U << 8)) != 0U); - - /* loop till the CPU is power ungated */ - do { - val = tegra_pmc_read_32(PMC_PWRGATE_STATUS); - } while ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U); - } -} - -/******************************************************************************* - * Setup CPU vectors for resume from deep sleep - ******************************************************************************/ -void tegra_pmc_cpu_setup(uint64_t reset_addr) -{ - uint32_t val; - - tegra_pmc_write_32(PMC_SECURE_SCRATCH34, - ((uint32_t)reset_addr & 0xFFFFFFFFU) | 1U); - val = (uint32_t)(reset_addr >> 32U); - tegra_pmc_write_32(PMC_SECURE_SCRATCH35, val & 0x7FFU); -} - -/******************************************************************************* - * Lock CPU vectors to restrict further writes - ******************************************************************************/ -void tegra_pmc_lock_cpu_vectors(void) -{ - uint32_t val; - - /* lock PMC_SECURE_SCRATCH22 */ - val = tegra_pmc_read_32(PMC_SECURE_DISABLE2); - val |= PMC_SECURE_DISABLE2_WRITE22_ON; - tegra_pmc_write_32(PMC_SECURE_DISABLE2, val); - - /* lock PMC_SECURE_SCRATCH34/35 */ - val = tegra_pmc_read_32(PMC_SECURE_DISABLE3); - val |= (PMC_SECURE_DISABLE3_WRITE34_ON | - PMC_SECURE_DISABLE3_WRITE35_ON); - tegra_pmc_write_32(PMC_SECURE_DISABLE3, val); -} - -/******************************************************************************* - * Find out if this is the last standing CPU - ******************************************************************************/ -bool tegra_pmc_is_last_on_cpu(void) -{ - int i, cpu = read_mpidr() & MPIDR_CPU_MASK; - uint32_t val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);; - bool status = true; - - /* check if this is the last standing CPU */ - for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) { - - /* skip the current CPU */ - if (i == cpu) - continue; - - /* are other CPUs already power gated? */ - if ((val & ((uint32_t)1 << pmc_cpu_powergate_id[i])) != 0U) { - status = false; - } - } - - return status; -} - -/******************************************************************************* - * Handler to be called on exiting System suspend. Right now only DPD registers - * are cleared. - ******************************************************************************/ -void tegra_pmc_resume(void) -{ - - /* Clear DPD sample */ - mmio_write_32((TEGRA_PMC_BASE + PMC_IO_DPD_SAMPLE), 0x0); - - /* Clear DPD Enable */ - mmio_write_32((TEGRA_PMC_BASE + PMC_DPD_ENABLE_0), 0x0); -} - -/******************************************************************************* - * Restart the system - ******************************************************************************/ -__dead2 void tegra_pmc_system_reset(void) -{ - uint32_t reg; - - reg = tegra_pmc_read_32(PMC_CONFIG); - reg |= RESET_ENABLE; /* restart */ - tegra_pmc_write_32(PMC_CONFIG, reg); - wfi(); - - ERROR("Tegra System Reset: operation not handled.\n"); - panic(); -} diff --git a/plat/nvidia/tegra/common/drivers/smmu/smmu.c b/plat/nvidia/tegra/common/drivers/smmu/smmu.c deleted file mode 100644 index 8c1b899f7..000000000 --- a/plat/nvidia/tegra/common/drivers/smmu/smmu.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <assert.h> -#include <string.h> - -#include <platform_def.h> - -#include <common/bl_common.h> -#include <common/debug.h> - -#include <smmu.h> -#include <tegra_private.h> - -extern void memcpy16(void *dest, const void *src, unsigned int length); - -/* SMMU IDs currently supported by the driver */ -enum { - TEGRA_SMMU0 = 0U, - TEGRA_SMMU1, - TEGRA_SMMU2 -}; - -static uint32_t tegra_smmu_read_32(uint32_t smmu_id, uint32_t off) -{ - uint32_t ret = 0U; - -#if defined(TEGRA_SMMU0_BASE) - if (smmu_id == TEGRA_SMMU0) { - ret = mmio_read_32(TEGRA_SMMU0_BASE + (uint64_t)off); - } -#endif - -#if defined(TEGRA_SMMU1_BASE) - if (smmu_id == TEGRA_SMMU1) { - ret = mmio_read_32(TEGRA_SMMU1_BASE + (uint64_t)off); - } -#endif - -#if defined(TEGRA_SMMU2_BASE) - if (smmu_id == TEGRA_SMMU2) { - ret = mmio_read_32(TEGRA_SMMU2_BASE + (uint64_t)off); - } -#endif - - return ret; -} - -static void tegra_smmu_write_32(uint32_t smmu_id, - uint32_t off, uint32_t val) -{ -#if defined(TEGRA_SMMU0_BASE) - if (smmu_id == TEGRA_SMMU0) { - mmio_write_32(TEGRA_SMMU0_BASE + (uint64_t)off, val); - } -#endif - -#if defined(TEGRA_SMMU1_BASE) - if (smmu_id == TEGRA_SMMU1) { - mmio_write_32(TEGRA_SMMU1_BASE + (uint64_t)off, val); - } -#endif - -#if defined(TEGRA_SMMU2_BASE) - if (smmu_id == TEGRA_SMMU2) { - mmio_write_32(TEGRA_SMMU2_BASE + (uint64_t)off, val); - } -#endif -} - -/* - * Save SMMU settings before "System Suspend" to TZDRAM - */ -void tegra_smmu_save_context(uint64_t smmu_ctx_addr) -{ - uint32_t i, num_entries = 0; - smmu_regs_t *smmu_ctx_regs; - const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); - uint64_t tzdram_base = params_from_bl2->tzdram_base; - uint64_t tzdram_end = tzdram_base + params_from_bl2->tzdram_size; - uint32_t reg_id1, pgshift, cb_size; - - /* sanity check SMMU settings c*/ - reg_id1 = mmio_read_32((TEGRA_SMMU0_BASE + SMMU_GNSR0_IDR1)); - pgshift = ((reg_id1 & ID1_PAGESIZE) != 0U) ? 16U : 12U; - cb_size = ((uint32_t)2 << pgshift) * \ - ((uint32_t)1 << (((reg_id1 >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1U)); - - assert(!((pgshift != PGSHIFT) || (cb_size != CB_SIZE))); - assert((smmu_ctx_addr >= tzdram_base) && (smmu_ctx_addr <= tzdram_end)); - - /* get SMMU context table */ - smmu_ctx_regs = plat_get_smmu_ctx(); - assert(smmu_ctx_regs != NULL); - - /* - * smmu_ctx_regs[0].val contains the size of the context table minus - * the last entry. Sanity check the table size before we start with - * the context save operation. - */ - while ((smmu_ctx_regs[num_entries].reg != 0xFFFFFFFFU)) { - num_entries++; - } - - /* panic if the sizes do not match */ - if (num_entries != smmu_ctx_regs[0].val) { - ERROR("SMMU context size mismatch!"); - panic(); - } - - /* save SMMU register values */ - for (i = 1U; i < num_entries; i++) { - smmu_ctx_regs[i].val = mmio_read_32(smmu_ctx_regs[i].reg); - } - - /* increment by 1 to take care of the last entry */ - num_entries++; - - /* Save SMMU config settings */ - (void)memcpy16((uint8_t *)smmu_ctx_addr, (uint8_t *)smmu_ctx_regs, - (sizeof(smmu_regs_t) * num_entries)); - - /* save the SMMU table address */ - mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_LO, - (uint32_t)smmu_ctx_addr); - mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_HI, - (uint32_t)(smmu_ctx_addr >> 32)); -} - -#define SMMU_NUM_CONTEXTS 64 -#define SMMU_CONTEXT_BANK_MAX_IDX 64 - -/* - * Init SMMU during boot or "System Suspend" exit - */ -void tegra_smmu_init(void) -{ - uint32_t val, cb_idx, smmu_id, ctx_base; - uint32_t smmu_counter = plat_get_num_smmu_devices(); - - for (smmu_id = 0U; smmu_id < smmu_counter; smmu_id++) { - /* Program the SMMU pagesize and reset CACHE_LOCK bit */ - val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR); - val |= SMMU_GSR0_PGSIZE_64K; - val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; - tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val); - - /* reset CACHE LOCK bit for NS Aux. Config. Register */ - val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR); - val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; - tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val); - - /* disable TCU prefetch for all contexts */ - ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) - + SMMU_CBn_ACTLR; - for (cb_idx = 0; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) { - val = tegra_smmu_read_32(smmu_id, - ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx)); - val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT; - tegra_smmu_write_32(smmu_id, ctx_base + - (SMMU_GSR0_PGSIZE_64K * cb_idx), val); - } - - /* set CACHE LOCK bit for NS Aux. Config. Register */ - val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR); - val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT; - tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val); - - /* set CACHE LOCK bit for S Aux. Config. Register */ - val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR); - val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT; - tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val); - } -} diff --git a/plat/nvidia/tegra/common/drivers/spe/shared_console.S b/plat/nvidia/tegra/common/drivers/spe/shared_console.S deleted file mode 100644 index a3e110ec9..000000000 --- a/plat/nvidia/tegra/common/drivers/spe/shared_console.S +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -#include <asm_macros.S> -#include <console_macros.S> - -#define CONSOLE_NUM_BYTES_SHIFT 24 -#define CONSOLE_FLUSH_DATA_TO_PORT (1 << 26) -#define CONSOLE_RING_DOORBELL (1 << 31) -#define CONSOLE_IS_BUSY (1 << 31) -#define CONSOLE_WRITE (CONSOLE_RING_DOORBELL | CONSOLE_FLUSH_DATA_TO_PORT) - - /* - * This file contains a driver implementation to make use of the - * real console implementation provided by the SPE firmware running - * SoCs after Tegra186. - * - * This console is shared by multiple components and the SPE firmware - * finally displays everything on the UART port. - */ - - .globl console_spe_core_init - .globl console_spe_core_putc - .globl console_spe_core_getc - .globl console_spe_core_flush - .globl console_spe_putc - .globl console_spe_getc - .globl console_spe_flush - .globl console_spe_register - - /* ------------------------------------------------- - * int console_spe_register(uintptr_t baseaddr, - * uint32_t clock, uint32_t baud, - * console_spe_t *console); - * Function to initialize and register a new spe - * console. Storage passed in for the console struct - * *must* be persistent (i.e. not from the stack). - * In: x0 - UART register base address - * w1 - UART clock in Hz - * w2 - Baud rate - * x3 - pointer to empty console_spe_t struct - * Out: return 1 on success, 0 on error - * Clobber list : x0, x1, x2, x6, x7, x14 - * ------------------------------------------------- - */ -func console_spe_register - cbz x3, register_fail - str x0, [x3, #CONSOLE_T_DRVDATA] - mov x0, x3 - finish_console_register spe putc=1, getc=1, flush=1 - -register_fail: - mov w0, wzr - ret -endfunc console_spe_register - - /* -------------------------------------------------------- - * int console_spe_core_putc(int c, uintptr_t base_addr) - * Function to output a character over the console. It - * returns the character printed on success or -1 on error. - * In : w0 - character to be printed - * x1 - console base address - * Out : return -1 on error else return character. - * Clobber list : x2 - * -------------------------------------------------------- - */ -func console_spe_core_putc - /* Check the input parameter */ - cbz x1, putc_error - - /* Prepend '\r' to '\n' */ - cmp w0, #0xA - b.ne 2f - - /* wait until spe is ready */ -1: ldr w2, [x1] - and w2, w2, #CONSOLE_IS_BUSY - cbnz w2, 1b - - /* spe is ready */ - mov w2, #0xD /* '\r' */ - and w2, w2, #0xFF - mov w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT)) - orr w2, w2, w3 - str w2, [x1] - - /* wait until spe is ready */ -2: ldr w2, [x1] - and w2, w2, #CONSOLE_IS_BUSY - cbnz w2, 2b - - /* spe is ready */ - mov w2, w0 - and w2, w2, #0xFF - mov w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT)) - orr w2, w2, w3 - str w2, [x1] - - ret -putc_error: - mov w0, #-1 - ret -endfunc console_spe_core_putc - - /* -------------------------------------------------------- - * int console_spe_putc(int c, console_spe_t *console) - * Function to output a character over the console. It - * returns the character printed on success or -1 on error. - * In : w0 - character to be printed - * x1 - pointer to console_t structure - * Out : return -1 on error else return character. - * Clobber list : x2 - * -------------------------------------------------------- - */ -func console_spe_putc - ldr x1, [x1, #CONSOLE_T_DRVDATA] - b console_spe_core_putc -endfunc console_spe_putc - - /* --------------------------------------------- - * int console_spe_getc(console_spe_t *console) - * Function to get a character from the console. - * It returns the character grabbed on success - * or -1 if no character is available. - * In : x0 - pointer to console_t structure - * Out: w0 - character if available, else -1 - * Clobber list : x0, x1 - * --------------------------------------------- - */ -func console_spe_getc - mov w0, #-1 - ret -endfunc console_spe_getc - - /* ------------------------------------------------- - * int console_spe_core_flush(uintptr_t base_addr) - * Function to force a write of all buffered - * data that hasn't been output. - * In : x0 - console base address - * Out : return -1 on error else return 0. - * Clobber list : x0, x1 - * ------------------------------------------------- - */ -func console_spe_core_flush - cbz x0, flush_error - - /* flush console */ - mov w1, #CONSOLE_WRITE - str w1, [x0] - mov w0, #0 - ret -flush_error: - mov w0, #-1 - ret -endfunc console_spe_core_flush - - /* --------------------------------------------- - * int console_spe_flush(console_spe_t *console) - * Function to force a write of all buffered - * data that hasn't been output. - * In : x0 - pointer to console_t structure - * Out : return -1 on error else return 0. - * Clobber list : x0, x1 - * --------------------------------------------- - */ -func console_spe_flush - ldr x0, [x0, #CONSOLE_T_DRVDATA] - b console_spe_core_flush -endfunc console_spe_flush diff --git a/plat/nvidia/tegra/common/lib/debug/profiler.c b/plat/nvidia/tegra/common/lib/debug/profiler.c deleted file mode 100644 index dd76a4e96..000000000 --- a/plat/nvidia/tegra/common/lib/debug/profiler.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/******************************************************************************* - * The profiler stores the timestamps captured during cold boot to the shared - * memory for the non-secure world. The non-secure world driver parses the - * shared memory block and writes the contents to a file on the device, which - * can be later extracted for analysis. - * - * Profiler memory map - * - * TOP --------------------------- --- - * Trusted OS timestamps 3KB - * --------------------------- --- - * Trusted Firmware timestamps 1KB - * BASE --------------------------- --- - * - ******************************************************************************/ - -#include <arch.h> -#include <arch_helpers.h> -#include <assert.h> -#include <lib/mmio.h> -#include <lib/utils_def.h> -#include <lib/xlat_tables/xlat_tables_v2.h> -#include <profiler.h> -#include <stdbool.h> -#include <string.h> - -static uint64_t shmem_base_addr; - -#define MAX_PROFILER_RECORDS U(16) -#define TAG_LEN_BYTES U(56) - -/******************************************************************************* - * Profiler entry format - ******************************************************************************/ -typedef struct { - /* text explaining the timestamp location in code */ - uint8_t tag[TAG_LEN_BYTES]; - /* timestamp value */ - uint64_t timestamp; -} profiler_rec_t; - -static profiler_rec_t *head, *cur, *tail; -static uint32_t tmr; -static bool is_shmem_buf_mapped; - -/******************************************************************************* - * Initialise the profiling library - ******************************************************************************/ -void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base) -{ - uint64_t shmem_end_base; - - assert(shmem_base != ULL(0)); - assert(tmr_base != U(0)); - - /* store the buffer address */ - shmem_base_addr = shmem_base; - - /* calculate the base address of the last record */ - shmem_end_base = shmem_base + (sizeof(profiler_rec_t) * - (MAX_PROFILER_RECORDS - U(1))); - - /* calculate the head, tail and cur values */ - head = (profiler_rec_t *)shmem_base; - tail = (profiler_rec_t *)shmem_end_base; - cur = head; - - /* timer used to get the current timestamp */ - tmr = tmr_base; -} - -/******************************************************************************* - * Add tag and timestamp to profiler - ******************************************************************************/ -void boot_profiler_add_record(const char *str) -{ - unsigned int len; - - /* calculate the length of the tag */ - if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) { - len = TAG_LEN_BYTES; - } else { - len = (unsigned int)strlen(str) + U(1); - } - - if (head != NULL) { - - /* - * The profiler runs with/without MMU enabled. Check - * if MMU is enabled and memmap the shmem buffer, in - * case it is. - */ - if ((!is_shmem_buf_mapped) && - ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) { - - (void)mmap_add_dynamic_region(shmem_base_addr, - shmem_base_addr, - PROFILER_SIZE_BYTES, - (MT_NS | MT_RW | MT_EXECUTE_NEVER)); - - is_shmem_buf_mapped = true; - } - - /* write the tag and timestamp to buffer */ - (void)snprintf((char *)cur->tag, len, "%s", str); - cur->timestamp = mmio_read_32(tmr); - - /* start from head if we reached the end */ - if (cur == tail) { - cur = head; - } else { - cur++; - } - } -} - -/******************************************************************************* - * Deinint the profiler - ******************************************************************************/ -void boot_profiler_deinit(void) -{ - if (shmem_base_addr != ULL(0)) { - - /* clean up resources */ - cur = NULL; - head = NULL; - tail = NULL; - - /* flush the shmem for it to be visible to the NS world */ - flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES); - - /* unmap the shmem buffer */ - if (is_shmem_buf_mapped) { - (void)mmap_remove_dynamic_region(shmem_base_addr, - PROFILER_SIZE_BYTES); - } - } -} diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index cbe3377b0..cb4886f1a 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -16,7 +17,6 @@ #include <bl31/bl31.h> #include <common/bl_common.h> #include <common/debug.h> -#include <cortex_a53.h> #include <cortex_a57.h> #include <denver.h> #include <drivers/console.h> @@ -27,6 +27,7 @@ #include <memctrl.h> #include <profiler.h> +#include <smmu.h> #include <tegra_def.h> #include <tegra_platform.h> #include <tegra_private.h> @@ -34,21 +35,12 @@ /* length of Trusty's input parameters (in bytes) */ #define TRUSTY_PARAMS_LEN_BYTES (4096*2) -extern void memcpy16(void *dest, const void *src, unsigned int length); - /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout * of trusted SRAM ******************************************************************************/ - IMPORT_SYM(uint64_t, __RW_START__, BL31_RW_START); -static const uint64_t BL31_RW_END = BL_END; -static const uint64_t BL31_RODATA_BASE = BL_RO_DATA_BASE; -static const uint64_t BL31_RODATA_END = BL_RO_DATA_END; -static const uint64_t TEXT_START = BL_CODE_BASE; -static const uint64_t TEXT_END = BL_CODE_END; - extern uint64_t tegra_bl31_phys_base; static entry_point_info_t bl33_image_ep_info, bl32_image_ep_info; @@ -65,35 +57,6 @@ static aapcs64_params_t bl32_args; extern uint64_t ns_image_entrypoint; /******************************************************************************* - * The following platform setup functions are weakly defined. They - * provide typical implementations that will be overridden by a SoC. - ******************************************************************************/ -#pragma weak plat_early_platform_setup -#pragma weak plat_get_bl31_params -#pragma weak plat_get_bl31_plat_params -#pragma weak plat_late_platform_setup - -void plat_early_platform_setup(void) -{ - ; /* do nothing */ -} - -struct tegra_bl31_params *plat_get_bl31_params(void) -{ - return NULL; -} - -plat_params_from_bl2_t *plat_get_bl31_plat_params(void) -{ - return NULL; -} - -void plat_late_platform_setup(void) -{ - ; /* do nothing */ -} - -/******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. @@ -130,15 +93,12 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, { struct tegra_bl31_params *arg_from_bl2 = (struct tegra_bl31_params *) arg0; plat_params_from_bl2_t *plat_params = (plat_params_from_bl2_t *)arg1; - image_info_t bl32_img_info = { {0} }; - uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end; int32_t ret; /* * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so * there's no argument to relay from a previous bootloader. Platforms - * might use custom ways to get arguments, so provide handlers which - * they can override. + * might use custom ways to get arguments. */ if (arg_from_bl2 == NULL) { arg_from_bl2 = plat_get_bl31_params(); @@ -193,20 +153,17 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, * location to store the boot profiler logs. Sanity check the * address and initialise the profiler library, if it looks ok. */ - if (plat_params->boot_profiler_shmem_base != 0ULL) { + ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base, + PROFILER_SIZE_BYTES); + if (ret == (int32_t)0) { - ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base, - PROFILER_SIZE_BYTES); - if (ret == (int32_t)0) { + /* store the membase for the profiler lib */ + plat_bl31_params_from_bl2.boot_profiler_shmem_base = + plat_params->boot_profiler_shmem_base; - /* store the membase for the profiler lib */ - plat_bl31_params_from_bl2.boot_profiler_shmem_base = - plat_params->boot_profiler_shmem_base; - - /* initialise the profiler library */ - boot_profiler_init(plat_params->boot_profiler_shmem_base, - TEGRA_TMRUS_BASE); - } + /* initialise the profiler library */ + boot_profiler_init(plat_params->boot_profiler_shmem_base, + TEGRA_TMRUS_BASE); } /* @@ -223,48 +180,6 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, plat_early_platform_setup(); /* - * Do initial security configuration to allow DRAM/device access. - */ - tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, - (uint32_t)plat_bl31_params_from_bl2.tzdram_size); - - /* - * The previous bootloader might not have placed the BL32 image - * inside the TZDRAM. We check the BL32 image info to find out - * the base/PC values and relocate the image if necessary. - */ - if (arg_from_bl2->bl32_image_info != NULL) { - - bl32_img_info = *arg_from_bl2->bl32_image_info; - - /* Relocate BL32 if it resides outside of the TZDRAM */ - tzdram_start = plat_bl31_params_from_bl2.tzdram_base; - tzdram_end = plat_bl31_params_from_bl2.tzdram_base + - plat_bl31_params_from_bl2.tzdram_size; - bl32_start = bl32_img_info.image_base; - bl32_end = bl32_img_info.image_base + bl32_img_info.image_size; - - assert(tzdram_end > tzdram_start); - assert(bl32_end > bl32_start); - assert(bl32_image_ep_info.pc > tzdram_start); - assert(bl32_image_ep_info.pc < tzdram_end); - - /* relocate BL32 */ - if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) { - - INFO("Relocate BL32 to TZDRAM\n"); - - (void)memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc, - (void *)(uintptr_t)bl32_start, - bl32_img_info.image_size); - - /* clean up non-secure intermediate buffer */ - zeromem((void *)(uintptr_t)bl32_start, - bl32_img_info.image_size); - } - } - - /* * Add timestamp for platform early setup exit. */ boot_profiler_add_record("[TF] early setup exit"); @@ -318,12 +233,6 @@ void bl31_platform_setup(void) tegra_memctrl_setup(); /* - * Set up the TZRAM memory aperture to allow only secure world - * access - */ - tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); - - /* * Late setup handler to allow platforms to performs additional * functionality. * This handler gets called with MMU enabled. @@ -344,24 +253,9 @@ void bl31_platform_setup(void) void bl31_plat_runtime_setup(void) { /* - * During cold boot, it is observed that the arbitration - * bit is set in the Memory controller leading to false - * error interrupts in the non-secure world. To avoid - * this, clean the interrupt status register before - * booting into the non-secure world + * Platform specific runtime setup */ - tegra_memctrl_clear_pending_interrupts(); - - /* - * During boot, USB3 and flash media (SDMMC/SATA) devices need - * access to IRAM. Because these clients connect to the MC and - * do not have a direct path to the IRAM, the MC implements AHB - * redirection during boot to allow path to IRAM. In this mode - * accesses to a programmed memory address aperture are directed - * to the AHB bus, allowing access to the IRAM. This mode must be - * disabled before we jump to the non-secure world. - */ - tegra_memctrl_disable_ahb_redirection(); + plat_runtime_setup(); /* * Add final timestamp before exiting BL31. @@ -377,15 +271,12 @@ void bl31_plat_runtime_setup(void) void bl31_plat_arch_setup(void) { uint64_t rw_start = BL31_RW_START; - uint64_t rw_size = BL31_RW_END - BL31_RW_START; - uint64_t rodata_start = BL31_RODATA_BASE; - uint64_t rodata_size = BL31_RODATA_END - BL31_RODATA_BASE; - uint64_t code_base = TEXT_START; - uint64_t code_size = TEXT_END - TEXT_START; + uint64_t rw_size = BL_END - BL31_RW_START; + uint64_t rodata_start = BL_RO_DATA_BASE; + uint64_t rodata_size = BL_RO_DATA_END - BL_RO_DATA_BASE; + uint64_t code_base = BL_CODE_BASE; + uint64_t code_size = BL_CODE_END - BL_CODE_BASE; const mmap_region_t *plat_mmio_map = NULL; -#if USE_COHERENT_MEM - uint32_t coh_start, coh_size; -#endif const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); /* @@ -412,15 +303,6 @@ void bl31_plat_arch_setup(void) code_size, MT_CODE | MT_SECURE); -#if USE_COHERENT_MEM - coh_start = total_base + (BL_COHERENT_RAM_BASE - BL31_RO_BASE); - coh_size = BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE; - - mmap_add_region(coh_start, coh_start, - coh_size, - (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE); -#endif - /* map TZDRAM used by BL31 as coherent memory */ if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) { mmap_add_region(params_from_bl2->tzdram_base, @@ -449,7 +331,15 @@ void bl31_plat_arch_setup(void) int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes) { uint64_t end = base + size_in_bytes - U(1); - int32_t ret = 0; + + /* + * Sanity check the input values + */ + if ((base == 0U) || (size_in_bytes == 0U)) { + ERROR("NS address 0x%llx (%lld bytes) is invalid\n", + base, size_in_bytes); + return -EINVAL; + } /* * Check if the NS DRAM address is valid @@ -458,7 +348,7 @@ int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes) (end > TEGRA_DRAM_END)) { ERROR("NS address 0x%llx is out-of-bounds!\n", base); - ret = -EFAULT; + return -EFAULT; } /* @@ -467,9 +357,9 @@ int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes) */ if ((base < (uint64_t)TZDRAM_END) && (end > tegra_bl31_phys_base)) { ERROR("NS address 0x%llx overlaps TZDRAM!\n", base); - ret = -ENOTSUP; + return -ENOTSUP; } /* valid NS address */ - return ret; + return 0; } diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index 34b5638ec..37910181c 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -1,37 +1,59 @@ # -# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2020, NVIDIA Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \ -Iplat/nvidia/tegra/include/lib \ - -Iplat/nvidia/tegra/include \ - -Iplat/nvidia/tegra/include/${TARGET_SOC} + -Iplat/nvidia/tegra/include include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} -COMMON_DIR := plat/nvidia/tegra/common +TEGRA_COMMON := plat/nvidia/tegra/common +TEGRA_DRIVERS := plat/nvidia/tegra/drivers +TEGRA_LIBS := plat/nvidia/tegra/lib -TEGRA_GICv2_SOURCES := drivers/arm/gic/common/gic_common.c \ - drivers/arm/gic/v2/gicv2_main.c \ - drivers/arm/gic/v2/gicv2_helpers.c \ +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk +TEGRA_GICv3_SOURCES := $(GICV3_SOURCES) \ + plat/common/plat_gicv3.c \ + ${TEGRA_COMMON}/tegra_gicv3.c + +# Include GICv2 driver files +include drivers/arm/gic/v2/gicv2.mk + +TEGRA_GICv2_SOURCES := ${GICV2_SOURCES} \ plat/common/plat_gicv2.c \ - ${COMMON_DIR}/tegra_gicv2.c + ${TEGRA_COMMON}/tegra_gicv2.c + +TEGRA_GICv3_SOURCES := drivers/arm/gic/common/gic_common.c \ + drivers/arm/gic/v3/arm_gicv3_common.c \ + drivers/arm/gic/v3/gicv3_main.c \ + drivers/arm/gic/v3/gicv3_helpers.c \ + plat/common/plat_gicv3.c \ + ${TEGRA_COMMON}/tegra_gicv3.c BL31_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/io/io_storage.c \ plat/common/aarch64/crash_console_helpers.S \ - ${TEGRA_GICv2_SOURCES} \ - ${COMMON_DIR}/aarch64/tegra_helpers.S \ - ${COMMON_DIR}/drivers/pmc/pmc.c \ - ${COMMON_DIR}/lib/debug/profiler.c \ - ${COMMON_DIR}/tegra_bl31_setup.c \ - ${COMMON_DIR}/tegra_delay_timer.c \ - ${COMMON_DIR}/tegra_fiq_glue.c \ - ${COMMON_DIR}/tegra_io_storage.c \ - ${COMMON_DIR}/tegra_platform.c \ - ${COMMON_DIR}/tegra_pm.c \ - ${COMMON_DIR}/tegra_sip_calls.c \ - ${COMMON_DIR}/tegra_topology.c + ${TEGRA_LIBS}/debug/profiler.c \ + ${TEGRA_COMMON}/aarch64/tegra_helpers.S \ + ${TEGRA_LIBS}/debug/profiler.c \ + ${TEGRA_COMMON}/tegra_bl31_setup.c \ + ${TEGRA_COMMON}/tegra_delay_timer.c \ + ${TEGRA_COMMON}/tegra_fiq_glue.c \ + ${TEGRA_COMMON}/tegra_io_storage.c \ + ${TEGRA_COMMON}/tegra_platform.c \ + ${TEGRA_COMMON}/tegra_pm.c \ + ${TEGRA_COMMON}/tegra_sip_calls.c \ + ${TEGRA_COMMON}/tegra_sdei.c + +ifneq ($(ENABLE_STACK_PROTECTOR), 0) +BL31_SOURCES += ${TEGRA_COMMON}/tegra_stack_protector.c +endif +ifeq (${EL3_EXCEPTION_HANDLING},1) +BL31_SOURCES += plat/common/aarch64/plat_ehf.c +endif diff --git a/plat/nvidia/tegra/common/tegra_delay_timer.c b/plat/nvidia/tegra/common/tegra_delay_timer.c index 63dcf410c..d9547c4a3 100644 --- a/plat/nvidia/tegra/common/tegra_delay_timer.c +++ b/plat/nvidia/tegra/common/tegra_delay_timer.c @@ -1,31 +1,57 @@ /* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#include <arch.h> + #include <drivers/delay_timer.h> #include <lib/mmio.h> +#include <lib/utils_def.h> +#include <plat/common/platform.h> #include <tegra_def.h> #include <tegra_private.h> -static uint32_t tegra_timerus_get_value(void) +static uint32_t tegra_timer_get_value(void) { - return mmio_read_32(TEGRA_TMRUS_BASE); + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + + /* + * Generic delay timer implementation expects the timer to be a down + * counter. The value is clipped from 64 to 32 bits. + */ + return (uint32_t)(read_cntps_tval_el1()); } /* - * Initialise the on-chip free rolling us counter as the delay - * timer. + * Initialise the architecture provided counter as the delay timer. */ void tegra_delay_timer_init(void) { - static const timer_ops_t tegra_timer_ops = { - .get_timer_value = tegra_timerus_get_value, - .clk_mult = 1, - .clk_div = 1, - }; + static timer_ops_t tegra_timer_ops; + + /* Value in ticks */ + uint32_t multiplier = MHZ_TICKS_PER_SEC; + + /* Value in ticks per second (Hz) */ + uint32_t divider = plat_get_syscnt_freq2(); + + /* Reduce multiplier and divider by dividing them repeatedly by 10 */ + while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) { + multiplier /= 10U; + divider /= 10U; + } + + /* enable cntps_tval_el1 timer, mask interrupt */ + write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT); + /* register the timer */ + tegra_timer_ops.get_timer_value = tegra_timer_get_value; + tegra_timer_ops.clk_mult = multiplier; + tegra_timer_ops.clk_div = divider; timer_init(&tegra_timer_ops); } diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c index 60b559556..5309d98cd 100644 --- a/plat/nvidia/tegra/common/tegra_fiq_glue.c +++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -8,11 +9,11 @@ #include <arch_helpers.h> #include <bl31/interrupt_mgmt.h> +#include <bl31/ehf.h> #include <common/bl_common.h> #include <common/debug.h> #include <context.h> #include <denver.h> -#include <lib/bakery_lock.h> #include <lib/el3_runtime/context_mgmt.h> #include <plat/common/platform.h> @@ -25,8 +26,6 @@ /* Legacy FIQ used by earlier Tegra platforms */ #define LEGACY_FIQ_PPI_WDT 28U -static DEFINE_BAKERY_LOCK(tegra_fiq_lock); - /******************************************************************************* * Static variables ******************************************************************************/ @@ -37,29 +36,18 @@ static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; /******************************************************************************* * Handler for FIQ interrupts ******************************************************************************/ -static uint64_t tegra_fiq_interrupt_handler(uint32_t id, - uint32_t flags, - void *handle, - void *cookie) +static int tegra_fiq_interrupt_handler(unsigned int id, unsigned int flags, + void *handle, void *cookie) { cpu_context_t *ctx = cm_get_context(NON_SECURE); el3_state_t *el3state_ctx = get_el3state_ctx(ctx); uint32_t cpu = plat_my_core_pos(); - uint32_t irq; - (void)id; (void)flags; (void)handle; (void)cookie; /* - * Read the pending interrupt ID - */ - irq = plat_ic_get_pending_interrupt_id(); - - bakery_lock_get(&tegra_fiq_lock); - - /* * Jump to NS world only if the NS world's FIQ handler has * been registered */ @@ -94,7 +82,7 @@ static uint64_t tegra_fiq_interrupt_handler(uint32_t id, * disable the routing so that we can mark it as "complete" in the * GIC later. */ - if (irq == LEGACY_FIQ_PPI_WDT) { + if (id == LEGACY_FIQ_PPI_WDT) { tegra_fc_disable_fiq_to_ccplex_routing(); } #endif @@ -102,12 +90,7 @@ static uint64_t tegra_fiq_interrupt_handler(uint32_t id, /* * Mark this interrupt as complete to avoid a FIQ storm. */ - if (irq < 1022U) { - (void)plat_ic_acknowledge_interrupt(); - plat_ic_end_of_interrupt(irq); - } - - bakery_lock_release(&tegra_fiq_lock); + plat_ic_end_of_interrupt(id); return 0; } @@ -117,23 +100,13 @@ static uint64_t tegra_fiq_interrupt_handler(uint32_t id, ******************************************************************************/ void tegra_fiq_handler_setup(void) { - uint32_t flags; - int32_t rc; - /* return if already registered */ if (fiq_handler_active == 0U) { /* * Register an interrupt handler for FIQ interrupts generated for * NS interrupt sources */ - flags = 0U; - set_interrupt_rm_flag((flags), (NON_SECURE)); - rc = register_interrupt_type_handler(INTR_TYPE_EL3, - tegra_fiq_interrupt_handler, - flags); - if (rc != 0) { - panic(); - } + ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler); /* handler is now active */ fiq_handler_active = 1; @@ -155,7 +128,7 @@ int32_t tegra_fiq_get_intr_context(void) { cpu_context_t *ctx = cm_get_context(NON_SECURE); gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); - const el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); + const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx); uint32_t cpu = plat_my_core_pos(); uint64_t val; diff --git a/plat/nvidia/tegra/common/tegra_gicv2.c b/plat/nvidia/tegra/common/tegra_gicv2.c index 293df8d4f..012107e3b 100644 --- a/plat/nvidia/tegra/common/tegra_gicv2.c +++ b/plat/nvidia/tegra/common/tegra_gicv2.c @@ -1,20 +1,23 @@ /* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include <assert.h> - #include <platform_def.h> #include <common/bl_common.h> #include <drivers/arm/gicv2.h> #include <lib/utils.h> +#include <plat/common/platform.h> #include <tegra_private.h> #include <tegra_def.h> +static unsigned int tegra_target_masks[PLATFORM_CORE_COUNT]; + /****************************************************************************** * Tegra common helper to setup the GICv2 driver data. *****************************************************************************/ @@ -33,6 +36,8 @@ void tegra_gic_setup(const interrupt_prop_t *interrupt_props, tegra_gic_data.gicc_base = TEGRA_GICC_BASE; tegra_gic_data.interrupt_props = interrupt_props; tegra_gic_data.interrupt_props_num = interrupt_props_num; + tegra_gic_data.target_masks = tegra_target_masks; + tegra_gic_data.target_masks_num = ARRAY_SIZE(tegra_target_masks); gicv2_driver_init(&tegra_gic_data); } @@ -43,6 +48,7 @@ void tegra_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); + gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } @@ -61,5 +67,6 @@ void tegra_gic_cpuif_deactivate(void) void tegra_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); + gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } diff --git a/plat/nvidia/tegra/common/tegra_gicv3.c b/plat/nvidia/tegra/common/tegra_gicv3.c new file mode 100644 index 000000000..cba2f9b95 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_gicv3.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/bl_common.h> +#include <drivers/arm/gicv3.h> +#include <lib/utils.h> + +#include <plat/common/platform.h> +#include <platform_def.h> +#include <tegra_private.h> +#include <tegra_def.h> + +/* The GICv3 driver only needs to be initialized in EL3 */ +static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static unsigned int plat_tegra_mpidr_to_core_pos(unsigned long mpidr) +{ + return (unsigned int)plat_core_pos_by_mpidr(mpidr); +} + +/****************************************************************************** + * Tegra common helper to setup the GICv3 driver data. + *****************************************************************************/ +void tegra_gic_setup(const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + /* + * Tegra GIC configuration settings + */ + static gicv3_driver_data_t tegra_gic_data; + + /* + * Register Tegra GICv3 driver + */ + tegra_gic_data.gicd_base = TEGRA_GICD_BASE; + tegra_gic_data.gicr_base = TEGRA_GICR_BASE; + tegra_gic_data.rdistif_num = PLATFORM_CORE_COUNT; + tegra_gic_data.rdistif_base_addrs = rdistif_base_addrs; + tegra_gic_data.mpidr_to_core_pos = plat_tegra_mpidr_to_core_pos; + tegra_gic_data.interrupt_props = interrupt_props; + tegra_gic_data.interrupt_props_num = interrupt_props_num; + gicv3_driver_init(&tegra_gic_data); + + /* initialize the GICD and GICR */ + tegra_gic_init(); +} + +/****************************************************************************** + * Tegra common helper to initialize the GICv3 only driver. + *****************************************************************************/ +void tegra_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * Tegra common helper to disable the GICv3 CPU interface + *****************************************************************************/ +void tegra_gic_cpuif_deactivate(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +/****************************************************************************** + * Tegra common helper to initialize the per cpu distributor interface + * in GICv3 + *****************************************************************************/ +void tegra_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} diff --git a/plat/nvidia/tegra/common/tegra_platform.c b/plat/nvidia/tegra/common/tegra_platform.c index c1e420959..d45d9886f 100644 --- a/plat/nvidia/tegra/common/tegra_platform.c +++ b/plat/nvidia/tegra/common/tegra_platform.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,6 +8,8 @@ #include <arch_helpers.h> #include <assert.h> #include <lib/mmio.h> +#include <lib/smccc.h> +#include <services/arm_arch_svc.h> #include <tegra_def.h> #include <tegra_platform.h> #include <tegra_private.h> @@ -105,6 +108,13 @@ bool tegra_chipid_is_t210_b01(void) return (tegra_chipid_is_t210() && (tegra_get_chipid_major() == 0x2U)); } +bool tegra_chipid_is_t194(void) +{ + uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; + + return (chip_id == TEGRA_CHIPID_TEGRA19); +} + /* * Read the chip ID value and derive the platform */ @@ -259,3 +269,47 @@ bool tegra_platform_is_virt_dev_kit(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_VIRT_DEV_KIT) ? true : false); } + +/* + * This function returns soc version which mainly consist of below fields + * + * soc_version[30:24] = JEP-106 continuation code for the SiP + * soc_version[23:16] = JEP-106 identification code with parity bit for the SiP + * soc_version[0:15] = chip identification + */ +int32_t plat_get_soc_version(void) +{ + uint32_t chip_id = ((tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK); + uint32_t manfid = (JEDEC_NVIDIA_BKID << 24) | (JEDEC_NVIDIA_MFID << 16); + + return (int32_t)(manfid | (chip_id & 0xFFFF)); +} + +/* + * This function returns soc revision in below format + * + * soc_revision[8:15] = major version number + * soc_revision[0:7] = minor version number + */ +int32_t plat_get_soc_revision(void) +{ + return (int32_t)((tegra_get_chipid_major() << 8) | tegra_get_chipid_minor()); +} + +/***************************************************************************** + * plat_is_smccc_feature_available() - This function checks whether SMCCC feature + * is availabile for the platform or not. + * @fid: SMCCC function id + * + * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and + * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. + *****************************************************************************/ +int32_t plat_is_smccc_feature_available(u_register_t fid) +{ + switch (fid) { + case SMCCC_ARCH_SOC_ID: + return SMC_ARCH_CALL_SUCCESS; + default: + return SMC_ARCH_CALL_NOT_SUPPORTED; + } +} diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index 39dc42c5b..ec34a850d 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -27,104 +28,13 @@ extern uint64_t tegra_bl31_phys_base; extern uint64_t tegra_sec_entry_point; -/* - * The following platform setup functions are weakly defined. They - * provide typical implementations that will be overridden by a SoC. - */ -#pragma weak tegra_soc_pwr_domain_suspend_pwrdown_early -#pragma weak tegra_soc_cpu_standby -#pragma weak tegra_soc_pwr_domain_suspend -#pragma weak tegra_soc_pwr_domain_on -#pragma weak tegra_soc_pwr_domain_off -#pragma weak tegra_soc_pwr_domain_on_finish -#pragma weak tegra_soc_pwr_domain_power_down_wfi -#pragma weak tegra_soc_prepare_system_reset -#pragma weak tegra_soc_prepare_system_off -#pragma weak tegra_soc_get_target_pwr_state - -int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) -{ - return PSCI_E_NOT_SUPPORTED; -} - -int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state) -{ - (void)cpu_state; - return PSCI_E_SUCCESS; -} - -int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) -{ - (void)target_state; - return PSCI_E_NOT_SUPPORTED; -} - -int32_t tegra_soc_pwr_domain_on(u_register_t mpidr) -{ - (void)mpidr; - return PSCI_E_SUCCESS; -} - -int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) -{ - (void)target_state; - return PSCI_E_SUCCESS; -} - -int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) -{ - (void)target_state; - return PSCI_E_SUCCESS; -} - -int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) -{ - (void)target_state; - return PSCI_E_SUCCESS; -} - -int32_t tegra_soc_prepare_system_reset(void) -{ - return PSCI_E_SUCCESS; -} - -__dead2 void tegra_soc_prepare_system_off(void) -{ - ERROR("Tegra System Off: operation not handled.\n"); - panic(); -} - -plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl, - const plat_local_state_t *states, - uint32_t ncpu) -{ - plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; - uint32_t num_cpu = ncpu; - const plat_local_state_t *local_state = states; - - (void)lvl; - - assert(ncpu != 0U); - - do { - temp = *local_state; - if ((temp < target)) { - target = temp; - } - --num_cpu; - local_state++; - } while (num_cpu != 0U); - - return target; -} - /******************************************************************************* * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` * call to get the `power_state` parameter. This allows the platform to encode * the appropriate State-ID field within the `power_state` parameter which can * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. ******************************************************************************/ -void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) +static void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { /* all affinities use system suspend state id */ for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) { @@ -135,7 +45,7 @@ void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) /******************************************************************************* * Handler called when an affinity instance is about to enter standby. ******************************************************************************/ -void tegra_cpu_standby(plat_local_state_t cpu_state) +static void tegra_cpu_standby(plat_local_state_t cpu_state) { u_register_t saved_scr_el3; @@ -174,7 +84,7 @@ void tegra_cpu_standby(plat_local_state_t cpu_state) * Handler called when an affinity instance is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ -int32_t tegra_pwr_domain_on(u_register_t mpidr) +static int32_t tegra_pwr_domain_on(u_register_t mpidr) { return tegra_soc_pwr_domain_on(mpidr); } @@ -183,9 +93,12 @@ int32_t tegra_pwr_domain_on(u_register_t mpidr) * Handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_pwr_domain_off(const psci_power_state_t *target_state) +static void tegra_pwr_domain_off(const psci_power_state_t *target_state) { (void)tegra_soc_pwr_domain_off(target_state); + + /* disable GICC */ + tegra_gic_cpuif_deactivate(); } /******************************************************************************* @@ -203,17 +116,10 @@ void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_sta * Handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) +static void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) { (void)tegra_soc_pwr_domain_suspend(target_state); - /* Disable console if we are entering deep sleep. */ - if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == - PSTATE_ID_SOC_POWERDN) { - (void)console_flush(); - console_switch_state(0); - } - /* disable GICC */ tegra_gic_cpuif_deactivate(); } @@ -222,12 +128,20 @@ void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) * Handler called at the end of the power domain suspend sequence. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ -__dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t +static __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { /* call the chip's power down handler */ (void)tegra_soc_pwr_domain_power_down_wfi(target_state); + /* Disable console if we are entering deep sleep. */ + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PSTATE_ID_SOC_POWERDN) { + INFO("%s: complete. Entering System Suspend...\n", __func__); + console_flush(); + console_switch_state(0); + } + wfi(); panic(); } @@ -237,21 +151,23 @@ __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ -void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) +static void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) { const plat_params_from_bl2_t *plat_params; /* - * Initialize the GIC cpu and distributor interfaces - */ - tegra_gic_pcpu_init(); - - /* * Check if we are exiting from deep sleep. */ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == PSTATE_ID_SOC_POWERDN) { + /* + * On entering System Suspend state, the GIC loses power + * completely. Initialize the GIC global distributor and + * GIC cpu interfaces. + */ + tegra_gic_init(); + /* Restart console output. */ console_switch_state(CONSOLE_FLAG_RUNTIME); @@ -268,11 +184,11 @@ void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) tegra_memctrl_tzdram_setup(plat_params->tzdram_base, (uint32_t)plat_params->tzdram_size); + } else { /* - * Set up the TZRAM memory aperture to allow only secure world - * access + * Initialize the GIC cpu and distributor interfaces */ - tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); + tegra_gic_pcpu_init(); } /* @@ -286,7 +202,7 @@ void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. ******************************************************************************/ -void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) +static void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { tegra_pwr_domain_on_finish(target_state); } @@ -294,7 +210,7 @@ void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) /******************************************************************************* * Handler called when the system wants to be powered off ******************************************************************************/ -__dead2 void tegra_system_off(void) +static __dead2 void tegra_system_off(void) { INFO("Powering down system...\n"); @@ -304,23 +220,23 @@ __dead2 void tegra_system_off(void) /******************************************************************************* * Handler called when the system wants to be restarted. ******************************************************************************/ -__dead2 void tegra_system_reset(void) +static __dead2 void tegra_system_reset(void) { INFO("Restarting system...\n"); /* per-SoC system reset handler */ (void)tegra_soc_prepare_system_reset(); - /* - * Program the PMC in order to restart the system. - */ - tegra_pmc_system_reset(); + /* wait for the system to reset */ + for (;;) { + ; + } } /******************************************************************************* * Handler called to check the validity of the power state parameter. ******************************************************************************/ -int32_t tegra_validate_power_state(uint32_t power_state, +static int32_t tegra_validate_power_state(uint32_t power_state, psci_power_state_t *req_state) { assert(req_state != NULL); @@ -331,7 +247,7 @@ int32_t tegra_validate_power_state(uint32_t power_state, /******************************************************************************* * Platform handler called to check the validity of the non secure entrypoint. ******************************************************************************/ -int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) +static int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) { int32_t ret = PSCI_E_INVALID_ADDRESS; @@ -349,7 +265,7 @@ int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) /******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ -static const plat_psci_ops_t tegra_plat_psci_ops = { +static plat_psci_ops_t tegra_plat_psci_ops = { .cpu_standby = tegra_cpu_standby, .pwr_domain_on = tegra_pwr_domain_on, .pwr_domain_off = tegra_pwr_domain_off, @@ -386,6 +302,14 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, (void)tegra_soc_pwr_domain_on_finish(&target_state); /* + * Disable System Suspend if the platform does not + * support it + */ + if (!plat_supports_system_suspend()) { + tegra_plat_psci_ops.get_sys_suspend_power_state = NULL; + } + + /* * Initialize PSCI ops struct */ *psci_ops = &tegra_plat_psci_ops; diff --git a/plat/nvidia/tegra/common/tegra_sdei.c b/plat/nvidia/tegra/common/tegra_sdei.c new file mode 100644 index 000000000..9241b8172 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_sdei.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* SDEI configuration for Tegra platforms */ + +#include <platform_def.h> + +#include <bl31/ehf.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <lib/utils_def.h> +#include <services/sdei.h> + +/* Private event mappings */ +static sdei_ev_map_t tegra_sdei_private[] = { + /* Event 0 definition */ + SDEI_DEFINE_EVENT_0(TEGRA_SDEI_SGI_PRIVATE), + + /* Dynamic private events */ + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + + /* General purpose explicit events */ + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_0, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_1, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_2, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_3, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_4, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_5, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_6, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_7, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_8, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_9, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_10, SDEI_MAPF_CRITICAL), + SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_11, SDEI_MAPF_CRITICAL) +}; + +/* Shared event mappings */ +static sdei_ev_map_t tegra_sdei_shared[] = { + /* Dynamic shared events */ + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), + SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) +}; + +void plat_sdei_setup(void) +{ + INFO("SDEI platform setup\n"); +} + +/* Export Tegra SDEI events */ +REGISTER_SDEI_MAP(tegra_sdei_private, tegra_sdei_shared); diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c index b8ba09562..80a2c4d0c 100644 --- a/plat/nvidia/tegra/common/tegra_sip_calls.c +++ b/plat/nvidia/tegra/common/tegra_sip_calls.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -26,32 +27,6 @@ #define TEGRA_SIP_FIQ_NS_GET_CONTEXT 0x82000006 /******************************************************************************* - * SoC specific SiP handler - ******************************************************************************/ -#pragma weak plat_sip_handler -int32_t plat_sip_handler(uint32_t smc_fid, - uint64_t x1, - uint64_t x2, - uint64_t x3, - uint64_t x4, - const void *cookie, - void *handle, - uint64_t flags) -{ - /* unused parameters */ - (void)smc_fid; - (void)x1; - (void)x2; - (void)x3; - (void)x4; - (void)cookie; - (void)handle; - (void)flags; - - return -ENOTSUP; -} - -/******************************************************************************* * This function is responsible for handling all SiP calls ******************************************************************************/ uintptr_t tegra_sip_handler(uint32_t smc_fid, @@ -77,6 +52,12 @@ uintptr_t tegra_sip_handler(uint32_t smc_fid, switch (smc_fid) { case TEGRA_SIP_NEW_VIDEOMEM_REGION: + /* Check whether Video memory resize is enabled */ + if (mmio_read_32(TEGRA_MC_BASE + MC_VIDEO_PROTECT_REG_CTRL) + != MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED) { + ERROR("Video Memory Resize isn't enabled! \n"); + SMC_RET1(handle, (uint64_t)-ENOTSUP); + } /* * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) diff --git a/plat/nvidia/tegra/common/tegra_stack_protector.c b/plat/nvidia/tegra/common/tegra_stack_protector.c new file mode 100644 index 000000000..f6c459a8e --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_stack_protector.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <arch_helpers.h> +#include <lib/mmio.h> +#include <plat/common/platform.h> +#include <platform_def.h> + +u_register_t plat_get_stack_protector_canary(void) +{ + u_register_t seed; + + /* + * Ideally, a random number should be returned instead. As the + * platform does not have any random number generator, this is + * better than nothing, but not really secure. + */ + seed = mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET); + seed <<= 32; + seed |= mmio_read_32(TEGRA_TMRUS_BASE); + + return seed ^ read_cntpct_el0(); +} diff --git a/plat/nvidia/tegra/common/tegra_topology.c b/plat/nvidia/tegra/common/tegra_topology.c deleted file mode 100644 index 205b05165..000000000 --- a/plat/nvidia/tegra/common/tegra_topology.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include <platform_def.h> - -#include <arch.h> -#include <lib/psci/psci.h> -#include <plat/common/platform.h> - -#pragma weak plat_core_pos_by_mpidr - -/******************************************************************************* - * This function implements a part of the critical interface between the psci - * generic layer and the platform that allows the former to query the platform - * to convert an MPIDR to a unique linear index. An error code (-1) is returned - * in case the MPIDR is invalid. - ******************************************************************************/ -int32_t plat_core_pos_by_mpidr(u_register_t mpidr) -{ - u_register_t cluster_id, cpu_id; - int32_t result; - - cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & - (u_register_t)MPIDR_AFFLVL_MASK; - cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & - (u_register_t)MPIDR_AFFLVL_MASK; - - /* CorePos = CoreId + (ClusterId * cpus per cluster) */ - result = (int32_t)cpu_id + ((int32_t)cluster_id * - PLATFORM_MAX_CPUS_PER_CLUSTER); - - if (cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) { - result = PSCI_E_NOT_PRESENT; - } - - /* - * Validate cpu_id by checking whether it represents a CPU in - * one of the two clusters present on the platform. - */ - if (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER) { - result = PSCI_E_NOT_PRESENT; - } - - return result; -} |