[U-Boot] [PATCH 1/4] ARC: read pae_exist bit from MMU BCR

ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist only if PAE exists in current HW. So we had to check pae_exist bit before using them.
Signed-off-by: Eugeniy Paltsev Eugeniy.Paltsev@synopsys.com --- arch/arc/include/asm/arcregs.h | 3 +++ arch/arc/lib/cache.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+)
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index ba1f7ba..53e83c7 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -65,6 +65,9 @@ #define ARC_AUX_SLC_FLDL 0x912 #define ARC_BCR_CLUSTER 0xcf
+/* MMU Management regs */ +#define ARC_AUX_MMU_BCR 0x06f + /* IO coherency related auxiliary registers */ #define ARC_AUX_IO_COH_ENABLE 0x500 #define ARC_AUX_IO_COH_PARTIAL 0x501 diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index 1073e15..0a41dc4 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -41,6 +41,32 @@ bool icache_exists __section(".data") = false; int slc_line_sz __section(".data"); bool slc_exists __section(".data") = false; bool ioc_exists __section(".data") = false; +bool pae_exists __section(".data") = false; + +void read_decode_mmu_bcr(void) +{ + /* TODO: should we compare mmu version from BCR and from CONFIG? */ +#if (CONFIG_ARC_MMU_VER >= 4) + u32 tmp; + + tmp = read_aux_reg(ARC_AUX_MMU_BCR); + + struct bcr_mmu_4 { +#ifdef CONFIG_CPU_BIG_ENDIAN + unsigned int ver:8, sasid:1, sz1:4, sz0:4, res:2, pae:1, + n_ways:2, n_entry:2, n_super:2, u_itlb:3, u_dtlb:3; +#else + /* DTLB ITLB JES JE JA */ + unsigned int u_dtlb:3, u_itlb:3, n_super:2, n_entry:2, n_ways:2, + pae:1, res:2, sz0:4, sz1:4, sasid:1, ver:8; +#endif /* CONFIG_CPU_BIG_ENDIAN */ + } *mmu4; + + mmu4 = (struct bcr_mmu_4 *)&tmp; + + pae_exists = !!mmu4->pae; +#endif /* (CONFIG_ARC_MMU_VER >= 4) */ +}
static unsigned int __before_slc_op(const int op) { @@ -244,6 +270,8 @@ void cache_init(void) write_aux_reg(ARC_AUX_IO_COH_ENABLE, 1);
} + + read_decode_mmu_bcr(); #endif }

