/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of ARM nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #define TEGRA_GPU_RESET_REG_OFFSET 0x28c #define GPU_RESET_BIT (1 << 24) /* 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) { /* * Perform cache maintenance to ensure that the non-overlapping area is * zeroed out. The first invalidation of this range ensures that * possible evictions of dirty cache lines do not interfere with the * 'zeromem' operation. Other CPUs could speculatively prefetch the * main memory contents of this area between the first invalidation and * the 'zeromem' operation. The second invalidation ensures that any * such cache lines are removed as well. */ inv_dcache_range(non_overlap_area_start, non_overlap_area_size); zeromem((void *)non_overlap_area_start, non_overlap_area_size); inv_dcache_range(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; uint32_t regval; unsigned long long non_overlap_area_size; /* * The GPU is the user of the Video Memory region. In order to * transition to the new memory region smoothly, we program the * new base/size ONLY if the GPU is in reset mode. */ regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET); if ((regval & GPU_RESET_BIT) == 0) { ERROR("GPU not in reset! Video Memory setup failed\n"); return; } /* * 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"); disable_mmu_el3(); 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); } } enable_mmu_el3(0); 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; }