[U-Boot] [PATCH v7 09/16] arm: Add control over cachability of memory regions

Simon Glass sjg at chromium.org
Mon Nov 5 21:21:57 CET 2012


Hi Dennis,

On Sun, Nov 4, 2012 at 7:00 PM, Dennis Lan (dlan) <dennis.yxun at gmail.com> wrote:
> HI Simon:
> This patch still not go to the master branch,
> but I actually found it useful, like interact with peripheral buffer
> (not only just LCD here), then I can set special attribute.

It should come in via Tegra, ARM fairly soon.

>
>   One question here, can I use mmu_set_region_dcache_behaviour following malloc,
> what about if I allocate small buffer (less than 1MBytes), since that
> current default Page Size is 1MByes (the granularity), then much more
> memory area will be affected?

Yes that's right - it is designed for memory regions allocated in
board_init_f(), that are at least one section in size.

Certainly it could be enhanced to support L2 page tables. But another
option might be to allocate 2MB of memory and place your buffer within
that region, aligned to 1MB.

Regards,
Simon

>
>
>
> On Thu, Oct 18, 2012 at 7:24 AM, Simon Glass <sjg at chromium.org> wrote:
>> 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 at chromium.org>
>> ---
>> Changes in v7:
>> - Rename mmu_set_region_dcache() to mmu_set_region_dcache_behaviour()
>>
>> Changes in v4:
>> - Use system bit values for enum dcache_option instead of arbitrary numbers
>>
>>  arch/arm/cpu/armv7/cache_v7.c |   11 +++++++++
>>  arch/arm/include/asm/system.h |   31 +++++++++++++++++++++++++
>>  arch/arm/lib/cache-cp15.c     |   51 ++++++++++++++++++++++++++++++++---------
>>  3 files changed, 82 insertions(+), 11 deletions(-)
>>
>> diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c
>> index 1b4e808..5f6d039 100644
>> --- a/arch/arm/cpu/armv7/cache_v7.c
>> +++ b/arch/arm/cpu/armv7/cache_v7.c
>> @@ -297,6 +297,12 @@ void arm_init_before_mmu(void)
>>         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:
>>   * 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 mmu_page_table_flush(unsigned long start, unsigned long stop)
>> +{
>> +}
>> +
>>  #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */
>>
>>  #ifndef CONFIG_SYS_ICACHE_OFF
>> diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
>> index 2b28a26..78ca8e0 100644
>> --- a/arch/arm/include/asm/system.h
>> +++ b/arch/arm/include/asm/system.h
>> @@ -75,6 +75,37 @@ static inline void set_cr(unsigned int val)
>>         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__ */
>>
>>  #define arch_align_stack(x) (x)
>> diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
>> index 939de10..6edf815 100644
>> --- a/arch/arm/lib/cache-cp15.c
>> +++ b/arch/arm/lib/cache-cp15.c
>> @@ -26,12 +26,6 @@
>>
>>  #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;
>>
>>  void __arm_init_before_mmu(void)
>> @@ -50,9 +44,41 @@ static void cp_delay (void)
>>         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 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;
>>         int     i;
>>
>> @@ -60,21 +86,24 @@ static inline void dram_bank_mmu_setup(int bank)
>>         for (i = bd->bi_dram[bank].start >> 20;
>>              i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
>>              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 */
>>  static inline void mmu_setup(void)
>>  {
>> -       u32 *page_table = (u32 *)gd->tlb_addr;
>>         int i;
>>         u32 reg;
>>
>>         arm_init_before_mmu();
>>         /* Set up an identity-mapping for all 4GB, rw for everyone */
>>         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++) {
>>                 dram_bank_mmu_setup(i);
>> @@ -82,7 +111,7 @@ static inline void mmu_setup(void)
>>
>>         /* Copy the page table address to cp15 */
>>         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 */
>>         asm volatile("mcr p15, 0, %0, c3, c0, 0"
>>                      : : "r" (~0));
>> --
>> 1.7.7.3
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot


More information about the U-Boot mailing list