Tegra: memctrl_v2: fixup sequence to resize video memory

The previous sequence used by the driver to program the new memory
aperture settings and clear the non-overlapping memory was faulty.
The sequence locked the non-overlapping regions twice, leading to
faults when trying to clear it.

This patch modifies the sequence to follow these steps:

* move the previous memory region to a new firewall register
* program the new memory aperture settings
* clean the non-overlapping memory

This patch also maps the non-overlapping memory as Device memory to
follow guidance from the arch. team.

Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
Change-Id: I7cf6e05b2dd372103dc7229e37b1b3fc269a57ae
This commit is contained in:
Varun Wadekar 2020-06-02 21:08:38 -07:00
parent 9935047b20
commit a7749acc10
1 changed files with 46 additions and 43 deletions

View File

@ -280,56 +280,32 @@ static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
{
int ret;
INFO("Cleaning previous Video Memory Carveout\n");
/*
* 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 |
MT_NON_CACHEABLE); /* attrs */
MT_DEVICE | MT_RW | MT_NS); /* attrs */
assert(ret == 0);
zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size);
zeromem((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,
ret = mmap_remove_dynamic_region(non_overlap_area_start,
non_overlap_area_size);
assert(ret == 0);
}
/*
* 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)
static void tegra_clear_videomem_nonoverlap(uintptr_t phys_base,
unsigned long 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 -
@ -338,8 +314,6 @@ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
* 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);
@ -353,26 +327,55 @@ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
tegra_clear_videomem(vmem_end_new, 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)
{
/*
* Setup the Memory controller to restrict CPU accesses to the Video
* Memory region
*/
INFO("Configuring Video Memory Carveout\n");
if (video_mem_base != 0U) {
/*
* 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);
}
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();
(void)mce_update_gsc_videomem();
/* Clear the non-overlapping memory */
if (video_mem_base != 0U) {
tegra_clear_videomem_nonoverlap(phys_base, size_in_bytes);
tegra_unlock_videomem_nonoverlap();
}
/* store new values */
video_mem_base = phys_base;
video_mem_size_mb = (uint64_t)size_in_bytes >> 20;
}
/*