Previous slc_line_op implementation is broken. It was never tested/used as we use u-boot with IOC enabled. So if we disable IOC we will get a lot of errors while using DMA peripherals. Fix it by replacingi broken slc_line_op with slc region operations (which are used in linux kernel)
Main changes: * Replace __slc_line_op (per line operations) by __slc_rgn_op (region operations) Implementation from 4.14 linux kernel. * Rework __slc_entire_op to get rid of __after_slc_op and __before_slc_op functions. Implementation from 4.14 linux kernel with flush fix (flush only instead of flush-n-inv when OP_FLUSH is used) * Add SLC invalidation to invalidate_icache_all function. * Add (start >= end) check to invalidate_dcache_range and flush_dcache_range as some buggy drivers pass region start == end.
Signed-off-by: Eugeniy Paltsev Eugeniy.Paltsev@synopsys.com --- arch/arc/include/asm/arcregs.h | 4 + arch/arc/lib/cache.c | 167 +++++++++++++++++++++++------------------ 2 files changed, 97 insertions(+), 74 deletions(-)
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h index 53e83c7..67f4163 100644 --- a/arch/arc/include/asm/arcregs.h +++ b/arch/arc/include/asm/arcregs.h @@ -63,6 +63,10 @@ #define ARC_AUX_SLC_INVALIDATE 0x905 #define ARC_AUX_SLC_IVDL 0x910 #define ARC_AUX_SLC_FLDL 0x912 +#define ARC_AUX_SLC_RGN_START 0x914 +#define ARC_AUX_SLC_RGN_START1 0x915 +#define ARC_AUX_SLC_RGN_END 0x916 +#define ARC_AUX_SLC_RGN_END1 0x917 #define ARC_BCR_CLUSTER 0xcf
/* MMU Management regs */ diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index 0a41dc4..a6bbe3c 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -20,12 +20,17 @@ #define DC_CTRL_INV_MODE_FLUSH (1 << 6) #define DC_CTRL_FLUSH_STATUS (1 << 8) #define CACHE_VER_NUM_MASK 0xF -#define SLC_CTRL_SB (1 << 2)
#define OP_INV 0x1 #define OP_FLUSH 0x2 #define OP_INV_IC 0x3
+/* Bit val in SLC_CONTROL */ +#define SLC_CTRL_DIS 0x001 +#define SLC_CTRL_IM 0x040 +#define SLC_CTRL_BUSY 0x100 +#define SLC_CTRL_RGN_OP_INV 0x200 + /* * By default that variable will fall into .bss section. * But .bss section is not relocated and so it will be initilized before @@ -68,87 +73,88 @@ void read_decode_mmu_bcr(void) #endif /* (CONFIG_ARC_MMU_VER >= 4) */ }
-static unsigned int __before_slc_op(const int op) +static void __slc_entire_op(const int op) { - unsigned int reg = reg; + unsigned int ctrl;
- if (op == OP_INV) { - /* - * IM is set by default and implies Flush-n-inv - * Clear it here for vanilla inv - */ - reg = read_aux_reg(ARC_AUX_SLC_CTRL); - write_aux_reg(ARC_AUX_SLC_CTRL, reg & ~DC_CTRL_INV_MODE_FLUSH); - } + ctrl = read_aux_reg(ARC_AUX_SLC_CTRL);
- return reg; -} - -static void __after_slc_op(const int op, unsigned int reg) -{ - 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) - write_aux_reg(ARC_AUX_SLC_CTRL, reg | DC_CTRL_INV_MODE_FLUSH); -} - -static inline void __slc_line_loop(unsigned long paddr, unsigned long sz, - const int op) -{ - unsigned int aux_cmd; - int num_lines; + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM;
-#define SLC_LINE_MASK (~(slc_line_sz - 1)) + write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
- aux_cmd = op & OP_INV ? ARC_AUX_SLC_IVDL : ARC_AUX_SLC_FLDL; + if (op & OP_INV) /* Inv or flush-n-inv use same cmd reg */ + write_aux_reg(ARC_AUX_SLC_INVALIDATE, 0x1); + else + write_aux_reg(ARC_AUX_SLC_FLUSH, 0x1);
- sz += paddr & ~SLC_LINE_MASK; - paddr &= SLC_LINE_MASK; + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ + read_aux_reg(ARC_AUX_SLC_CTRL);
- num_lines = DIV_ROUND_UP(sz, slc_line_sz); + /* Important to wait for flush to complete */ + while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); +}
- while (num_lines-- > 0) { - write_aux_reg(aux_cmd, paddr); - paddr += slc_line_sz; - } +static void slc_upper_region_init(void) +{ + /* + * ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1 are always == 0 + * as we don't use PAE40. + */ + write_aux_reg(ARC_AUX_SLC_RGN_END1, 0); + write_aux_reg(ARC_AUX_SLC_RGN_START1, 0); }
-static inline void __slc_entire_op(const int cacheop) +static void __slc_rgn_op(unsigned long paddr, unsigned long sz, const int op) { - int aux; - unsigned int ctrl_reg = __before_slc_op(cacheop); + unsigned int ctrl; + unsigned long end; + + /* + * The Region Flush operation is specified by CTRL.RGN_OP[11..9] + * - b'000 (default) is Flush, + * - b'001 is Invalidate if CTRL.IM == 0 + * - b'001 is Flush-n-Invalidate if CTRL.IM == 1 + */ + ctrl = read_aux_reg(ARC_AUX_SLC_CTRL); + + /* Don't rely on default value of IM bit */ + if (!(op & OP_FLUSH)) /* i.e. OP_INV */ + ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */ + else + ctrl |= SLC_CTRL_IM;
- if (cacheop & OP_INV) /* Inv or flush-n-inv use same cmd reg */ - aux = ARC_AUX_SLC_INVALIDATE; + if (op & OP_INV) + ctrl |= SLC_CTRL_RGN_OP_INV; /* Inv or flush-n-inv */ else - aux = ARC_AUX_SLC_FLUSH; + ctrl &= ~SLC_CTRL_RGN_OP_INV;
- write_aux_reg(aux, 0x1); + write_aux_reg(ARC_AUX_SLC_CTRL, ctrl);
- __after_slc_op(cacheop, ctrl_reg); -} + /* + * Lower bits are ignored, no need to clip + * END needs to be setup before START (latter triggers the operation) + * END can't be same as START, so add (l2_line_sz - 1) to sz + */ + end = paddr + sz + slc_line_sz - 1;
-static inline void __slc_line_op(unsigned long paddr, unsigned long sz, - const int cacheop) -{ - unsigned int ctrl_reg = __before_slc_op(cacheop); - __slc_line_loop(paddr, sz, cacheop); - __after_slc_op(cacheop, ctrl_reg); + /* + * Upper addresses (ARC_AUX_SLC_RGN_END1 and ARC_AUX_SLC_RGN_START1) + * are always == 0 as we don't use PAE40, so we only setup lower ones + * (ARC_AUX_SLC_RGN_END and ARC_AUX_SLC_RGN_START) + */ + write_aux_reg(ARC_AUX_SLC_RGN_END, end); + write_aux_reg(ARC_AUX_SLC_RGN_START, paddr); + + /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */ + read_aux_reg(ARC_AUX_SLC_CTRL); + + while (read_aux_reg(ARC_AUX_SLC_CTRL) & SLC_CTRL_BUSY); } -#else -#define __slc_entire_op(cacheop) -#define __slc_line_op(paddr, sz, cacheop) -#endif +#endif /* CONFIG_ISA_ARCV2 */
#ifdef CONFIG_ISA_ARCV2 static void read_decode_cache_bcr_arcv2(void) @@ -272,7 +278,15 @@ void cache_init(void) }
read_decode_mmu_bcr(); -#endif + + /* + * ARC_AUX_SLC_RGN_START1 and ARC_AUX_SLC_RGN_END1 register exist + * only if PAE exists in current HW. So we had to check pae_exist + * before using them. + */ + if (slc_exists && pae_exists) + slc_upper_region_init(); +#endif /* CONFIG_ISA_ARCV2 */ }
int icache_status(void) @@ -300,7 +314,6 @@ void icache_disable(void) IC_CTRL_CACHE_DISABLE); }
-#ifndef CONFIG_SYS_DCACHE_OFF void invalidate_icache_all(void) { /* Any write to IC_IVIC register triggers invalidation of entire I$ */ @@ -315,12 +328,12 @@ void invalidate_icache_all(void) __builtin_arc_nop(); read_aux_reg(ARC_AUX_IC_CTRL); /* blocks */ } -} -#else -void invalidate_icache_all(void) -{ -} + +#ifdef CONFIG_ISA_ARCV2 + if (slc_exists) + __slc_entire_op(OP_INV); #endif +}
int dcache_status(void) { @@ -447,6 +460,9 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz,
void invalidate_dcache_range(unsigned long start, unsigned long end) { + if (start >= end) + return; + #ifdef CONFIG_ISA_ARCV2 if (!ioc_exists) #endif @@ -454,12 +470,15 @@ void invalidate_dcache_range(unsigned long start, unsigned long end)
#ifdef CONFIG_ISA_ARCV2 if (slc_exists && !ioc_exists) - __slc_line_op(start, end - start, OP_INV); + __slc_rgn_op(start, end - start, OP_INV); #endif }
void flush_dcache_range(unsigned long start, unsigned long end) { + if (start >= end) + return; + #ifdef CONFIG_ISA_ARCV2 if (!ioc_exists) #endif @@ -467,7 +486,7 @@ void flush_dcache_range(unsigned long start, unsigned long end)
#ifdef CONFIG_ISA_ARCV2 if (slc_exists && !ioc_exists) - __slc_line_op(start, end - start, OP_FLUSH); + __slc_rgn_op(start, end - start, OP_FLUSH); #endif }

Disable IOC by default with option to enable it. We don't want to enable IOC in u-boot by default as we want keep IOC HW at same state as after reset when we launching linux.
Signed-off-by: Eugeniy Paltsev Eugeniy.Paltsev@synopsys.com --- arch/arc/lib/cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index a6bbe3c..d17948d 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -48,6 +48,9 @@ bool slc_exists __section(".data") = false; bool ioc_exists __section(".data") = false; bool pae_exists __section(".data") = false;
+/* To force enable IOC set ioc_enable to 'true' */ +bool ioc_enable __section(".data") = false; + void read_decode_mmu_bcr(void) { /* TODO: should we compare mmu version from BCR and from CONFIG? */ @@ -200,7 +203,7 @@ static void read_decode_cache_bcr_arcv2(void) } cbcr;
cbcr.word = read_aux_reg(ARC_BCR_CLUSTER); - if (cbcr.fields.c) + if (cbcr.fields.c && ioc_enable) ioc_exists = true; } #endif

Signed-off-by: Eugeniy Paltsev Eugeniy.Paltsev@synopsys.com --- arch/arc/lib/cache.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/arch/arc/lib/cache.c b/arch/arc/lib/cache.c index d17948d..04f1d9d 100644 --- a/arch/arc/lib/cache.c +++ b/arch/arc/lib/cache.c @@ -13,12 +13,12 @@ #include <asm/cache.h>
/* Bit values in IC_CTRL */ -#define IC_CTRL_CACHE_DISABLE (1 << 0) +#define IC_CTRL_CACHE_DISABLE BIT(0)
/* Bit values in DC_CTRL */ -#define DC_CTRL_CACHE_DISABLE (1 << 0) -#define DC_CTRL_INV_MODE_FLUSH (1 << 6) -#define DC_CTRL_FLUSH_STATUS (1 << 8) +#define DC_CTRL_CACHE_DISABLE BIT(0) +#define DC_CTRL_INV_MODE_FLUSH BIT(6) +#define DC_CTRL_FLUSH_STATUS BIT(8) #define CACHE_VER_NUM_MASK 0xF
#define OP_INV 0x1 @@ -232,7 +232,7 @@ void read_decode_cache_bcr(void) }
dbcr.word = read_aux_reg(ARC_BCR_DC_BUILD); - if (dbcr.fields.ver){ + if (dbcr.fields.ver) { dcache_exists = true; l1_line_sz = dc_line_sz = 16 << dbcr.fields.line_len; if (!dc_line_sz) @@ -267,8 +267,7 @@ void cache_init(void) * so setting 0x11 implies 512M, 0x12 implies 1G... */ write_aux_reg(ARC_AUX_IO_COH_AP0_SIZE, - order_base_2(ap_size/1024) - 2); - + 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) @@ -277,7 +276,6 @@ void cache_init(void) 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); - }
read_decode_mmu_bcr(); @@ -426,8 +424,7 @@ static unsigned int __before_dc_op(const int op) static void __after_dc_op(const int op, unsigned int reg) { if (op & OP_FLUSH) /* flush / flush-n-inv both wait */ - while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS) - ; + while (read_aux_reg(ARC_AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
/* Switch back to default Invalidate mode */ if (op == OP_INV) @@ -453,6 +450,7 @@ static inline void __dc_line_op(unsigned long paddr, unsigned long sz, const int cacheop) { unsigned int ctrl_reg = __before_dc_op(cacheop); + __cache_line_loop(paddr, sz, cacheop); __after_dc_op(cacheop, ctrl_reg); }
participants (1)
-
Eugeniy Paltsev