Merge branch 'master' of git://git.denx.de/u-boot-mpc85xx
[oweals/u-boot.git] / arch / mips / cpu / mips32 / cpu.c
index 3ae397c8eff4160f6d37102016fbf7e634b591b1..278865b6fff54849c98b0e1bd69a7cc7b2e5ba6f 100644 (file)
@@ -2,23 +2,7 @@
  * (C) Copyright 2003
  * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
@@ -50,29 +34,94 @@ int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        return 0;
 }
 
+#ifdef CONFIG_SYS_CACHELINE_SIZE
+
+static inline unsigned long icache_line_size(void)
+{
+       return CONFIG_SYS_CACHELINE_SIZE;
+}
+
+static inline unsigned long dcache_line_size(void)
+{
+       return CONFIG_SYS_CACHELINE_SIZE;
+}
+
+#else /* !CONFIG_SYS_CACHELINE_SIZE */
+
+static inline unsigned long icache_line_size(void)
+{
+       unsigned long conf1, il;
+       conf1 = read_c0_config1();
+       il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHIFT;
+       if (!il)
+               return 0;
+       return 2 << il;
+}
+
+static inline unsigned long dcache_line_size(void)
+{
+       unsigned long conf1, dl;
+       conf1 = read_c0_config1();
+       dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHIFT;
+       if (!dl)
+               return 0;
+       return 2 << dl;
+}
+
+#endif /* !CONFIG_SYS_CACHELINE_SIZE */
+
 void flush_cache(ulong start_addr, ulong size)
 {
-       unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
-       unsigned long addr = start_addr & ~(lsize - 1);
-       unsigned long aend = (start_addr + size - 1) & ~(lsize - 1);
+       unsigned long ilsize = icache_line_size();
+       unsigned long dlsize = dcache_line_size();
+       unsigned long addr, aend;
+
+       /* aend will be miscalculated when size is zero, so we return here */
+       if (size == 0)
+               return;
+
+       addr = start_addr & ~(dlsize - 1);
+       aend = (start_addr + size - 1) & ~(dlsize - 1);
+
+       if (ilsize == dlsize) {
+               /* flush I-cache & D-cache simultaneously */
+               while (1) {
+                       cache_op(HIT_WRITEBACK_INV_D, addr);
+                       cache_op(HIT_INVALIDATE_I, addr);
+                       if (addr == aend)
+                               break;
+                       addr += dlsize;
+               }
+               return;
+       }
 
+       /* flush D-cache */
        while (1) {
-               cache_op(Hit_Writeback_Inv_D, addr);
-               cache_op(Hit_Invalidate_I, addr);
+               cache_op(HIT_WRITEBACK_INV_D, addr);
                if (addr == aend)
                        break;
-               addr += lsize;
+               addr += dlsize;
+       }
+
+       /* flush I-cache */
+       addr = start_addr & ~(ilsize - 1);
+       aend = (start_addr + size - 1) & ~(ilsize - 1);
+       while (1) {
+               cache_op(HIT_INVALIDATE_I, addr);
+               if (addr == aend)
+                       break;
+               addr += ilsize;
        }
 }
 
 void flush_dcache_range(ulong start_addr, ulong stop)
 {
-       unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+       unsigned long lsize = dcache_line_size();
        unsigned long addr = start_addr & ~(lsize - 1);
        unsigned long aend = (stop - 1) & ~(lsize - 1);
 
        while (1) {
-               cache_op(Hit_Writeback_Inv_D, addr);
+               cache_op(HIT_WRITEBACK_INV_D, addr);
                if (addr == aend)
                        break;
                addr += lsize;
@@ -81,12 +130,12 @@ void flush_dcache_range(ulong start_addr, ulong stop)
 
 void invalidate_dcache_range(ulong start_addr, ulong stop)
 {
-       unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+       unsigned long lsize = dcache_line_size();
        unsigned long addr = start_addr & ~(lsize - 1);
        unsigned long aend = (stop - 1) & ~(lsize - 1);
 
        while (1) {
-               cache_op(Hit_Invalidate_D, addr);
+               cache_op(HIT_INVALIDATE_D, addr);
                if (addr == aend)
                        break;
                addr += lsize;