uboot/arch/mips/lib/cache.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003
   3 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <asm/cacheops.h>
  10#include <asm/mipsregs.h>
  11
  12static inline unsigned long icache_line_size(void)
  13{
  14        unsigned long conf1, il;
  15
  16        if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
  17                return CONFIG_SYS_ICACHE_LINE_SIZE;
  18
  19        conf1 = read_c0_config1();
  20        il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
  21        if (!il)
  22                return 0;
  23        return 2 << il;
  24}
  25
  26static inline unsigned long dcache_line_size(void)
  27{
  28        unsigned long conf1, dl;
  29
  30        if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
  31                return CONFIG_SYS_DCACHE_LINE_SIZE;
  32
  33        conf1 = read_c0_config1();
  34        dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
  35        if (!dl)
  36                return 0;
  37        return 2 << dl;
  38}
  39
  40#define cache_loop(start, end, lsize, ops...) do {                      \
  41        const void *addr = (const void *)(start & ~(lsize - 1));        \
  42        const void *aend = (const void *)((end - 1) & ~(lsize - 1));    \
  43        const unsigned int cache_ops[] = { ops };                       \
  44        unsigned int i;                                                 \
  45                                                                        \
  46        for (; addr <= aend; addr += lsize) {                           \
  47                for (i = 0; i < ARRAY_SIZE(cache_ops); i++)             \
  48                        mips_cache(cache_ops[i], addr);                 \
  49        }                                                               \
  50} while (0)
  51
  52void flush_cache(ulong start_addr, ulong size)
  53{
  54        unsigned long ilsize = icache_line_size();
  55        unsigned long dlsize = dcache_line_size();
  56
  57        /* aend will be miscalculated when size is zero, so we return here */
  58        if (size == 0)
  59                return;
  60
  61        if (ilsize == dlsize) {
  62                /* flush I-cache & D-cache simultaneously */
  63                cache_loop(start_addr, start_addr + size, ilsize,
  64                           HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
  65                return;
  66        }
  67
  68        /* flush D-cache */
  69        cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
  70
  71        /* flush I-cache */
  72        cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
  73}
  74
  75void flush_dcache_range(ulong start_addr, ulong stop)
  76{
  77        unsigned long lsize = dcache_line_size();
  78
  79        /* aend will be miscalculated when size is zero, so we return here */
  80        if (start_addr == stop)
  81                return;
  82
  83        cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
  84}
  85
  86void invalidate_dcache_range(ulong start_addr, ulong stop)
  87{
  88        unsigned long lsize = dcache_line_size();
  89
  90        /* aend will be miscalculated when size is zero, so we return here */
  91        if (start_addr == stop)
  92                return;
  93
  94        cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D);
  95}
  96