304 lines
7.2 KiB
C
304 lines
7.2 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||
/*
|
||
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
||
*/
|
||
|
||
/*
|
||
* Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
|
||
*
|
||
* All information contained herein is Amlogic confidential.
|
||
*
|
||
* This software is provided to you pursuant to Software License Agreement
|
||
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
|
||
* only in accordance with the terms of this agreement.
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification is strictly prohibited without prior written permission from
|
||
* Amlogic.
|
||
*
|
||
* 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
|
||
* OWNER 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 <mmu.h>
|
||
#include <cache_v8.h>
|
||
#include <serial.h>
|
||
#include <io.h>
|
||
#include "ram_compress.h"
|
||
#include "platform_def.h"
|
||
#include "regs.h"
|
||
|
||
/* Asm functions from cache_v7_asm.S */
|
||
void v7_flush_dcache_all(void);
|
||
void v7_invalidate_dcache_all(void);
|
||
|
||
u32 bl2e_ttbr0 = 0, bl2e_dacr = 0, bl2e_sctlr = 0;
|
||
|
||
//porting from arch/arm/lib/cache-cp15.c
|
||
static inline unsigned int get_cr(void)
|
||
{
|
||
unsigned int val;
|
||
|
||
asm volatile("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val)
|
||
:
|
||
: "cc");
|
||
return val;
|
||
}
|
||
|
||
static inline void set_cr(unsigned int val)
|
||
{
|
||
asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" :
|
||
: "r" (val)
|
||
: "cc");
|
||
asm volatile("isb");
|
||
}
|
||
|
||
u32 __asm_get_sctlr(void)
|
||
{
|
||
return get_cr();
|
||
}
|
||
|
||
void __asm_set_sctlr(u32 val)
|
||
{
|
||
set_cr(val);
|
||
}
|
||
|
||
//porting from arch/arm/cpu/armv7/cache_v7.c
|
||
/* Invalidate entire I-cache and branch predictor array */
|
||
void invalidate_icache_all(void)
|
||
{
|
||
/*
|
||
* Invalidate all instruction caches to PoU.
|
||
* Also flushes branch target cache.
|
||
*/
|
||
asm volatile ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
|
||
|
||
/* Invalidate entire branch predictor array */
|
||
asm volatile ("mcr p15, 0, %0, c7, c5, 6" : : "r" (0));
|
||
|
||
/* Full system DSB - make sure that the invalidation is complete */
|
||
asm volatile("dsb");
|
||
|
||
/* ISB - make sure the instruction stream sees it */
|
||
asm volatile("isb");
|
||
}
|
||
|
||
/* Invalidate TLB */
|
||
static void invalidate_tlb_all(void)
|
||
{
|
||
/* Invalidate entire unified TLB */
|
||
asm volatile ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0));
|
||
/* Invalidate entire data TLB */
|
||
asm volatile ("mcr p15, 0, %0, c8, c6, 0" : : "r" (0));
|
||
/* Invalidate entire instruction TLB */
|
||
asm volatile ("mcr p15, 0, %0, c8, c5, 0" : : "r" (0));
|
||
/* Full system DSB - make sure that the invalidation is complete */
|
||
asm volatile("dsb");
|
||
/* Full system ISB - make sure the instruction stream sees it */
|
||
asm volatile("isb");
|
||
}
|
||
|
||
void get_bl2e_mmu_state(void)
|
||
{
|
||
bl2e_ttbr0 = __asm_get_ttbr0();
|
||
bl2e_dacr = __asm_get_dacr();
|
||
bl2e_sctlr = get_cr();
|
||
|
||
serial_puts("Get bl2e mmu table. ttbr0_EL2:0x");
|
||
serial_put_hex(bl2e_ttbr0, 32);
|
||
serial_puts(", dacr_EL2:0x");
|
||
serial_put_hex(bl2e_dacr, 32);
|
||
serial_puts(", sctlr_EL2:0x");
|
||
serial_put_hex(bl2e_sctlr, 32);
|
||
serial_puts("\n");
|
||
}
|
||
|
||
void set_bl2e_mmu_state(void)
|
||
{
|
||
__asm_set_ttbr0(bl2e_ttbr0);
|
||
__asm_set_dacr(bl2e_dacr);
|
||
set_cr(bl2e_sctlr);
|
||
serial_puts("Overwrite bl2e mmu table for bl33 board_f.");
|
||
}
|
||
|
||
void set_pgtable_section(u32 *pgtable, u32 index, u32 phys, u32 flags)
|
||
{
|
||
u32 desc;
|
||
|
||
desc = (phys & 0xFFF00000) // section base
|
||
| (2 << 0) // bit[1:0] = 10 → section
|
||
| (1 << 10) // AP[2] (full access)
|
||
| (3 << 10); // AP[1:0] = 11 (RW)
|
||
|
||
desc |= flags; // TEX/C/B 等
|
||
|
||
pgtable[index] = desc;
|
||
}
|
||
|
||
/*
|
||
* Section Mapping (1MB) + Identity Mapping
|
||
* VA == PA, using ARMv7 first-level section descriptors.
|
||
*
|
||
* Each entry maps one 1MB region:
|
||
* section[i] -> physical base (i << 20)
|
||
*
|
||
* 4GB is initially mapped as Device memory,
|
||
* then DDR is overwritten as Normal cacheable memory.
|
||
*/
|
||
void mmu_setup(unsigned long ddr_size)
|
||
{
|
||
u32 *page_table = (u32 *)CONFIG_AML_MMU_ADDR;
|
||
u32 i, reg;
|
||
unsigned long nTotal;
|
||
|
||
/* 1. clean pagetable */
|
||
for (i = 0; i < PAGE_ENTRIES; i++) {
|
||
page_table[i] = 0;
|
||
}
|
||
|
||
/* 2. aarch32 full ddr is 4GB: DEVICE ( avoid MMIO crash) */
|
||
for (i = 0; i < PAGE_ENTRIES; i++) {
|
||
page_table[i] =
|
||
(i << SECTION_SHIFT) |
|
||
PMD_TYPE_SECT |
|
||
PMD_SECT_AF |
|
||
MT_DEVICE;
|
||
}
|
||
|
||
/* 3. DDR 0~512MB change to NORMAL memory */
|
||
nTotal = readl(REG_MDUMP_CPUBOOT_STATUS) & (AMLOGIC_USERAM_MASK & ~RAMDUMP_STICKY_DMA_MASK);
|
||
nTotal = ((nTotal - 1) / 64 + 1) * 64; /* ddr size must big than 64MB */
|
||
nTotal = nTotal ? nTotal : (ddr_size >> 20);
|
||
serial_puts("mmu: DDR size is ");
|
||
serial_put_dec(nTotal);
|
||
serial_puts("MB\n");
|
||
for (i = 0; i < (nTotal / SECTION_SIZE_MB); i++) {
|
||
page_table[i] =
|
||
(i << SECTION_SHIFT) |
|
||
PMD_TYPE_SECT |
|
||
PMD_SECT_AF |
|
||
MT_NORMAL;
|
||
}
|
||
|
||
/* 4. TTBCR = 0 (disable LPAE / full TTBR0 space) */
|
||
asm volatile("mcr p15, 0, %0, c2, c0, 2"
|
||
: : "r"(0) : "memory");
|
||
|
||
/* 5. TTBR0 */
|
||
reg = (u32)page_table;
|
||
/* cache policy(WB/WA) */
|
||
reg &= TTBR0_BASE_ADDR_MASK;
|
||
reg |= TTBR0_RGN_WB;
|
||
reg |= TTBR0_IRGN_WB;
|
||
|
||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||
: : "r"(reg) : "memory");
|
||
|
||
/* 6. DACR = all domains client */
|
||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||
: : "r"(0x55555555));
|
||
asm volatile("dsb");
|
||
asm volatile("isb");
|
||
|
||
/* 7. ENABLE MMU */
|
||
reg = get_cr();
|
||
reg |= (1 << 0); // M bit
|
||
asm volatile("mcr p15, 0, %0, c1, c0, 0"
|
||
: : "r"(reg) : "memory");
|
||
asm volatile("dsb");
|
||
asm volatile("isb");
|
||
|
||
serial_puts("mmu: enabled OK\n");
|
||
}
|
||
|
||
void enable_dcache(unsigned long ddr_size)
|
||
{
|
||
uint32_t reg;
|
||
|
||
/* already enabled */
|
||
if (get_cr() & CR_C)
|
||
return;
|
||
|
||
/*
|
||
* D-cache requires MMU enabled first.
|
||
* Build 1MB section identity mapping if MMU is still off.
|
||
*/
|
||
if (!(get_cr() & CR_M)) {
|
||
/*
|
||
* Optional but recommended:
|
||
* invalidate TLB before installing new translation base
|
||
*/
|
||
invalidate_tlb_all();
|
||
|
||
/*
|
||
* Setup TTBR0 / DACR / enable CR_M
|
||
*/
|
||
mmu_setup(ddr_size);
|
||
}
|
||
|
||
reg = get_cr();
|
||
reg |= CR_C;
|
||
set_cr(reg);
|
||
}
|
||
|
||
void enable_icache(void)
|
||
{
|
||
uint32_t reg;
|
||
|
||
invalidate_icache_all();
|
||
|
||
reg = get_cr();
|
||
set_cr(reg | CR_I);
|
||
}
|
||
|
||
void disable_dcache(void)
|
||
{
|
||
uint32_t reg;
|
||
|
||
reg = get_cr();
|
||
if (!(reg & CR_C))
|
||
return;
|
||
set_cr(reg & ~(CR_C | CR_M));
|
||
|
||
v7_flush_dcache_all();
|
||
invalidate_tlb_all();
|
||
}
|
||
|
||
void disable_icache(void)
|
||
{
|
||
uint32_t reg;
|
||
|
||
/* 1. Invalidate I-cache first */
|
||
invalidate_icache_all();
|
||
|
||
/* 2. Disable I-cache */
|
||
reg = get_cr();
|
||
reg &= ~CR_I;
|
||
set_cr(reg);
|
||
|
||
/* 3. Ensure new state takes effect */
|
||
asm volatile("isb");
|
||
}
|
||
|
||
// C4_aarch32 porting from uboot/v2025/arch/arm/lib/cache-cp15.c
|
||
void enable_caches(unsigned long ddr_size)
|
||
{
|
||
enable_icache();
|
||
enable_dcache(ddr_size);
|
||
}
|
||
|
||
void disable_caches(void)
|
||
{
|
||
disable_icache();
|
||
disable_dcache();
|
||
}
|