mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-14 08:57:58 +00:00
arm: Add control over cachability of memory regions
Add support for adjusting the L1 cache behavior by updating the MMU configuration. The mmu_set_region_dcache_behaviour() function allows drivers to make these changes after the MMU is set up. It is implemented only for ARMv7 at present. This is needed for LCD support, where we want to make the LCD frame buffer write-through (or off) rather than write-back. Signed-off-by: Simon Glass <sjg@chromium.org> Signed-off-by: Tom Warren <twarren@nvidia.com>
This commit is contained in:
parent
1b24a50b44
commit
0dde7f5379
3 changed files with 82 additions and 11 deletions
|
@ -297,6 +297,12 @@ void arm_init_before_mmu(void)
|
||||||
v7_inval_tlb();
|
v7_inval_tlb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||||
|
{
|
||||||
|
flush_dcache_range(start, stop);
|
||||||
|
v7_inval_tlb();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush range from all levels of d-cache/unified-cache used:
|
* Flush range from all levels of d-cache/unified-cache used:
|
||||||
* Affects the range [start, start + size - 1]
|
* Affects the range [start, start + size - 1]
|
||||||
|
@ -329,6 +335,11 @@ void arm_init_before_mmu(void)
|
||||||
void flush_cache(unsigned long start, unsigned long size)
|
void flush_cache(unsigned long start, unsigned long size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
|
||||||
|
|
||||||
#ifndef CONFIG_SYS_ICACHE_OFF
|
#ifndef CONFIG_SYS_ICACHE_OFF
|
||||||
|
|
|
@ -75,6 +75,37 @@ static inline void set_cr(unsigned int val)
|
||||||
isb();
|
isb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* options available for data cache on each page */
|
||||||
|
enum dcache_option {
|
||||||
|
DCACHE_OFF = 0x12,
|
||||||
|
DCACHE_WRITETHROUGH = 0x1a,
|
||||||
|
DCACHE_WRITEBACK = 0x1e,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Size of an MMU section */
|
||||||
|
enum {
|
||||||
|
MMU_SECTION_SHIFT = 20,
|
||||||
|
MMU_SECTION_SIZE = 1 << MMU_SECTION_SHIFT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the cache settings for a region.
|
||||||
|
*
|
||||||
|
* \param start start address of memory region to change
|
||||||
|
* \param size size of memory region to change
|
||||||
|
* \param option dcache option to select
|
||||||
|
*/
|
||||||
|
void mmu_set_region_dcache_behaviour(u32 start, int size,
|
||||||
|
enum dcache_option option);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register an update to the page tables, and flush the TLB
|
||||||
|
*
|
||||||
|
* \param start start address of update in page table
|
||||||
|
* \param stop stop address of update in page table
|
||||||
|
*/
|
||||||
|
void mmu_page_table_flush(unsigned long start, unsigned long stop);
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
#define arch_align_stack(x) (x)
|
#define arch_align_stack(x) (x)
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
|
|
||||||
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
|
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
|
||||||
|
|
||||||
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
|
||||||
#define CACHE_SETUP 0x1a
|
|
||||||
#else
|
|
||||||
#define CACHE_SETUP 0x1e
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
void __arm_init_before_mmu(void)
|
void __arm_init_before_mmu(void)
|
||||||
|
@ -50,9 +44,41 @@ static void cp_delay (void)
|
||||||
asm volatile("" : : : "memory");
|
asm volatile("" : : : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dram_bank_mmu_setup(int bank)
|
void set_section_dcache(int section, enum dcache_option option)
|
||||||
{
|
{
|
||||||
u32 *page_table = (u32 *)gd->tlb_addr;
|
u32 *page_table = (u32 *)gd->tlb_addr;
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
value = (section << MMU_SECTION_SHIFT) | (3 << 10);
|
||||||
|
value |= option;
|
||||||
|
page_table[section] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||||
|
{
|
||||||
|
debug("%s: Warning: not implemented\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmu_page_table_flush(unsigned long start, unsigned long stop)
|
||||||
|
__attribute__((weak, alias("__mmu_page_table_flush")));
|
||||||
|
|
||||||
|
void mmu_set_region_dcache_behaviour(u32 start, int size,
|
||||||
|
enum dcache_option option)
|
||||||
|
{
|
||||||
|
u32 *page_table = (u32 *)gd->tlb_addr;
|
||||||
|
u32 upto, end;
|
||||||
|
|
||||||
|
end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
|
||||||
|
start = start >> MMU_SECTION_SHIFT;
|
||||||
|
debug("%s: start=%x, size=%x, option=%d\n", __func__, start, size,
|
||||||
|
option);
|
||||||
|
for (upto = start; upto < end; upto++)
|
||||||
|
set_section_dcache(upto, option);
|
||||||
|
mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dram_bank_mmu_setup(int bank)
|
||||||
|
{
|
||||||
bd_t *bd = gd->bd;
|
bd_t *bd = gd->bd;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -60,21 +86,24 @@ static inline void dram_bank_mmu_setup(int bank)
|
||||||
for (i = bd->bi_dram[bank].start >> 20;
|
for (i = bd->bi_dram[bank].start >> 20;
|
||||||
i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
|
i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
|
||||||
i++) {
|
i++) {
|
||||||
page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
|
#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
|
||||||
|
set_section_dcache(i, DCACHE_WRITETHROUGH);
|
||||||
|
#else
|
||||||
|
set_section_dcache(i, DCACHE_WRITEBACK);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* to activate the MMU we need to set up virtual memory: use 1M areas */
|
/* to activate the MMU we need to set up virtual memory: use 1M areas */
|
||||||
static inline void mmu_setup(void)
|
static inline void mmu_setup(void)
|
||||||
{
|
{
|
||||||
u32 *page_table = (u32 *)gd->tlb_addr;
|
|
||||||
int i;
|
int i;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
arm_init_before_mmu();
|
arm_init_before_mmu();
|
||||||
/* Set up an identity-mapping for all 4GB, rw for everyone */
|
/* Set up an identity-mapping for all 4GB, rw for everyone */
|
||||||
for (i = 0; i < 4096; i++)
|
for (i = 0; i < 4096; i++)
|
||||||
page_table[i] = i << 20 | (3 << 10) | 0x12;
|
set_section_dcache(i, DCACHE_OFF);
|
||||||
|
|
||||||
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
|
||||||
dram_bank_mmu_setup(i);
|
dram_bank_mmu_setup(i);
|
||||||
|
@ -82,7 +111,7 @@ static inline void mmu_setup(void)
|
||||||
|
|
||||||
/* Copy the page table address to cp15 */
|
/* Copy the page table address to cp15 */
|
||||||
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
asm volatile("mcr p15, 0, %0, c2, c0, 0"
|
||||||
: : "r" (page_table) : "memory");
|
: : "r" (gd->tlb_addr) : "memory");
|
||||||
/* Set the access control to all-supervisor */
|
/* Set the access control to all-supervisor */
|
||||||
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
asm volatile("mcr p15, 0, %0, c3, c0, 0"
|
||||||
: : "r" (~0));
|
: : "r" (~0));
|
||||||
|
|
Loading…
Reference in a new issue