From 265c271c822bd57677e3b286389487fd45e6960d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:44 +0000 Subject: ARM: l2c: remove outer_inv_all() method No one ever calls this function anywhere in the kernel, so let's completely remove it from the outer cache API and turn it into an internal-only thing. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 7abde2ce8973..f9985e5a208c 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -414,7 +414,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) outer_cache.flush_range = l2x0_flush_range; outer_cache.sync = l2x0_cache_sync; outer_cache.flush_all = l2x0_flush_all; - outer_cache.inv_all = l2x0_inv_all; outer_cache.disable = l2x0_disable; } @@ -884,7 +883,6 @@ static const struct l2x0_of_data pl310_data = { .flush_range = l2x0_flush_range, .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, - .inv_all = l2x0_inv_all, .disable = l2x0_disable, }, }; @@ -899,7 +897,6 @@ static const struct l2x0_of_data l2x0_data = { .flush_range = l2x0_flush_range, .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, - .inv_all = l2x0_inv_all, .disable = l2x0_disable, }, }; @@ -914,7 +911,6 @@ static const struct l2x0_of_data aurora_with_outer_data = { .flush_range = aurora_flush_range, .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, - .inv_all = l2x0_inv_all, .disable = l2x0_disable, }, }; @@ -946,7 +942,6 @@ static const struct l2x0_of_data bcm_l2x0_data = { .flush_range = bcm_flush_range, .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, - .inv_all = l2x0_inv_all, .disable = l2x0_disable, }, }; -- cgit v1.2.3 From a65bb925601cf35ef5db54c8a9ad9e6575c6fe8c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:01 +0000 Subject: ARM: l2c: add helper for L2 cache controller DT IDs Make it easier to declare L2 cache controller DT IDs by using a macro. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index f9985e5a208c..ac410b21edfb 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -946,20 +946,17 @@ static const struct l2x0_of_data bcm_l2x0_data = { }, }; +#define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } static const struct of_device_id l2x0_ids[] __initconst = { - { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data }, - { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, - { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, - { .compatible = "bcm,bcm11351-a2-pl310-cache", /* deprecated name */ - .data = (void *)&bcm_l2x0_data}, - { .compatible = "brcm,bcm11351-a2-pl310-cache", - .data = (void *)&bcm_l2x0_data}, - { .compatible = "marvell,aurora-outer-cache", - .data = (void *)&aurora_with_outer_data}, - { .compatible = "marvell,aurora-system-cache", - .data = (void *)&aurora_no_outer_data}, - { .compatible = "marvell,tauros3-cache", - .data = (void *)&tauros3_data }, + L2C_ID("arm,l210-cache", l2x0_data), + L2C_ID("arm,l220-cache", l2x0_data), + L2C_ID("arm,pl310-cache", pl310_data), + L2C_ID("brcm,bcm11351-a2-pl310-cache", bcm_l2x0_data), + L2C_ID("marvell,aurora-outer-cache", aurora_with_outer_data), + L2C_ID("marvell,aurora-system-cache", aurora_no_outer_data), + L2C_ID("marvell,tauros3-cache", tauros3_data), + /* Deprecated IDs */ + L2C_ID("bcm,bcm11351-a2-pl310-cache", bcm_l2x0_data), {} }; -- cgit v1.2.3 From ce84130384badcad2cdbc1e825657d622165f0e6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:03 +0000 Subject: ARM: l2c: tidy up l2x0_of_data declarations Remove NULL initialisers, make these all __initconst structures, and order their members in the same order as the structure declaration. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index ac410b21edfb..063e1787e8c3 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -873,49 +873,48 @@ static void __init aurora_of_setup(const struct device_node *np, *aux_mask &= ~mask; } -static const struct l2x0_of_data pl310_data = { +static const struct l2x0_of_data pl310_data __initconst = { .setup = pl310_of_setup, .save = pl310_save, .outer_cache = { - .resume = pl310_resume, .inv_range = l2x0_inv_range, .clean_range = l2x0_clean_range, .flush_range = l2x0_flush_range, - .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = pl310_resume, }, }; -static const struct l2x0_of_data l2x0_data = { +static const struct l2x0_of_data l2x0_data __initconst = { .setup = l2x0_of_setup, - .save = NULL, .outer_cache = { - .resume = l2x0_resume, .inv_range = l2x0_inv_range, .clean_range = l2x0_clean_range, .flush_range = l2x0_flush_range, - .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = l2x0_resume, }, }; -static const struct l2x0_of_data aurora_with_outer_data = { +static const struct l2x0_of_data aurora_with_outer_data __initconst = { .setup = aurora_of_setup, .save = aurora_save, .outer_cache = { - .resume = aurora_resume, .inv_range = aurora_inv_range, .clean_range = aurora_clean_range, .flush_range = aurora_flush_range, - .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = aurora_resume, }, }; -static const struct l2x0_of_data aurora_no_outer_data = { +static const struct l2x0_of_data aurora_no_outer_data __initconst = { .setup = aurora_of_setup, .save = aurora_save, .outer_cache = { @@ -923,8 +922,7 @@ static const struct l2x0_of_data aurora_no_outer_data = { }, }; -static const struct l2x0_of_data tauros3_data = { - .setup = NULL, +static const struct l2x0_of_data tauros3_data __initconst = { .save = tauros3_save, /* Tauros3 broadcasts L1 cache operations to L2 */ .outer_cache = { @@ -932,17 +930,17 @@ static const struct l2x0_of_data tauros3_data = { }, }; -static const struct l2x0_of_data bcm_l2x0_data = { +static const struct l2x0_of_data bcm_l2x0_data __initconst = { .setup = pl310_of_setup, .save = pl310_save, .outer_cache = { - .resume = pl310_resume, .inv_range = bcm_inv_range, .clean_range = bcm_clean_range, .flush_range = bcm_flush_range, - .sync = l2x0_cache_sync, .flush_all = l2x0_flush_all, .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = pl310_resume, }, }; -- cgit v1.2.3 From c02642bc1010b7ef8a4b87763ab28f5e4ab1d823 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:54 +0000 Subject: ARM: l2c: rename OF specific things, making l2x0_of_data available to all Rename a few things to help distinguish their function(s): l2x0_of_data -> l2c_init_data setup -> of_parse add of_ prefix to OF specific data Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 063e1787e8c3..d659c4ca46bb 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -28,6 +28,12 @@ #include "cache-tauros3.h" #include "cache-aurora-l2.h" +struct l2c_init_data { + void (*of_parse)(const struct device_node *, u32 *, u32 *); + void (*save)(void); + struct outer_cache_fns outer_cache; +}; + #define CACHE_LINE_SIZE 32 static void __iomem *l2x0_base; @@ -42,12 +48,6 @@ static u32 cache_id_part_number_from_dt; struct l2x0_regs l2x0_saved_regs; -struct l2x0_of_data { - void (*setup)(const struct device_node *, u32 *, u32 *); - void (*save)(void); - struct outer_cache_fns outer_cache; -}; - static bool of_init = false; static inline void cache_wait_way(void __iomem *reg, unsigned long mask) @@ -664,7 +664,7 @@ static void bcm_flush_range(unsigned long start, unsigned long end) new_end); } -static void __init l2x0_of_setup(const struct device_node *np, +static void __init l2x0_of_parse(const struct device_node *np, u32 *aux_val, u32 *aux_mask) { u32 data[2] = { 0, 0 }; @@ -698,7 +698,7 @@ static void __init l2x0_of_setup(const struct device_node *np, *aux_mask &= ~mask; } -static void __init pl310_of_setup(const struct device_node *np, +static void __init pl310_of_parse(const struct device_node *np, u32 *aux_val, u32 *aux_mask) { u32 data[3] = { 0, 0, 0 }; @@ -851,7 +851,7 @@ static void __init aurora_broadcast_l2_commands(void) isb(); } -static void __init aurora_of_setup(const struct device_node *np, +static void __init aurora_of_parse(const struct device_node *np, u32 *aux_val, u32 *aux_mask) { u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; @@ -873,8 +873,8 @@ static void __init aurora_of_setup(const struct device_node *np, *aux_mask &= ~mask; } -static const struct l2x0_of_data pl310_data __initconst = { - .setup = pl310_of_setup, +static const struct l2c_init_data of_pl310_data __initconst = { + .of_parse = pl310_of_parse, .save = pl310_save, .outer_cache = { .inv_range = l2x0_inv_range, @@ -887,8 +887,8 @@ static const struct l2x0_of_data pl310_data __initconst = { }, }; -static const struct l2x0_of_data l2x0_data __initconst = { - .setup = l2x0_of_setup, +static const struct l2c_init_data of_l2x0_data __initconst = { + .of_parse = l2x0_of_parse, .outer_cache = { .inv_range = l2x0_inv_range, .clean_range = l2x0_clean_range, @@ -900,8 +900,8 @@ static const struct l2x0_of_data l2x0_data __initconst = { }, }; -static const struct l2x0_of_data aurora_with_outer_data __initconst = { - .setup = aurora_of_setup, +static const struct l2c_init_data of_aurora_with_outer_data __initconst = { + .of_parse = aurora_of_parse, .save = aurora_save, .outer_cache = { .inv_range = aurora_inv_range, @@ -914,15 +914,15 @@ static const struct l2x0_of_data aurora_with_outer_data __initconst = { }, }; -static const struct l2x0_of_data aurora_no_outer_data __initconst = { - .setup = aurora_of_setup, +static const struct l2c_init_data of_aurora_no_outer_data __initconst = { + .of_parse = aurora_of_parse, .save = aurora_save, .outer_cache = { .resume = aurora_resume, }, }; -static const struct l2x0_of_data tauros3_data __initconst = { +static const struct l2c_init_data of_tauros3_data __initconst = { .save = tauros3_save, /* Tauros3 broadcasts L1 cache operations to L2 */ .outer_cache = { @@ -930,8 +930,8 @@ static const struct l2x0_of_data tauros3_data __initconst = { }, }; -static const struct l2x0_of_data bcm_l2x0_data __initconst = { - .setup = pl310_of_setup, +static const struct l2c_init_data of_bcm_l2x0_data __initconst = { + .of_parse = pl310_of_parse, .save = pl310_save, .outer_cache = { .inv_range = bcm_inv_range, @@ -946,22 +946,22 @@ static const struct l2x0_of_data bcm_l2x0_data __initconst = { #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } static const struct of_device_id l2x0_ids[] __initconst = { - L2C_ID("arm,l210-cache", l2x0_data), - L2C_ID("arm,l220-cache", l2x0_data), - L2C_ID("arm,pl310-cache", pl310_data), - L2C_ID("brcm,bcm11351-a2-pl310-cache", bcm_l2x0_data), - L2C_ID("marvell,aurora-outer-cache", aurora_with_outer_data), - L2C_ID("marvell,aurora-system-cache", aurora_no_outer_data), - L2C_ID("marvell,tauros3-cache", tauros3_data), + L2C_ID("arm,l210-cache", of_l2x0_data), + L2C_ID("arm,l220-cache", of_l2x0_data), + L2C_ID("arm,pl310-cache", of_pl310_data), + L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), + L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data), + L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data), + L2C_ID("marvell,tauros3-cache", of_tauros3_data), /* Deprecated IDs */ - L2C_ID("bcm,bcm11351-a2-pl310-cache", bcm_l2x0_data), + L2C_ID("bcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), {} }; int __init l2x0_of_init(u32 aux_val, u32 aux_mask) { + const struct l2c_init_data *data; struct device_node *np; - const struct l2x0_of_data *data; struct resource res; np = of_find_matching_node(NULL, l2x0_ids); @@ -981,12 +981,12 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) /* L2 configuration can only be changed if the cache is disabled */ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { - if (data->setup) - data->setup(np, &aux_val, &aux_mask); + if (data->of_parse) + data->of_parse(np, &aux_val, &aux_mask); /* For aurora cache in no outer mode select the * correct mode using the coprocessor*/ - if (data == &aurora_no_outer_data) + if (data == &of_aurora_no_outer_data) aurora_broadcast_l2_commands(); } -- cgit v1.2.3 From 2b2a87a12d2e0aede29e45911aeb0c520066b0c0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 16 Mar 2014 17:19:21 +0000 Subject: ARM: l2c: provide generic function for calling set_debug method Provide a generic function which always calls the set_debug method. This will be used later in the series as some work-arounds require that the debug register be written. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index d659c4ca46bb..595c50519e41 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -57,6 +57,16 @@ static inline void cache_wait_way(void __iomem *reg, unsigned long mask) cpu_relax(); } +/* + * This should only be called when we have a requirement that the + * register be written due to a work-around, as platforms running + * in non-secure mode may not be able to access this register. + */ +static inline void l2c_set_debug(void __iomem *base, unsigned long val) +{ + outer_cache.set_debug(val); +} + #ifdef CONFIG_CACHE_PL310 static inline void cache_wait(void __iomem *reg, unsigned long mask) { @@ -92,7 +102,7 @@ static inline void l2x0_inv_line(unsigned long addr) static inline void debug_writel(unsigned long val) { if (outer_cache.set_debug) - outer_cache.set_debug(val); + l2c_set_debug(l2x0_base, val); } static void pl310_set_debug(unsigned long val) -- cgit v1.2.3 From 37abcdb9194001a0c6ccc5508cd84ea8bd92c29c Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:50 +0000 Subject: ARM: l2c: split out cache unlock code Split the cache unlock code out of l2x0_unlock(). We want to be able to re-use this functionality later. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 595c50519e41..a1313d20f205 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -50,6 +50,9 @@ struct l2x0_regs l2x0_saved_regs; static bool of_init = false; +/* + * Common code for all cache controllers. + */ static inline void cache_wait_way(void __iomem *reg, unsigned long mask) { /* wait for cache operation by line or way to complete */ @@ -67,6 +70,18 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val) outer_cache.set_debug(val); } +static inline void l2c_unlock(void __iomem *base, unsigned num) +{ + unsigned i; + + for (i = 0; i < num; i++) { + writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_D_BASE + + i * L2X0_LOCKDOWN_STRIDE); + writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_I_BASE + + i * L2X0_LOCKDOWN_STRIDE); + } +} + #ifdef CONFIG_CACHE_PL310 static inline void cache_wait(void __iomem *reg, unsigned long mask) { @@ -308,7 +323,6 @@ static void l2x0_disable(void) static void l2x0_unlock(u32 cache_id) { int lockregs; - int i; switch (cache_id & L2X0_CACHE_ID_PART_MASK) { case L2X0_CACHE_ID_PART_L310: @@ -323,12 +337,7 @@ static void l2x0_unlock(u32 cache_id) break; } - for (i = 0; i < lockregs; i++) { - writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + - i * L2X0_LOCKDOWN_STRIDE); - writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + - i * L2X0_LOCKDOWN_STRIDE); - } + l2c_unlock(l2x0_base, lockregs); } void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) -- cgit v1.2.3 From df5dd4c6e27081bce2c68cdc2e57a93ea998b63e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:56 +0000 Subject: ARM: l2c: provide generic helper for way-based operations Provide a generic helper function for way based operations. These are always background operations, and thus have to be waited for before a new operation is commenced. This helper extracts that requirement from several locations in the code. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index a1313d20f205..1c3a23318f53 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -70,6 +70,12 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val) outer_cache.set_debug(val); } +static void __l2c_op_way(void __iomem *reg) +{ + writel_relaxed(l2x0_way_mask, reg); + cache_wait_way(reg, l2x0_way_mask); +} + static inline void l2c_unlock(void __iomem *base, unsigned num) { unsigned i; @@ -166,8 +172,7 @@ static void l2x0_cache_sync(void) static void __l2x0_flush_all(void) { debug_writel(0x03); - writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); - cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); + __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); cache_sync(); debug_writel(0x00); } @@ -188,8 +193,7 @@ static void l2x0_clean_all(void) /* clean all ways */ raw_spin_lock_irqsave(&l2x0_lock, flags); - writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); - cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); + __l2c_op_way(l2x0_base + L2X0_CLEAN_WAY); cache_sync(); raw_spin_unlock_irqrestore(&l2x0_lock, flags); } @@ -202,8 +206,7 @@ static void l2x0_inv_all(void) raw_spin_lock_irqsave(&l2x0_lock, flags); /* Invalidating when L2 is enabled is a nono */ BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN); - writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); - cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); + __l2c_op_way(l2x0_base + L2X0_INV_WAY); cache_sync(); raw_spin_unlock_irqrestore(&l2x0_lock, flags); } -- cgit v1.2.3 From 83841fe1fb0c4316af89ab85d3528702724a33f4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:14 +0000 Subject: ARM: l2c: rename cache_wait_way() cache_wait_way() is actually used to wait for a particular mask to report clear; it's not really got much to do with cache ways at all. Indeed, it gets used to wait for the C bit to clear on older caches. Rename this with a more generic function name which better reflects its purpose: l2c_wait_mask(). Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 1c3a23318f53..29ee7f692801 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -53,7 +53,7 @@ static bool of_init = false; /* * Common code for all cache controllers. */ -static inline void cache_wait_way(void __iomem *reg, unsigned long mask) +static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask) { /* wait for cache operation by line or way to complete */ while (readl_relaxed(reg) & mask) @@ -73,7 +73,7 @@ static inline void l2c_set_debug(void __iomem *base, unsigned long val) static void __l2c_op_way(void __iomem *reg) { writel_relaxed(l2x0_way_mask, reg); - cache_wait_way(reg, l2x0_way_mask); + l2c_wait_mask(reg, l2x0_way_mask); } static inline void l2c_unlock(void __iomem *base, unsigned num) @@ -94,7 +94,7 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask) /* cache operations by line are atomic on PL310 */ } #else -#define cache_wait cache_wait_way +#define cache_wait l2c_wait_mask #endif static inline void cache_sync(void) -- cgit v1.2.3 From 14b882cfa3f9db3430037dca6038e161eda953a1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:49 +0000 Subject: ARM: l2c: add and use L2C revision constants The revision namespace is specific to the L2 cache part, so don't name these with generic identifiers, use a part specific identifier. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 29ee7f692801..c39602ef2cdd 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -374,7 +374,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) /* Unmapped register. */ sync_reg_offset = L2X0_DUMMY_REG; #endif - if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L2X0_CACHE_ID_RTL_R3P0) + if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0) outer_cache.set_debug = pl310_set_debug; break; case L2X0_CACHE_ID_PART_L210: @@ -768,7 +768,7 @@ static void __init pl310_save(void) l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base + L2X0_ADDR_FILTER_START); - if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { + if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { /* * From r2p0, there is Prefetch offset/control register */ @@ -777,7 +777,7 @@ static void __init pl310_save(void) /* * From r3p0, there is Power control register */ - if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) + if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base + L2X0_POWER_CTRL); } @@ -830,10 +830,10 @@ static void pl310_resume(void) l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK; - if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { + if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { writel_relaxed(l2x0_saved_regs.prefetch_ctrl, l2x0_base + L2X0_PREFETCH_CTRL); - if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) + if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) writel_relaxed(l2x0_saved_regs.pwr_ctrl, l2x0_base + L2X0_POWER_CTRL); } -- cgit v1.2.3 From 96054b0a99f4b7104c02e5521ee5c0d7b1fb09bc Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:52 +0000 Subject: ARM: l2c: clean up OF initialisation a bit Rather than having a boolean and other tricks to disable some bits of l2x0_init(), split this function into two parts: a common part shared between OF and non-OF, and the non-OF part. The common part can take a block of function pointers, and the cache ID (to cope with Aurora's DT specified ID.) Eliminate the redundant setting of l2x0_base in the OF case, moving it to the non-OF init function. This allows us to localise the OF-specific initialisation handling from the non-OF handling. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 66 +++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index c39602ef2cdd..0d83b24b7971 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -42,14 +42,8 @@ static u32 l2x0_way_mask; /* Bitmask of active ways */ static u32 l2x0_size; static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; -/* Aurora don't have the cache ID register available, so we have to - * pass it though the device tree */ -static u32 cache_id_part_number_from_dt; - struct l2x0_regs l2x0_saved_regs; -static bool of_init = false; - /* * Common code for all cache controllers. */ @@ -343,20 +337,26 @@ static void l2x0_unlock(u32 cache_id) l2c_unlock(l2x0_base, lockregs); } -void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) +static const struct l2c_init_data l2x0_init_fns __initconst = { + .outer_cache = { + .inv_range = l2x0_inv_range, + .clean_range = l2x0_clean_range, + .flush_range = l2x0_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + }, +}; + +static void __init __l2c_init(const struct l2c_init_data *data, + u32 aux_val, u32 aux_mask, u32 cache_id) { u32 aux; - u32 cache_id; u32 way_size = 0; int ways; int way_size_shift = L2X0_WAY_SIZE_SHIFT; const char *type; - l2x0_base = base; - if (cache_id_part_number_from_dt) - cache_id = cache_id_part_number_from_dt; - else - cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); aux &= aux_mask; @@ -374,8 +374,6 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) /* Unmapped register. */ sync_reg_offset = L2X0_DUMMY_REG; #endif - if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0) - outer_cache.set_debug = pl310_set_debug; break; case L2X0_CACHE_ID_PART_L210: ways = (aux >> 13) & 0xf; @@ -430,23 +428,35 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) /* Save the value for resuming. */ l2x0_saved_regs.aux_ctrl = aux; - if (!of_init) { - outer_cache.inv_range = l2x0_inv_range; - outer_cache.clean_range = l2x0_clean_range; - outer_cache.flush_range = l2x0_flush_range; - outer_cache.sync = l2x0_cache_sync; - outer_cache.flush_all = l2x0_flush_all; - outer_cache.disable = l2x0_disable; - } + outer_cache = data->outer_cache; + + if ((cache_id & L2X0_CACHE_ID_PART_MASK) == L2X0_CACHE_ID_PART_L310 && + (cache_id & L2X0_CACHE_ID_RTL_MASK) <= L310_CACHE_ID_RTL_R3P0) + outer_cache.set_debug = pl310_set_debug; pr_info("%s cache controller enabled\n", type); pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n", ways, cache_id, aux, l2x0_size >> 10); } +void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) +{ + u32 cache_id; + + l2x0_base = base; + + cache_id = readl_relaxed(base + L2X0_CACHE_ID); + + __l2c_init(&l2x0_init_fns, aux_val, aux_mask, cache_id); +} + #ifdef CONFIG_OF static int l2_wt_override; +/* Aurora don't have the cache ID register available, so we have to + * pass it though the device tree */ +static u32 cache_id_part_number_from_dt; + /* * Note that the end addresses passed to Linux primitives are * noninclusive, while the hardware cache range operations use @@ -985,6 +995,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) const struct l2c_init_data *data; struct device_node *np; struct resource res; + u32 cache_id; np = of_find_matching_node(NULL, l2x0_ids); if (!np) @@ -1015,9 +1026,12 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) if (data->save) data->save(); - of_init = true; - memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache)); - l2x0_init(l2x0_base, aux_val, aux_mask); + if (cache_id_part_number_from_dt) + cache_id = cache_id_part_number_from_dt; + else + cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); + + __l2c_init(data, aux_val, aux_mask, cache_id); return 0; } -- cgit v1.2.3 From 9846dfc98f0e3482e3d0df91bea67ead728301ac Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:55 +0000 Subject: ARM: l2c: pass iomem address into data->save function Pass the iomem address into this function so we don't have to keep accessing it from a global. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 0d83b24b7971..08f9cade028a 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -30,7 +30,7 @@ struct l2c_init_data { void (*of_parse)(const struct device_node *, u32 *, u32 *); - void (*save)(void); + void (*save)(void __iomem *); struct outer_cache_fns outer_cache; }; @@ -764,47 +764,47 @@ static void __init pl310_of_parse(const struct device_node *np, } } -static void __init pl310_save(void) +static void __init pl310_save(void __iomem *base) { - u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & + u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK; - l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base + + l2x0_saved_regs.tag_latency = readl_relaxed(base + L2X0_TAG_LATENCY_CTRL); - l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base + + l2x0_saved_regs.data_latency = readl_relaxed(base + L2X0_DATA_LATENCY_CTRL); - l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base + + l2x0_saved_regs.filter_end = readl_relaxed(base + L2X0_ADDR_FILTER_END); - l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base + + l2x0_saved_regs.filter_start = readl_relaxed(base + L2X0_ADDR_FILTER_START); if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { /* * From r2p0, there is Prefetch offset/control register */ - l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base + + l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base + L2X0_PREFETCH_CTRL); /* * From r3p0, there is Power control register */ if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) - l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base + + l2x0_saved_regs.pwr_ctrl = readl_relaxed(base + L2X0_POWER_CTRL); } } -static void aurora_save(void) +static void aurora_save(void __iomem *base) { - l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL); - l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); + l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); + l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); } -static void __init tauros3_save(void) +static void __init tauros3_save(void __iomem *base) { l2x0_saved_regs.aux2_ctrl = - readl_relaxed(l2x0_base + TAUROS3_AUX2_CTRL); + readl_relaxed(base + TAUROS3_AUX2_CTRL); l2x0_saved_regs.prefetch_ctrl = - readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); + readl_relaxed(base + L2X0_PREFETCH_CTRL); } static void l2x0_resume(void) @@ -1024,7 +1024,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) } if (data->save) - data->save(); + data->save(l2x0_base); if (cache_id_part_number_from_dt) cache_id = cache_id_part_number_from_dt; -- cgit v1.2.3 From c40e7eb6c0b08fbc905ac1bec516e6f59ffd4d02 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:04 +0000 Subject: ARM: l2c: move l2c save function to __l2c_init() There's no reason this functionality should be specific to DT, so move it into the common initialisation function. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 08f9cade028a..3b6213838054 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -357,6 +357,13 @@ static void __init __l2c_init(const struct l2c_init_data *data, int way_size_shift = L2X0_WAY_SIZE_SHIFT; const char *type; + /* + * It is strange to save the register state before initialisation, + * but hey, this is what the DT implementations decided to do. + */ + if (data->save) + data->save(l2x0_base); + aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); aux &= aux_mask; @@ -1023,9 +1030,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) aurora_broadcast_l2_commands(); } - if (data->save) - data->save(l2x0_base); - if (cache_id_part_number_from_dt) cache_id = cache_id_part_number_from_dt; else -- cgit v1.2.3 From da3627fbda8983e96fb087c358fab4d7661fd97d Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:06 +0000 Subject: ARM: l2c: group implementation specific code together Back in the mists of time, someone decided that it would be a good idea to group like functions together - so all the save functions in one place, all the resume functions in another, all the OF parsing functions some place else. This makes it difficult to get an overview on what a particular implementation is doing - grouping an implementations specific functions together makes more sense, because you can see what it's doing without the clutter of other implementations. Organise it according to implementation. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 502 +++++++++++++++++++++++------------------------ 1 file changed, 251 insertions(+), 251 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 3b6213838054..09fe0f5eada5 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -464,6 +464,175 @@ static int l2_wt_override; * pass it though the device tree */ static u32 cache_id_part_number_from_dt; +static void __init l2x0_of_parse(const struct device_node *np, + u32 *aux_val, u32 *aux_mask) +{ + u32 data[2] = { 0, 0 }; + u32 tag = 0; + u32 dirty = 0; + u32 val = 0, mask = 0; + + of_property_read_u32(np, "arm,tag-latency", &tag); + if (tag) { + mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; + val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; + } + + of_property_read_u32_array(np, "arm,data-latency", + data, ARRAY_SIZE(data)); + if (data[0] && data[1]) { + mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | + L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; + val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | + ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); + } + + of_property_read_u32(np, "arm,dirty-latency", &dirty); + if (dirty) { + mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; + val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; + } + + *aux_val &= ~mask; + *aux_val |= val; + *aux_mask &= ~mask; +} + +static void l2x0_resume(void) +{ + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { + /* restore aux ctrl and enable l2 */ + l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID)); + + writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base + + L2X0_AUX_CTRL); + + l2x0_inv_all(); + + writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); + } +} + +static const struct l2c_init_data of_l2x0_data __initconst = { + .of_parse = l2x0_of_parse, + .outer_cache = { + .inv_range = l2x0_inv_range, + .clean_range = l2x0_clean_range, + .flush_range = l2x0_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = l2x0_resume, + }, +}; + +static void __init pl310_of_parse(const struct device_node *np, + u32 *aux_val, u32 *aux_mask) +{ + u32 data[3] = { 0, 0, 0 }; + u32 tag[3] = { 0, 0, 0 }; + u32 filter[2] = { 0, 0 }; + + of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); + if (tag[0] && tag[1] && tag[2]) + writel_relaxed( + ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | + ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | + ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), + l2x0_base + L2X0_TAG_LATENCY_CTRL); + + of_property_read_u32_array(np, "arm,data-latency", + data, ARRAY_SIZE(data)); + if (data[0] && data[1] && data[2]) + writel_relaxed( + ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | + ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | + ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), + l2x0_base + L2X0_DATA_LATENCY_CTRL); + + of_property_read_u32_array(np, "arm,filter-ranges", + filter, ARRAY_SIZE(filter)); + if (filter[1]) { + writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), + l2x0_base + L2X0_ADDR_FILTER_END); + writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN, + l2x0_base + L2X0_ADDR_FILTER_START); + } +} + +static void __init pl310_save(void __iomem *base) +{ + u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) & + L2X0_CACHE_ID_RTL_MASK; + + l2x0_saved_regs.tag_latency = readl_relaxed(base + + L2X0_TAG_LATENCY_CTRL); + l2x0_saved_regs.data_latency = readl_relaxed(base + + L2X0_DATA_LATENCY_CTRL); + l2x0_saved_regs.filter_end = readl_relaxed(base + + L2X0_ADDR_FILTER_END); + l2x0_saved_regs.filter_start = readl_relaxed(base + + L2X0_ADDR_FILTER_START); + + if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { + /* + * From r2p0, there is Prefetch offset/control register + */ + l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base + + L2X0_PREFETCH_CTRL); + /* + * From r3p0, there is Power control register + */ + if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) + l2x0_saved_regs.pwr_ctrl = readl_relaxed(base + + L2X0_POWER_CTRL); + } +} + +static void pl310_resume(void) +{ + u32 l2x0_revision; + + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { + /* restore pl310 setup */ + writel_relaxed(l2x0_saved_regs.tag_latency, + l2x0_base + L2X0_TAG_LATENCY_CTRL); + writel_relaxed(l2x0_saved_regs.data_latency, + l2x0_base + L2X0_DATA_LATENCY_CTRL); + writel_relaxed(l2x0_saved_regs.filter_end, + l2x0_base + L2X0_ADDR_FILTER_END); + writel_relaxed(l2x0_saved_regs.filter_start, + l2x0_base + L2X0_ADDR_FILTER_START); + + l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & + L2X0_CACHE_ID_RTL_MASK; + + if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { + writel_relaxed(l2x0_saved_regs.prefetch_ctrl, + l2x0_base + L2X0_PREFETCH_CTRL); + if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) + writel_relaxed(l2x0_saved_regs.pwr_ctrl, + l2x0_base + L2X0_POWER_CTRL); + } + } + + l2x0_resume(); +} + +static const struct l2c_init_data of_pl310_data __initconst = { + .of_parse = pl310_of_parse, + .save = pl310_save, + .outer_cache = { + .inv_range = l2x0_inv_range, + .clean_range = l2x0_clean_range, + .flush_range = l2x0_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = pl310_resume, + }, +}; + /* * Note that the end addresses passed to Linux primitives are * noninclusive, while the hardware cache range operations use @@ -562,6 +731,75 @@ static void aurora_flush_range(unsigned long start, unsigned long end) } } +static void aurora_save(void __iomem *base) +{ + l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); + l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); +} + +static void aurora_resume(void) +{ + if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { + writel_relaxed(l2x0_saved_regs.aux_ctrl, + l2x0_base + L2X0_AUX_CTRL); + writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL); + } +} + +static void __init aurora_broadcast_l2_commands(void) +{ + __u32 u; + /* Enable Broadcasting of cache commands to L2*/ + __asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u)); + u |= AURORA_CTRL_FW; /* Set the FW bit */ + __asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u)); + isb(); +} + +static void __init aurora_of_parse(const struct device_node *np, + u32 *aux_val, u32 *aux_mask) +{ + u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; + u32 mask = AURORA_ACR_REPLACEMENT_MASK; + + of_property_read_u32(np, "cache-id-part", + &cache_id_part_number_from_dt); + + /* Determine and save the write policy */ + l2_wt_override = of_property_read_bool(np, "wt-override"); + + if (l2_wt_override) { + val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; + mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; + } + + *aux_val &= ~mask; + *aux_val |= val; + *aux_mask &= ~mask; +} + +static const struct l2c_init_data of_aurora_with_outer_data __initconst = { + .of_parse = aurora_of_parse, + .save = aurora_save, + .outer_cache = { + .inv_range = aurora_inv_range, + .clean_range = aurora_clean_range, + .flush_range = aurora_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = aurora_resume, + }, +}; + +static const struct l2c_init_data of_aurora_no_outer_data __initconst = { + .of_parse = aurora_of_parse, + .save = aurora_save, + .outer_cache = { + .resume = aurora_resume, + }, +}; + /* * For certain Broadcom SoCs, depending on the address range, different offsets * need to be added to the address before passing it to L2 for @@ -703,108 +941,19 @@ static void bcm_flush_range(unsigned long start, unsigned long end) new_end); } -static void __init l2x0_of_parse(const struct device_node *np, - u32 *aux_val, u32 *aux_mask) -{ - u32 data[2] = { 0, 0 }; - u32 tag = 0; - u32 dirty = 0; - u32 val = 0, mask = 0; - - of_property_read_u32(np, "arm,tag-latency", &tag); - if (tag) { - mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; - val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; - } - - of_property_read_u32_array(np, "arm,data-latency", - data, ARRAY_SIZE(data)); - if (data[0] && data[1]) { - mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | - L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; - val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | - ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); - } - - of_property_read_u32(np, "arm,dirty-latency", &dirty); - if (dirty) { - mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; - val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; - } - - *aux_val &= ~mask; - *aux_val |= val; - *aux_mask &= ~mask; -} - -static void __init pl310_of_parse(const struct device_node *np, - u32 *aux_val, u32 *aux_mask) -{ - u32 data[3] = { 0, 0, 0 }; - u32 tag[3] = { 0, 0, 0 }; - u32 filter[2] = { 0, 0 }; - - of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); - if (tag[0] && tag[1] && tag[2]) - writel_relaxed( - ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | - ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | - ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), - l2x0_base + L2X0_TAG_LATENCY_CTRL); - - of_property_read_u32_array(np, "arm,data-latency", - data, ARRAY_SIZE(data)); - if (data[0] && data[1] && data[2]) - writel_relaxed( - ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | - ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | - ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), - l2x0_base + L2X0_DATA_LATENCY_CTRL); - - of_property_read_u32_array(np, "arm,filter-ranges", - filter, ARRAY_SIZE(filter)); - if (filter[1]) { - writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), - l2x0_base + L2X0_ADDR_FILTER_END); - writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN, - l2x0_base + L2X0_ADDR_FILTER_START); - } -} - -static void __init pl310_save(void __iomem *base) -{ - u32 l2x0_revision = readl_relaxed(base + L2X0_CACHE_ID) & - L2X0_CACHE_ID_RTL_MASK; - - l2x0_saved_regs.tag_latency = readl_relaxed(base + - L2X0_TAG_LATENCY_CTRL); - l2x0_saved_regs.data_latency = readl_relaxed(base + - L2X0_DATA_LATENCY_CTRL); - l2x0_saved_regs.filter_end = readl_relaxed(base + - L2X0_ADDR_FILTER_END); - l2x0_saved_regs.filter_start = readl_relaxed(base + - L2X0_ADDR_FILTER_START); - - if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { - /* - * From r2p0, there is Prefetch offset/control register - */ - l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base + - L2X0_PREFETCH_CTRL); - /* - * From r3p0, there is Power control register - */ - if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) - l2x0_saved_regs.pwr_ctrl = readl_relaxed(base + - L2X0_POWER_CTRL); - } -} - -static void aurora_save(void __iomem *base) -{ - l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); - l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); -} +static const struct l2c_init_data of_bcm_l2x0_data __initconst = { + .of_parse = pl310_of_parse, + .save = pl310_save, + .outer_cache = { + .inv_range = bcm_inv_range, + .clean_range = bcm_clean_range, + .flush_range = bcm_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + .resume = pl310_resume, + }, +}; static void __init tauros3_save(void __iomem *base) { @@ -814,60 +963,6 @@ static void __init tauros3_save(void __iomem *base) readl_relaxed(base + L2X0_PREFETCH_CTRL); } -static void l2x0_resume(void) -{ - if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { - /* restore aux ctrl and enable l2 */ - l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID)); - - writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base + - L2X0_AUX_CTRL); - - l2x0_inv_all(); - - writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); - } -} - -static void pl310_resume(void) -{ - u32 l2x0_revision; - - if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { - /* restore pl310 setup */ - writel_relaxed(l2x0_saved_regs.tag_latency, - l2x0_base + L2X0_TAG_LATENCY_CTRL); - writel_relaxed(l2x0_saved_regs.data_latency, - l2x0_base + L2X0_DATA_LATENCY_CTRL); - writel_relaxed(l2x0_saved_regs.filter_end, - l2x0_base + L2X0_ADDR_FILTER_END); - writel_relaxed(l2x0_saved_regs.filter_start, - l2x0_base + L2X0_ADDR_FILTER_START); - - l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & - L2X0_CACHE_ID_RTL_MASK; - - if (l2x0_revision >= L310_CACHE_ID_RTL_R2P0) { - writel_relaxed(l2x0_saved_regs.prefetch_ctrl, - l2x0_base + L2X0_PREFETCH_CTRL); - if (l2x0_revision >= L310_CACHE_ID_RTL_R3P0) - writel_relaxed(l2x0_saved_regs.pwr_ctrl, - l2x0_base + L2X0_POWER_CTRL); - } - } - - l2x0_resume(); -} - -static void aurora_resume(void) -{ - if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { - writel_relaxed(l2x0_saved_regs.aux_ctrl, - l2x0_base + L2X0_AUX_CTRL); - writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL); - } -} - static void tauros3_resume(void) { if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { @@ -880,87 +975,6 @@ static void tauros3_resume(void) l2x0_resume(); } -static void __init aurora_broadcast_l2_commands(void) -{ - __u32 u; - /* Enable Broadcasting of cache commands to L2*/ - __asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u)); - u |= AURORA_CTRL_FW; /* Set the FW bit */ - __asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u)); - isb(); -} - -static void __init aurora_of_parse(const struct device_node *np, - u32 *aux_val, u32 *aux_mask) -{ - u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; - u32 mask = AURORA_ACR_REPLACEMENT_MASK; - - of_property_read_u32(np, "cache-id-part", - &cache_id_part_number_from_dt); - - /* Determine and save the write policy */ - l2_wt_override = of_property_read_bool(np, "wt-override"); - - if (l2_wt_override) { - val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; - mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; - } - - *aux_val &= ~mask; - *aux_val |= val; - *aux_mask &= ~mask; -} - -static const struct l2c_init_data of_pl310_data __initconst = { - .of_parse = pl310_of_parse, - .save = pl310_save, - .outer_cache = { - .inv_range = l2x0_inv_range, - .clean_range = l2x0_clean_range, - .flush_range = l2x0_flush_range, - .flush_all = l2x0_flush_all, - .disable = l2x0_disable, - .sync = l2x0_cache_sync, - .resume = pl310_resume, - }, -}; - -static const struct l2c_init_data of_l2x0_data __initconst = { - .of_parse = l2x0_of_parse, - .outer_cache = { - .inv_range = l2x0_inv_range, - .clean_range = l2x0_clean_range, - .flush_range = l2x0_flush_range, - .flush_all = l2x0_flush_all, - .disable = l2x0_disable, - .sync = l2x0_cache_sync, - .resume = l2x0_resume, - }, -}; - -static const struct l2c_init_data of_aurora_with_outer_data __initconst = { - .of_parse = aurora_of_parse, - .save = aurora_save, - .outer_cache = { - .inv_range = aurora_inv_range, - .clean_range = aurora_clean_range, - .flush_range = aurora_flush_range, - .flush_all = l2x0_flush_all, - .disable = l2x0_disable, - .sync = l2x0_cache_sync, - .resume = aurora_resume, - }, -}; - -static const struct l2c_init_data of_aurora_no_outer_data __initconst = { - .of_parse = aurora_of_parse, - .save = aurora_save, - .outer_cache = { - .resume = aurora_resume, - }, -}; - static const struct l2c_init_data of_tauros3_data __initconst = { .save = tauros3_save, /* Tauros3 broadcasts L1 cache operations to L2 */ @@ -969,20 +983,6 @@ static const struct l2c_init_data of_tauros3_data __initconst = { }, }; -static const struct l2c_init_data of_bcm_l2x0_data __initconst = { - .of_parse = pl310_of_parse, - .save = pl310_save, - .outer_cache = { - .inv_range = bcm_inv_range, - .clean_range = bcm_clean_range, - .flush_range = bcm_flush_range, - .flush_all = l2x0_flush_all, - .disable = l2x0_disable, - .sync = l2x0_cache_sync, - .resume = pl310_resume, - }, -}; - #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } static const struct of_device_id l2x0_ids[] __initconst = { L2C_ID("arm,l210-cache", of_l2x0_data), -- cgit v1.2.3 From 3b8bad5758113df34076dd868b6cab502bd4ee9a Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:57 +0000 Subject: ARM: l2c: provide enable method Providing an enable method gives L2 cache controllers a chance to do special handling at enable time. This allows us to remove a hack in l2x0_unlock() for Marvell Aurora L2 caches. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 80 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 09fe0f5eada5..2adb82e7f4b3 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -29,7 +29,9 @@ #include "cache-aurora-l2.h" struct l2c_init_data { + unsigned num_lock; void (*of_parse)(const struct device_node *, u32 *, u32 *); + void (*enable)(void __iomem *, u32, unsigned); void (*save)(void __iomem *); struct outer_cache_fns outer_cache; }; @@ -82,6 +84,36 @@ static inline void l2c_unlock(void __iomem *base, unsigned num) } } +/* + * Enable the L2 cache controller. This function must only be + * called when the cache controller is known to be disabled. + */ +static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) +{ + unsigned long flags; + + l2c_unlock(base, num_lock); + + writel_relaxed(aux, base + L2X0_AUX_CTRL); + + local_irq_save(flags); + __l2c_op_way(base + L2X0_INV_WAY); + writel_relaxed(0, base + sync_reg_offset); + l2c_wait_mask(base + sync_reg_offset, 1); + local_irq_restore(flags); + + writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL); +} + +static void l2c_disable(void) +{ + void __iomem *base = l2x0_base; + + outer_cache.flush_all(); + writel_relaxed(0, base + L2X0_CTRL); + dsb(st); +} + #ifdef CONFIG_CACHE_PL310 static inline void cache_wait(void __iomem *reg, unsigned long mask) { @@ -325,9 +357,6 @@ static void l2x0_unlock(u32 cache_id) case L2X0_CACHE_ID_PART_L310: lockregs = 8; break; - case AURORA_CACHE_ID: - lockregs = 4; - break; default: /* L210 and unknown types */ lockregs = 1; @@ -337,7 +366,22 @@ static void l2x0_unlock(u32 cache_id) l2c_unlock(l2x0_base, lockregs); } +static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock) +{ + /* Make sure that I&D is not locked down when starting */ + l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID)); + + /* l2x0 controller is disabled */ + writel_relaxed(aux, base + L2X0_AUX_CTRL); + + l2x0_inv_all(); + + /* enable L2X0 */ + writel_relaxed(L2X0_CTRL_EN, base + L2X0_CTRL); +} + static const struct l2c_init_data l2x0_init_fns __initconst = { + .enable = l2x0_enable, .outer_cache = { .inv_range = l2x0_inv_range, .clean_range = l2x0_clean_range, @@ -412,22 +456,11 @@ static void __init __l2c_init(const struct l2c_init_data *data, l2x0_size = ways * way_size * SZ_1K; /* - * Check if l2x0 controller is already enabled. - * If you are booting from non-secure mode - * accessing the below registers will fault. + * Check if l2x0 controller is already enabled. If we are booting + * in non-secure mode accessing the below registers will fault. */ - if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { - /* Make sure that I&D is not locked down when starting */ - l2x0_unlock(cache_id); - - /* l2x0 controller is disabled */ - writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); - - l2x0_inv_all(); - - /* enable L2X0 */ - writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); - } + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) + data->enable(l2x0_base, aux, data->num_lock); /* Re-read it in case some bits are reserved. */ aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); @@ -515,6 +548,7 @@ static void l2x0_resume(void) static const struct l2c_init_data of_l2x0_data __initconst = { .of_parse = l2x0_of_parse, + .enable = l2x0_enable, .outer_cache = { .inv_range = l2x0_inv_range, .clean_range = l2x0_clean_range, @@ -620,7 +654,9 @@ static void pl310_resume(void) } static const struct l2c_init_data of_pl310_data __initconst = { + .num_lock = 8, .of_parse = pl310_of_parse, + .enable = l2c_enable, .save = pl310_save, .outer_cache = { .inv_range = l2x0_inv_range, @@ -779,7 +815,9 @@ static void __init aurora_of_parse(const struct device_node *np, } static const struct l2c_init_data of_aurora_with_outer_data __initconst = { + .num_lock = 4, .of_parse = aurora_of_parse, + .enable = l2c_enable, .save = aurora_save, .outer_cache = { .inv_range = aurora_inv_range, @@ -793,7 +831,9 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { }; static const struct l2c_init_data of_aurora_no_outer_data __initconst = { + .num_lock = 4, .of_parse = aurora_of_parse, + .enable = l2c_enable, .save = aurora_save, .outer_cache = { .resume = aurora_resume, @@ -942,7 +982,9 @@ static void bcm_flush_range(unsigned long start, unsigned long end) } static const struct l2c_init_data of_bcm_l2x0_data __initconst = { + .num_lock = 8, .of_parse = pl310_of_parse, + .enable = l2c_enable, .save = pl310_save, .outer_cache = { .inv_range = bcm_inv_range, @@ -976,6 +1018,8 @@ static void tauros3_resume(void) } static const struct l2c_init_data of_tauros3_data __initconst = { + .num_lock = 8, + .enable = l2c_enable, .save = tauros3_save, /* Tauros3 broadcasts L1 cache operations to L2 */ .outer_cache = { -- cgit v1.2.3 From 17f3f99fab43ad17ae1adfc724e5ebaca9635902 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 17 Mar 2014 17:15:02 +0000 Subject: ARM: l2c: write auxctrl register before unlocking We should write the auxillary control register before unlocking: the write may be necessary to enable non-secure access to the lock registers. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 2adb82e7f4b3..fc609550b7fa 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -92,10 +92,10 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) { unsigned long flags; - l2c_unlock(base, num_lock); - writel_relaxed(aux, base + L2X0_AUX_CTRL); + l2c_unlock(base, num_lock); + local_irq_save(flags); __l2c_op_way(base + L2X0_INV_WAY); writel_relaxed(0, base + sync_reg_offset); @@ -368,12 +368,12 @@ static void l2x0_unlock(u32 cache_id) static void l2x0_enable(void __iomem *base, u32 aux, unsigned num_lock) { - /* Make sure that I&D is not locked down when starting */ - l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID)); - /* l2x0 controller is disabled */ writel_relaxed(aux, base + L2X0_AUX_CTRL); + /* Make sure that I&D is not locked down when starting */ + l2x0_unlock(readl_relaxed(base + L2X0_CACHE_ID)); + l2x0_inv_all(); /* enable L2X0 */ -- cgit v1.2.3 From 9a07f27bc5ff2e36400e605d99cc1e129582a0ca Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 17 Mar 2014 20:10:31 +0000 Subject: ARM: l2c: only write the auxiliary control register if required Avoid unnecessary writes to the auxiliary control register if the register already contains the required value. This allows us to avoid invoking the platforms secure monitor code unnecessarily. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index fc609550b7fa..1c947b4c7f05 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -92,7 +92,9 @@ static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) { unsigned long flags; - writel_relaxed(aux, base + L2X0_AUX_CTRL); + /* Only write the aux register if it needs changing */ + if (readl_relaxed(base + L2X0_AUX_CTRL) != aux) + writel_relaxed(aux, base + L2X0_AUX_CTRL); l2c_unlock(base, num_lock); -- cgit v1.2.3 From 40266d6f410a272b76ad861ba0b5ce91d598f606 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:47:59 +0000 Subject: ARM: l2c: move aurora broadcast setup to enable function Rather than having this hacked into the OF initialiation function, we can handle this via the enable function instead. While here, clean up that code and comments a little. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 1c947b4c7f05..5f381af1a7a4 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -784,14 +784,22 @@ static void aurora_resume(void) } } -static void __init aurora_broadcast_l2_commands(void) +/* + * For Aurora cache in no outer mode, enable via the CP15 coprocessor + * broadcasting of cache commands to L2. + */ +static void __init aurora_enable_no_outer(void __iomem *base, u32 aux, + unsigned num_lock) { - __u32 u; - /* Enable Broadcasting of cache commands to L2*/ - __asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u)); + u32 u; + + asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u)); u |= AURORA_CTRL_FW; /* Set the FW bit */ - __asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u)); + asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u)); + isb(); + + l2c_enable(base, aux, num_lock); } static void __init aurora_of_parse(const struct device_node *np, @@ -835,7 +843,7 @@ static const struct l2c_init_data of_aurora_with_outer_data __initconst = { static const struct l2c_init_data of_aurora_no_outer_data __initconst = { .num_lock = 4, .of_parse = aurora_of_parse, - .enable = l2c_enable, + .enable = aurora_enable_no_outer, .save = aurora_save, .outer_cache = { .resume = aurora_resume, @@ -1066,16 +1074,10 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask) data = of_match_node(l2x0_ids, np)->data; /* L2 configuration can only be changed if the cache is disabled */ - if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { + if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) if (data->of_parse) data->of_parse(np, &aux_val, &aux_mask); - /* For aurora cache in no outer mode select the - * correct mode using the coprocessor*/ - if (data == &of_aurora_no_outer_data) - aurora_broadcast_l2_commands(); - } - if (cache_id_part_number_from_dt) cache_id = cache_id_part_number_from_dt; else -- cgit v1.2.3 From 75461f5c8483bee543df30b288787fd3369312b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 15 Mar 2014 16:48:07 +0000 Subject: ARM: l2c: implement fixups for L2 cache controller quirks/errata Rather than putting quirk handling in __l2c_init(), move it out to a separate function which individual implementations can specify. This helps to localise the quirks to those implementations which require them. Signed-off-by: Russell King --- arch/arm/mm/cache-l2x0.c | 112 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 11 deletions(-) (limited to 'arch/arm/mm/cache-l2x0.c') diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 5f381af1a7a4..a544f19c448f 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -32,6 +32,7 @@ struct l2c_init_data { unsigned num_lock; void (*of_parse)(const struct device_node *, u32 *, u32 *); void (*enable)(void __iomem *, u32, unsigned); + void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); void (*save)(void __iomem *); struct outer_cache_fns outer_cache; }; @@ -394,9 +395,80 @@ static const struct l2c_init_data l2x0_init_fns __initconst = { }, }; +/* + * L2C-310 specific code. + * + * Errata: + * 588369: PL310 R0P0->R1P0, fixed R2P0. + * Affects: all clean+invalidate operations + * clean and invalidate skips the invalidate step, so we need to issue + * separate operations. We also require the above debug workaround + * enclosing this code fragment on affected parts. On unaffected parts, + * we must not use this workaround without the debug register writes + * to avoid exposing a problem similar to 727915. + * + * 727915: PL310 R2P0->R3P0, fixed R3P1. + * Affects: clean+invalidate by way + * clean and invalidate by way runs in the background, and a store can + * hit the line between the clean operation and invalidate operation, + * resulting in the store being lost. + * + * 753970: PL310 R3P0, fixed R3P1. + * Affects: sync + * prevents merging writes after the sync operation, until another L2C + * operation is performed (or a number of other conditions.) + * + * 769419: PL310 R0P0->R3P1, fixed R3P2. + * Affects: store buffer + * store buffer is not automatically drained. + */ +static void __init l2c310_fixup(void __iomem *base, u32 cache_id, + struct outer_cache_fns *fns) +{ + unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK; + const char *errata[4]; + unsigned n = 0; + + if (revision <= L310_CACHE_ID_RTL_R3P0) + fns->set_debug = pl310_set_debug; + + if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) && + revision == L310_CACHE_ID_RTL_R3P0) { + sync_reg_offset = L2X0_DUMMY_REG; + errata[n++] = "753970"; + } + + if (IS_ENABLED(CONFIG_PL310_ERRATA_769419)) + errata[n++] = "769419"; + + if (n) { + unsigned i; + + pr_info("L2C-310 errat%s", n > 1 ? "a" : "um"); + for (i = 0; i < n; i++) + pr_cont(" %s", errata[i]); + pr_cont(" enabled\n"); + } +} + +static const struct l2c_init_data l2c310_init_fns __initconst = { + .num_lock = 8, + .enable = l2c_enable, + .fixup = l2c310_fixup, + .outer_cache = { + .inv_range = l2x0_inv_range, + .clean_range = l2x0_clean_range, + .flush_range = l2x0_flush_range, + .flush_all = l2x0_flush_all, + .disable = l2x0_disable, + .sync = l2x0_cache_sync, + }, +}; + static void __init __l2c_init(const struct l2c_init_data *data, u32 aux_val, u32 aux_mask, u32 cache_id) { + struct outer_cache_fns fns; u32 aux; u32 way_size = 0; int ways; @@ -423,23 +495,20 @@ static void __init __l2c_init(const struc