arm-trusted-firmware/plat/nvidia/tegra/drivers/memctrl/memctrl_v1.c

213 lines
6.5 KiB
C
Raw Normal View History

/*
Tegra: memctrl: map video memory as uncached Memmap video memory as uncached normal memory by adding flag 'MT_NON_CACHEABLE' in mmap_add_dynamic_region(). This improves the time taken for clearing the non-overlapping video memory: test conditions: 32MB memory size, EMC running at 1866MHz, t186 1) without MT_NON_CACHEABLE: 30ms ~ 40ms <3>[ 133.852885] vpr-heap: update vpr base to 0x00000000c6000000, size=e000000 <3>[ 133.860471] _tegra_set_vpr_params[120]: begin <3>[ 133.896481] _tegra_set_vpr_params[123]: end <3>[ 133.908944] vpr-heap: update vpr base to 0x00000000c6000000, size=c000000 <3>[ 133.916397] _tegra_set_vpr_params[120]: begin <3>[ 133.956369] _tegra_set_vpr_params[123]: end <3>[ 133.970394] vpr-heap: update vpr base to 0x00000000c6000000, size=a000000 <3>[ 133.977934] _tegra_set_vpr_params[120]: begin <3>[ 134.013874] _tegra_set_vpr_params[123]: end <3>[ 134.025666] vpr-heap: update vpr base to 0x00000000c6000000, size=8000000 <3>[ 134.033512] _tegra_set_vpr_params[120]: begin <3>[ 134.065996] _tegra_set_vpr_params[123]: end <3>[ 134.075465] vpr-heap: update vpr base to 0x00000000c6000000, size=6000000 <3>[ 134.082923] _tegra_set_vpr_params[120]: begin <3>[ 134.113119] _tegra_set_vpr_params[123]: end <3>[ 134.123448] vpr-heap: update vpr base to 0x00000000c6000000, size=4000000 <3>[ 134.130790] _tegra_set_vpr_params[120]: begin <3>[ 134.162523] _tegra_set_vpr_params[123]: end <3>[ 134.172413] vpr-heap: update vpr base to 0x00000000c6000000, size=2000000 <3>[ 134.179772] _tegra_set_vpr_params[120]: begin <3>[ 134.209142] _tegra_set_vpr_params[123]: end 2) with MT_NON_CACHEABLE: 10ms ~ 18ms <3>[ 102.108702] vpr-heap: update vpr base to 0x00000000c6000000, size=e000000 <3>[ 102.116296] _tegra_set_vpr_params[120]: begin <3>[ 102.134272] _tegra_set_vpr_params[123]: end <3>[ 102.145839] vpr-heap: update vpr base to 0x00000000c6000000, size=c000000 <3>[ 102.153226] _tegra_set_vpr_params[120]: begin <3>[ 102.164201] _tegra_set_vpr_params[123]: end <3>[ 102.172275] vpr-heap: update vpr base to 0x00000000c6000000, size=a000000 <3>[ 102.179638] _tegra_set_vpr_params[120]: begin <3>[ 102.190342] _tegra_set_vpr_params[123]: end <3>[ 102.197524] vpr-heap: update vpr base to 0x00000000c6000000, size=8000000 <3>[ 102.205085] _tegra_set_vpr_params[120]: begin <3>[ 102.216112] _tegra_set_vpr_params[123]: end <3>[ 102.224080] vpr-heap: update vpr base to 0x00000000c6000000, size=6000000 <3>[ 102.231387] _tegra_set_vpr_params[120]: begin <3>[ 102.241775] _tegra_set_vpr_params[123]: end <3>[ 102.248825] vpr-heap: update vpr base to 0x00000000c6000000, size=4000000 <3>[ 102.256069] _tegra_set_vpr_params[120]: begin <3>[ 102.266368] _tegra_set_vpr_params[123]: end <3>[ 102.273400] vpr-heap: update vpr base to 0x00000000c6000000, size=2000000 <3>[ 102.280672] _tegra_set_vpr_params[120]: begin <3>[ 102.290929] _tegra_set_vpr_params[123]: end Change-Id: I5f604064ce7b8b73ea9ad5860156ae5e2c6cc42a Signed-off-by: Ken Chang <kenc@nvidia.com>
2018-12-28 00:44:12 +00:00
* 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 <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);
}
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 */
Tegra: memctrl: map video memory as uncached Memmap video memory as uncached normal memory by adding flag 'MT_NON_CACHEABLE' in mmap_add_dynamic_region(). This improves the time taken for clearing the non-overlapping video memory: test conditions: 32MB memory size, EMC running at 1866MHz, t186 1) without MT_NON_CACHEABLE: 30ms ~ 40ms <3>[ 133.852885] vpr-heap: update vpr base to 0x00000000c6000000, size=e000000 <3>[ 133.860471] _tegra_set_vpr_params[120]: begin <3>[ 133.896481] _tegra_set_vpr_params[123]: end <3>[ 133.908944] vpr-heap: update vpr base to 0x00000000c6000000, size=c000000 <3>[ 133.916397] _tegra_set_vpr_params[120]: begin <3>[ 133.956369] _tegra_set_vpr_params[123]: end <3>[ 133.970394] vpr-heap: update vpr base to 0x00000000c6000000, size=a000000 <3>[ 133.977934] _tegra_set_vpr_params[120]: begin <3>[ 134.013874] _tegra_set_vpr_params[123]: end <3>[ 134.025666] vpr-heap: update vpr base to 0x00000000c6000000, size=8000000 <3>[ 134.033512] _tegra_set_vpr_params[120]: begin <3>[ 134.065996] _tegra_set_vpr_params[123]: end <3>[ 134.075465] vpr-heap: update vpr base to 0x00000000c6000000, size=6000000 <3>[ 134.082923] _tegra_set_vpr_params[120]: begin <3>[ 134.113119] _tegra_set_vpr_params[123]: end <3>[ 134.123448] vpr-heap: update vpr base to 0x00000000c6000000, size=4000000 <3>[ 134.130790] _tegra_set_vpr_params[120]: begin <3>[ 134.162523] _tegra_set_vpr_params[123]: end <3>[ 134.172413] vpr-heap: update vpr base to 0x00000000c6000000, size=2000000 <3>[ 134.179772] _tegra_set_vpr_params[120]: begin <3>[ 134.209142] _tegra_set_vpr_params[123]: end 2) with MT_NON_CACHEABLE: 10ms ~ 18ms <3>[ 102.108702] vpr-heap: update vpr base to 0x00000000c6000000, size=e000000 <3>[ 102.116296] _tegra_set_vpr_params[120]: begin <3>[ 102.134272] _tegra_set_vpr_params[123]: end <3>[ 102.145839] vpr-heap: update vpr base to 0x00000000c6000000, size=c000000 <3>[ 102.153226] _tegra_set_vpr_params[120]: begin <3>[ 102.164201] _tegra_set_vpr_params[123]: end <3>[ 102.172275] vpr-heap: update vpr base to 0x00000000c6000000, size=a000000 <3>[ 102.179638] _tegra_set_vpr_params[120]: begin <3>[ 102.190342] _tegra_set_vpr_params[123]: end <3>[ 102.197524] vpr-heap: update vpr base to 0x00000000c6000000, size=8000000 <3>[ 102.205085] _tegra_set_vpr_params[120]: begin <3>[ 102.216112] _tegra_set_vpr_params[123]: end <3>[ 102.224080] vpr-heap: update vpr base to 0x00000000c6000000, size=6000000 <3>[ 102.231387] _tegra_set_vpr_params[120]: begin <3>[ 102.241775] _tegra_set_vpr_params[123]: end <3>[ 102.248825] vpr-heap: update vpr base to 0x00000000c6000000, size=4000000 <3>[ 102.256069] _tegra_set_vpr_params[120]: begin <3>[ 102.266368] _tegra_set_vpr_params[123]: end <3>[ 102.273400] vpr-heap: update vpr base to 0x00000000c6000000, size=2000000 <3>[ 102.280672] _tegra_set_vpr_params[120]: begin <3>[ 102.290929] _tegra_set_vpr_params[123]: end Change-Id: I5f604064ce7b8b73ea9ad5860156ae5e2c6cc42a Signed-off-by: Ken Chang <kenc@nvidia.com>
2018-12-28 00:44:12 +00:00
MT_NS | MT_RW | MT_EXECUTE_NEVER |
MT_NON_CACHEABLE); /* attrs */
assert(ret == 0);
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
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);
}
}