#include <common.h>
#include <linux/compiler.h>
#include <linux/kernel.h>
+#include <linux/log2.h>
#include <asm/arcregs.h>
#include <asm/cache.h>
#ifdef CONFIG_ISA_ARCV2
int slc_line_sz __section(".data");
int slc_exists __section(".data");
+int ioc_exists __section(".data");
static unsigned int __before_slc_op(const int op)
{
static void __after_slc_op(const int op, unsigned int reg)
{
- if (op & OP_FLUSH) /* flush / flush-n-inv both wait */
+ if (op & OP_FLUSH) { /* flush / flush-n-inv both wait */
+ /*
+ * Make sure "busy" bit reports correct status,
+ * see STAR 9001165532
+ */
+ read_aux_reg(ARC_AUX_SLC_CTRL);
while (read_aux_reg(ARC_AUX_SLC_CTRL) &
DC_CTRL_FLUSH_STATUS)
;
+ }
/* Switch back to default Invalidate mode */
if (op == OP_INV)
slc_exists = 1;
slc_line_sz = (slc_cfg.fields.lsz == 0) ? 128 : 64;
}
+
+ union {
+ struct bcr_clust_cfg {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
+#else
+ unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
+#endif
+ } fields;
+ unsigned int word;
+ } cbcr;
+
+ cbcr.word = read_aux_reg(ARC_BCR_CLUSTER);
+ if (cbcr.fields.c)
+ ioc_exists = 1;
}
#endif
#ifdef CONFIG_ISA_ARCV2
read_decode_cache_bcr_arcv2();
+
+ if (ioc_exists) {
+ /* IOC Aperture start is equal to DDR start */
+ unsigned int ap_base = CONFIG_SYS_SDRAM_BASE;
+ /* IOC Aperture size is equal to DDR size */
+ long ap_size = CONFIG_SYS_SDRAM_SIZE;
+
+ flush_dcache_all();
+ invalidate_dcache_all();
+
+ if (!is_power_of_2(ap_size) || ap_size < 4096)
+ panic("IOC Aperture size must be power of 2 and bigger 4Kib");
+
+ /*
+ * IOC Aperture size decoded as 2 ^ (SIZE + 2) KB,
+ * so setting 0x11 implies 512M, 0x12 implies 1G...
+ */
+ write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE,
+ order_base_2(ap_size/1024) - 2);
+
+
+ /* IOC Aperture start must be aligned to the size of the aperture */
+ if (ap_base % ap_size != 0)
+ panic("IOC Aperture start must be aligned to the size of the aperture");
+
+ write_aux_reg(ARC_AUX_IO_COH_AP0_BASE, ap_base >> 12);
+ write_aux_reg(ARC_AUX_IO_COH_PARTIAL, 1);
+ write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
+
+ }
#endif
}
/* Any write to IC_IVIC register triggers invalidation of entire I$ */
if (icache_status()) {
write_aux_reg(ARC_AUX_IC_IVIC, 1);
+ /*
+ * As per ARC HS databook (see chapter 5.3.3.2)
+ * it is required to add 3 NOPs after each write to IC_IVIC.
+ */
+ __builtin_arc_nop();
+ __builtin_arc_nop();
+ __builtin_arc_nop();
read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */
}
}
void invalidate_dcache_range(unsigned long start, unsigned long end)
{
- __dc_line_op(start, end - start, OP_INV);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_line_op(start, end - start, OP_INV);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_line_op(start, end - start, OP_INV);
#endif
}
void flush_dcache_range(unsigned long start, unsigned long end)
{
- __dc_line_op(start, end - start, OP_FLUSH);
#ifdef CONFIG_ISA_ARCV2
- if (slc_exists)
+ if (!ioc_exists)
+#endif
+ __dc_line_op(start, end - start, OP_FLUSH);
+
+#ifdef CONFIG_ISA_ARCV2
+ if (slc_exists && !ioc_exists)
__slc_line_op(start, end - start, OP_FLUSH);
#endif
}
void invalidate_dcache_all(void)
{
__dc_entire_op(OP_INV);
+
#ifdef CONFIG_ISA_ARCV2
if (slc_exists)
__slc_entire_op(OP_INV);
void flush_dcache_all(void)
{
__dc_entire_op(OP_FLUSH);
+
#ifdef CONFIG_ISA_ARCV2
if (slc_exists)
__slc_entire_op(OP_FLUSH);