xref: /openbmc/linux/arch/arm/mm/cache-l2x0.c (revision 8e007b36)
145051539SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2382266adSCatalin Marinas /*
3b69a7806SPavel Machek  * arch/arm/mm/cache-l2x0.c - L210/L220/L310 cache controller support
4382266adSCatalin Marinas  *
5382266adSCatalin Marinas  * Copyright (C) 2007 ARM Limited
6382266adSCatalin Marinas  */
78ef418c7SRussell King #include <linux/cpu.h>
88c369264SRob Herring #include <linux/err.h>
9382266adSCatalin Marinas #include <linux/init.h>
108ef418c7SRussell King #include <linux/smp.h>
1107620976SCatalin Marinas #include <linux/spinlock.h>
12f3354ab6SLinus Walleij #include <linux/log2.h>
13fced80c7SRussell King #include <linux/io.h>
148c369264SRob Herring #include <linux/of.h>
158c369264SRob Herring #include <linux/of_address.h>
16382266adSCatalin Marinas 
17382266adSCatalin Marinas #include <asm/cacheflush.h>
188ef418c7SRussell King #include <asm/cp15.h>
194374d649SRussell King #include <asm/cputype.h>
20382266adSCatalin Marinas #include <asm/hardware/cache-l2x0.h>
21921a3fe5SJan Luebbe #include <asm/hardware/cache-aurora-l2.h>
22e68f31f4SSebastian Hesselbarth #include "cache-tauros3.h"
23382266adSCatalin Marinas 
24c02642bcSRussell King struct l2c_init_data {
25051334bdSRussell King 	const char *type;
260493aef4SRussell King 	unsigned way_size_0;
273b8bad57SRussell King 	unsigned num_lock;
28c02642bcSRussell King 	void (*of_parse)(const struct device_node *, u32 *, u32 *);
295b290ec2SRussell King 	void (*enable)(void __iomem *, unsigned);
3075461f5cSRussell King 	void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
319846dfc9SRussell King 	void (*save)(void __iomem *);
326b49241aSTomasz Figa 	void (*configure)(void __iomem *);
33e946a8cbSRussell King 	void (*unlock)(void __iomem *, unsigned);
34c02642bcSRussell King 	struct outer_cache_fns outer_cache;
35c02642bcSRussell King };
36c02642bcSRussell King 
37382266adSCatalin Marinas #define CACHE_LINE_SIZE		32
38382266adSCatalin Marinas 
39382266adSCatalin Marinas static void __iomem *l2x0_base;
406b49241aSTomasz Figa static const struct l2c_init_data *l2x0_data;
41bd31b859SThomas Gleixner static DEFINE_RAW_SPINLOCK(l2x0_lock);
423e175ca4SRussell King static u32 l2x0_way_mask;	/* Bitmask of active ways */
433e175ca4SRussell King static u32 l2x0_size;
44f154fe9bSWill Deacon static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
45382266adSCatalin Marinas 
4691c2ebb9SBarry Song struct l2x0_regs l2x0_saved_regs;
4791c2ebb9SBarry Song 
48471b5e42SChris Brandt static bool l2x0_bresp_disable;
49471b5e42SChris Brandt static bool l2x0_flz_disable;
50471b5e42SChris Brandt 
5137abcdb9SRussell King /*
5237abcdb9SRussell King  * Common code for all cache controllers.
5337abcdb9SRussell King  */
l2c_wait_mask(void __iomem * reg,unsigned long mask)5483841fe1SRussell King static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask)
55382266adSCatalin Marinas {
569a6655e4SCatalin Marinas 	/* wait for cache operation by line or way to complete */
576775a558SCatalin Marinas 	while (readl_relaxed(reg) & mask)
581caf3092SBarry Song 		cpu_relax();
59382266adSCatalin Marinas }
60382266adSCatalin Marinas 
612b2a87a1SRussell King /*
628abd259fSRussell King  * By default, we write directly to secure registers.  Platforms must
638abd259fSRussell King  * override this if they are running non-secure.
648abd259fSRussell King  */
l2c_write_sec(unsigned long val,void __iomem * base,unsigned reg)658abd259fSRussell King static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg)
668abd259fSRussell King {
678abd259fSRussell King 	if (val == readl_relaxed(base + reg))
688abd259fSRussell King 		return;
698abd259fSRussell King 	if (outer_cache.write_sec)
708abd259fSRussell King 		outer_cache.write_sec(val, reg);
718abd259fSRussell King 	else
728abd259fSRussell King 		writel_relaxed(val, base + reg);
738abd259fSRussell King }
748abd259fSRussell King 
758abd259fSRussell King /*
762b2a87a1SRussell King  * This should only be called when we have a requirement that the
772b2a87a1SRussell King  * register be written due to a work-around, as platforms running
782b2a87a1SRussell King  * in non-secure mode may not be able to access this register.
792b2a87a1SRussell King  */
l2c_set_debug(void __iomem * base,unsigned long val)802b2a87a1SRussell King static inline void l2c_set_debug(void __iomem *base, unsigned long val)
812b2a87a1SRussell King {
828abd259fSRussell King 	l2c_write_sec(val, base, L2X0_DEBUG_CTRL);
832b2a87a1SRussell King }
842b2a87a1SRussell King 
__l2c_op_way(void __iomem * reg)85df5dd4c6SRussell King static void __l2c_op_way(void __iomem *reg)
86df5dd4c6SRussell King {
87df5dd4c6SRussell King 	writel_relaxed(l2x0_way_mask, reg);
8883841fe1SRussell King 	l2c_wait_mask(reg, l2x0_way_mask);
89df5dd4c6SRussell King }
90df5dd4c6SRussell King 
l2c_unlock(void __iomem * base,unsigned num)9137abcdb9SRussell King static inline void l2c_unlock(void __iomem *base, unsigned num)
9237abcdb9SRussell King {
9337abcdb9SRussell King 	unsigned i;
9437abcdb9SRussell King 
9537abcdb9SRussell King 	for (i = 0; i < num; i++) {
9637abcdb9SRussell King 		writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_D_BASE +
9737abcdb9SRussell King 			       i * L2X0_LOCKDOWN_STRIDE);
9837abcdb9SRussell King 		writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_I_BASE +
9937abcdb9SRussell King 			       i * L2X0_LOCKDOWN_STRIDE);
10037abcdb9SRussell King 	}
10137abcdb9SRussell King }
10237abcdb9SRussell King 
l2c_configure(void __iomem * base)1036b49241aSTomasz Figa static void l2c_configure(void __iomem *base)
1046b49241aSTomasz Figa {
1057705dd25SRussell King 	l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
1066b49241aSTomasz Figa }
1076b49241aSTomasz Figa 
1083b8bad57SRussell King /*
1093b8bad57SRussell King  * Enable the L2 cache controller.  This function must only be
1103b8bad57SRussell King  * called when the cache controller is known to be disabled.
1113b8bad57SRussell King  */
l2c_enable(void __iomem * base,unsigned num_lock)1125b290ec2SRussell King static void l2c_enable(void __iomem *base, unsigned num_lock)
1133b8bad57SRussell King {
1143b8bad57SRussell King 	unsigned long flags;
1153b8bad57SRussell King 
11650beefdeSRussell King 	if (outer_cache.configure)
11750beefdeSRussell King 		outer_cache.configure(&l2x0_saved_regs);
11850beefdeSRussell King 	else
11950beefdeSRussell King 		l2x0_data->configure(base);
1203b8bad57SRussell King 
121e946a8cbSRussell King 	l2x0_data->unlock(base, num_lock);
12217f3f99fSRussell King 
1233b8bad57SRussell King 	local_irq_save(flags);
1243b8bad57SRussell King 	__l2c_op_way(base + L2X0_INV_WAY);
1253b8bad57SRussell King 	writel_relaxed(0, base + sync_reg_offset);
1263b8bad57SRussell King 	l2c_wait_mask(base + sync_reg_offset, 1);
1273b8bad57SRussell King 	local_irq_restore(flags);
1283b8bad57SRussell King 
1298abd259fSRussell King 	l2c_write_sec(L2X0_CTRL_EN, base, L2X0_CTRL);
1303b8bad57SRussell King }
1313b8bad57SRussell King 
l2c_disable(void)1323b8bad57SRussell King static void l2c_disable(void)
1333b8bad57SRussell King {
1343b8bad57SRussell King 	void __iomem *base = l2x0_base;
1353b8bad57SRussell King 
136b828f960SMark Rutland 	l2x0_pmu_suspend();
137b828f960SMark Rutland 
1383b8bad57SRussell King 	outer_cache.flush_all();
1398abd259fSRussell King 	l2c_write_sec(0, base, L2X0_CTRL);
1403b8bad57SRussell King 	dsb(st);
1413b8bad57SRussell King }
1423b8bad57SRussell King 
l2c_save(void __iomem * base)143ddf7d79bSRussell King static void l2c_save(void __iomem *base)
144ddf7d79bSRussell King {
145ddf7d79bSRussell King 	l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
146ddf7d79bSRussell King }
147ddf7d79bSRussell King 
l2c_resume(void)1486b49241aSTomasz Figa static void l2c_resume(void)
1496b49241aSTomasz Figa {
150d965b0fcSRussell King 	void __iomem *base = l2x0_base;
151d965b0fcSRussell King 
152d965b0fcSRussell King 	/* Do not touch the controller if already enabled. */
153d965b0fcSRussell King 	if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
1545b290ec2SRussell King 		l2c_enable(base, l2x0_data->num_lock);
155b828f960SMark Rutland 
156b828f960SMark Rutland 	l2x0_pmu_resume();
1576b49241aSTomasz Figa }
1586b49241aSTomasz Figa 
15975461f5cSRussell King /*
1606a28cf59SRussell King  * L2C-210 specific code.
1616a28cf59SRussell King  *
1626a28cf59SRussell King  * The L2C-2x0 PA, set/way and sync operations are atomic, but we must
1636a28cf59SRussell King  * ensure that no background operation is running.  The way operations
1646a28cf59SRussell King  * are all background tasks.
1656a28cf59SRussell King  *
1666a28cf59SRussell King  * While a background operation is in progress, any new operation is
1676a28cf59SRussell King  * ignored (unspecified whether this causes an error.)  Thankfully, not
1686a28cf59SRussell King  * used on SMP.
1696a28cf59SRussell King  *
1706a28cf59SRussell King  * Never has a different sync register other than L2X0_CACHE_SYNC, but
1716a28cf59SRussell King  * we use sync_reg_offset here so we can share some of this with L2C-310.
1726a28cf59SRussell King  */
__l2c210_cache_sync(void __iomem * base)1736a28cf59SRussell King static void __l2c210_cache_sync(void __iomem *base)
1746a28cf59SRussell King {
1756a28cf59SRussell King 	writel_relaxed(0, base + sync_reg_offset);
1766a28cf59SRussell King }
1776a28cf59SRussell King 
__l2c210_op_pa_range(void __iomem * reg,unsigned long start,unsigned long end)1786a28cf59SRussell King static void __l2c210_op_pa_range(void __iomem *reg, unsigned long start,
1796a28cf59SRussell King 	unsigned long end)
1806a28cf59SRussell King {
1816a28cf59SRussell King 	while (start < end) {
1826a28cf59SRussell King 		writel_relaxed(start, reg);
1836a28cf59SRussell King 		start += CACHE_LINE_SIZE;
1846a28cf59SRussell King 	}
1856a28cf59SRussell King }
1866a28cf59SRussell King 
l2c210_inv_range(unsigned long start,unsigned long end)1876a28cf59SRussell King static void l2c210_inv_range(unsigned long start, unsigned long end)
1886a28cf59SRussell King {
1896a28cf59SRussell King 	void __iomem *base = l2x0_base;
1906a28cf59SRussell King 
1916a28cf59SRussell King 	if (start & (CACHE_LINE_SIZE - 1)) {
1926a28cf59SRussell King 		start &= ~(CACHE_LINE_SIZE - 1);
1936a28cf59SRussell King 		writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA);
1946a28cf59SRussell King 		start += CACHE_LINE_SIZE;
1956a28cf59SRussell King 	}
1966a28cf59SRussell King 
1976a28cf59SRussell King 	if (end & (CACHE_LINE_SIZE - 1)) {
1986a28cf59SRussell King 		end &= ~(CACHE_LINE_SIZE - 1);
1996a28cf59SRussell King 		writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA);
2006a28cf59SRussell King 	}
2016a28cf59SRussell King 
2026a28cf59SRussell King 	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
2036a28cf59SRussell King 	__l2c210_cache_sync(base);
2046a28cf59SRussell King }
2056a28cf59SRussell King 
l2c210_clean_range(unsigned long start,unsigned long end)2066a28cf59SRussell King static void l2c210_clean_range(unsigned long start, unsigned long end)
2076a28cf59SRussell King {
2086a28cf59SRussell King 	void __iomem *base = l2x0_base;
2096a28cf59SRussell King 
2106a28cf59SRussell King 	start &= ~(CACHE_LINE_SIZE - 1);
2116a28cf59SRussell King 	__l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end);
2126a28cf59SRussell King 	__l2c210_cache_sync(base);
2136a28cf59SRussell King }
2146a28cf59SRussell King 
l2c210_flush_range(unsigned long start,unsigned long end)2156a28cf59SRussell King static void l2c210_flush_range(unsigned long start, unsigned long end)
2166a28cf59SRussell King {
2176a28cf59SRussell King 	void __iomem *base = l2x0_base;
2186a28cf59SRussell King 
2196a28cf59SRussell King 	start &= ~(CACHE_LINE_SIZE - 1);
2206a28cf59SRussell King 	__l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end);
2216a28cf59SRussell King 	__l2c210_cache_sync(base);
2226a28cf59SRussell King }
2236a28cf59SRussell King 
l2c210_flush_all(void)2246a28cf59SRussell King static void l2c210_flush_all(void)
2256a28cf59SRussell King {
2266a28cf59SRussell King 	void __iomem *base = l2x0_base;
2276a28cf59SRussell King 
2286a28cf59SRussell King 	BUG_ON(!irqs_disabled());
2296a28cf59SRussell King 
2306a28cf59SRussell King 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
2316a28cf59SRussell King 	__l2c210_cache_sync(base);
2326a28cf59SRussell King }
2336a28cf59SRussell King 
l2c210_sync(void)2346a28cf59SRussell King static void l2c210_sync(void)
2356a28cf59SRussell King {
2366a28cf59SRussell King 	__l2c210_cache_sync(l2x0_base);
2376a28cf59SRussell King }
2386a28cf59SRussell King 
2396a28cf59SRussell King static const struct l2c_init_data l2c210_data __initconst = {
240051334bdSRussell King 	.type = "L2C-210",
2410493aef4SRussell King 	.way_size_0 = SZ_8K,
2426a28cf59SRussell King 	.num_lock = 1,
2436a28cf59SRussell King 	.enable = l2c_enable,
244ddf7d79bSRussell King 	.save = l2c_save,
24550beefdeSRussell King 	.configure = l2c_configure,
246e946a8cbSRussell King 	.unlock = l2c_unlock,
2476a28cf59SRussell King 	.outer_cache = {
2486a28cf59SRussell King 		.inv_range = l2c210_inv_range,
2496a28cf59SRussell King 		.clean_range = l2c210_clean_range,
2506a28cf59SRussell King 		.flush_range = l2c210_flush_range,
2516a28cf59SRussell King 		.flush_all = l2c210_flush_all,
2526a28cf59SRussell King 		.disable = l2c_disable,
2536a28cf59SRussell King 		.sync = l2c210_sync,
2546b49241aSTomasz Figa 		.resume = l2c_resume,
2556a28cf59SRussell King 	},
2566a28cf59SRussell King };
2576a28cf59SRussell King 
2586a28cf59SRussell King /*
259733c6bbaSRussell King  * L2C-220 specific code.
260733c6bbaSRussell King  *
261733c6bbaSRussell King  * All operations are background operations: they have to be waited for.
262733c6bbaSRussell King  * Conflicting requests generate a slave error (which will cause an
263733c6bbaSRussell King  * imprecise abort.)  Never uses sync_reg_offset, so we hard-code the
264733c6bbaSRussell King  * sync register here.
265733c6bbaSRussell King  *
266733c6bbaSRussell King  * However, we can re-use the l2c210_resume call.
267733c6bbaSRussell King  */
__l2c220_cache_sync(void __iomem * base)268733c6bbaSRussell King static inline void __l2c220_cache_sync(void __iomem *base)
269733c6bbaSRussell King {
270733c6bbaSRussell King 	writel_relaxed(0, base + L2X0_CACHE_SYNC);
271733c6bbaSRussell King 	l2c_wait_mask(base + L2X0_CACHE_SYNC, 1);
272733c6bbaSRussell King }
273733c6bbaSRussell King 
l2c220_op_way(void __iomem * base,unsigned reg)274733c6bbaSRussell King static void l2c220_op_way(void __iomem *base, unsigned reg)
275733c6bbaSRussell King {
276733c6bbaSRussell King 	unsigned long flags;
277733c6bbaSRussell King 
278733c6bbaSRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
279733c6bbaSRussell King 	__l2c_op_way(base + reg);
280733c6bbaSRussell King 	__l2c220_cache_sync(base);
281733c6bbaSRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
282733c6bbaSRussell King }
283733c6bbaSRussell King 
l2c220_op_pa_range(void __iomem * reg,unsigned long start,unsigned long end,unsigned long flags)284733c6bbaSRussell King static unsigned long l2c220_op_pa_range(void __iomem *reg, unsigned long start,
285733c6bbaSRussell King 	unsigned long end, unsigned long flags)
286733c6bbaSRussell King {
287733c6bbaSRussell King 	raw_spinlock_t *lock = &l2x0_lock;
288733c6bbaSRussell King 
289733c6bbaSRussell King 	while (start < end) {
290733c6bbaSRussell King 		unsigned long blk_end = start + min(end - start, 4096UL);
291733c6bbaSRussell King 
292733c6bbaSRussell King 		while (start < blk_end) {
293733c6bbaSRussell King 			l2c_wait_mask(reg, 1);
294733c6bbaSRussell King 			writel_relaxed(start, reg);
295733c6bbaSRussell King 			start += CACHE_LINE_SIZE;
296733c6bbaSRussell King 		}
297733c6bbaSRussell King 
298733c6bbaSRussell King 		if (blk_end < end) {
299733c6bbaSRussell King 			raw_spin_unlock_irqrestore(lock, flags);
300733c6bbaSRussell King 			raw_spin_lock_irqsave(lock, flags);
301733c6bbaSRussell King 		}
302733c6bbaSRussell King 	}
303733c6bbaSRussell King 
304733c6bbaSRussell King 	return flags;
305733c6bbaSRussell King }
306733c6bbaSRussell King 
l2c220_inv_range(unsigned long start,unsigned long end)307733c6bbaSRussell King static void l2c220_inv_range(unsigned long start, unsigned long end)
308733c6bbaSRussell King {
309733c6bbaSRussell King 	void __iomem *base = l2x0_base;
310733c6bbaSRussell King 	unsigned long flags;
311733c6bbaSRussell King 
312733c6bbaSRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
313733c6bbaSRussell King 	if ((start | end) & (CACHE_LINE_SIZE - 1)) {
314733c6bbaSRussell King 		if (start & (CACHE_LINE_SIZE - 1)) {
315733c6bbaSRussell King 			start &= ~(CACHE_LINE_SIZE - 1);
316733c6bbaSRussell King 			writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA);
317733c6bbaSRussell King 			start += CACHE_LINE_SIZE;
318733c6bbaSRussell King 		}
319733c6bbaSRussell King 
320733c6bbaSRussell King 		if (end & (CACHE_LINE_SIZE - 1)) {
321733c6bbaSRussell King 			end &= ~(CACHE_LINE_SIZE - 1);
322733c6bbaSRussell King 			l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
323733c6bbaSRussell King 			writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA);
324733c6bbaSRussell King 		}
325733c6bbaSRussell King 	}
326733c6bbaSRussell King 
327733c6bbaSRussell King 	flags = l2c220_op_pa_range(base + L2X0_INV_LINE_PA,
328733c6bbaSRussell King 				   start, end, flags);
329733c6bbaSRussell King 	l2c_wait_mask(base + L2X0_INV_LINE_PA, 1);
330733c6bbaSRussell King 	__l2c220_cache_sync(base);
331733c6bbaSRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
332733c6bbaSRussell King }
333733c6bbaSRussell King 
l2c220_clean_range(unsigned long start,unsigned long end)334733c6bbaSRussell King static void l2c220_clean_range(unsigned long start, unsigned long end)
335733c6bbaSRussell King {
336733c6bbaSRussell King 	void __iomem *base = l2x0_base;
337733c6bbaSRussell King 	unsigned long flags;
338733c6bbaSRussell King 
339733c6bbaSRussell King 	start &= ~(CACHE_LINE_SIZE - 1);
340733c6bbaSRussell King 	if ((end - start) >= l2x0_size) {
341733c6bbaSRussell King 		l2c220_op_way(base, L2X0_CLEAN_WAY);
342733c6bbaSRussell King 		return;
343733c6bbaSRussell King 	}
344733c6bbaSRussell King 
345733c6bbaSRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
346733c6bbaSRussell King 	flags = l2c220_op_pa_range(base + L2X0_CLEAN_LINE_PA,
347733c6bbaSRussell King 				   start, end, flags);
348733c6bbaSRussell King 	l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
349733c6bbaSRussell King 	__l2c220_cache_sync(base);
350733c6bbaSRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
351733c6bbaSRussell King }
352733c6bbaSRussell King 
l2c220_flush_range(unsigned long start,unsigned long end)353733c6bbaSRussell King static void l2c220_flush_range(unsigned long start, unsigned long end)
354733c6bbaSRussell King {
355733c6bbaSRussell King 	void __iomem *base = l2x0_base;
356733c6bbaSRussell King 	unsigned long flags;
357733c6bbaSRussell King 
358733c6bbaSRussell King 	start &= ~(CACHE_LINE_SIZE - 1);
359733c6bbaSRussell King 	if ((end - start) >= l2x0_size) {
360733c6bbaSRussell King 		l2c220_op_way(base, L2X0_CLEAN_INV_WAY);
361733c6bbaSRussell King 		return;
362733c6bbaSRussell King 	}
363733c6bbaSRussell King 
364733c6bbaSRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
365733c6bbaSRussell King 	flags = l2c220_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA,
366733c6bbaSRussell King 				   start, end, flags);
367733c6bbaSRussell King 	l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1);
368733c6bbaSRussell King 	__l2c220_cache_sync(base);
369733c6bbaSRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
370733c6bbaSRussell King }
371733c6bbaSRussell King 
l2c220_flush_all(void)372733c6bbaSRussell King static void l2c220_flush_all(void)
373733c6bbaSRussell King {
374733c6bbaSRussell King 	l2c220_op_way(l2x0_base, L2X0_CLEAN_INV_WAY);
375733c6bbaSRussell King }
376733c6bbaSRussell King 
l2c220_sync(void)377733c6bbaSRussell King static void l2c220_sync(void)
378733c6bbaSRussell King {
379733c6bbaSRussell King 	unsigned long flags;
380733c6bbaSRussell King 
381733c6bbaSRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
382733c6bbaSRussell King 	__l2c220_cache_sync(l2x0_base);
383733c6bbaSRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
384733c6bbaSRussell King }
385733c6bbaSRussell King 
l2c220_enable(void __iomem * base,unsigned num_lock)3865b290ec2SRussell King static void l2c220_enable(void __iomem *base, unsigned num_lock)
387a4b041a0SRussell King {
388a4b041a0SRussell King 	/*
389a4b041a0SRussell King 	 * Always enable non-secure access to the lockdown registers -
390a4b041a0SRussell King 	 * we write to them as part of the L2C enable sequence so they
391a4b041a0SRussell King 	 * need to be accessible.
392a4b041a0SRussell King 	 */
3935b290ec2SRussell King 	l2x0_saved_regs.aux_ctrl |= L220_AUX_CTRL_NS_LOCKDOWN;
394a4b041a0SRussell King 
3955b290ec2SRussell King 	l2c_enable(base, num_lock);
396a4b041a0SRussell King }
397a4b041a0SRussell King 
l2c220_unlock(void __iomem * base,unsigned num_lock)398e946a8cbSRussell King static void l2c220_unlock(void __iomem *base, unsigned num_lock)
399e946a8cbSRussell King {
400e946a8cbSRussell King 	if (readl_relaxed(base + L2X0_AUX_CTRL) & L220_AUX_CTRL_NS_LOCKDOWN)
401e946a8cbSRussell King 		l2c_unlock(base, num_lock);
402e946a8cbSRussell King }
403e946a8cbSRussell King 
404733c6bbaSRussell King static const struct l2c_init_data l2c220_data = {
405051334bdSRussell King 	.type = "L2C-220",
4060493aef4SRussell King 	.way_size_0 = SZ_8K,
407733c6bbaSRussell King 	.num_lock = 1,
408a4b041a0SRussell King 	.enable = l2c220_enable,
409ddf7d79bSRussell King 	.save = l2c_save,
41050beefdeSRussell King 	.configure = l2c_configure,
411e946a8cbSRussell King 	.unlock = l2c220_unlock,
412733c6bbaSRussell King 	.outer_cache = {
413733c6bbaSRussell King 		.inv_range = l2c220_inv_range,
414733c6bbaSRussell King 		.clean_range = l2c220_clean_range,
415733c6bbaSRussell King 		.flush_range = l2c220_flush_range,
416733c6bbaSRussell King 		.flush_all = l2c220_flush_all,
417733c6bbaSRussell King 		.disable = l2c_disable,
418733c6bbaSRussell King 		.sync = l2c220_sync,
4196b49241aSTomasz Figa 		.resume = l2c_resume,
420733c6bbaSRussell King 	},
421733c6bbaSRussell King };
422733c6bbaSRussell King 
423733c6bbaSRussell King /*
42475461f5cSRussell King  * L2C-310 specific code.
42575461f5cSRussell King  *
426f777332bSRussell King  * Very similar to L2C-210, the PA, set/way and sync operations are atomic,
427f777332bSRussell King  * and the way operations are all background tasks.  However, issuing an
428f777332bSRussell King  * operation while a background operation is in progress results in a
429f777332bSRussell King  * SLVERR response.  We can reuse:
430f777332bSRussell King  *
431f777332bSRussell King  *  __l2c210_cache_sync (using sync_reg_offset)
432f777332bSRussell King  *  l2c210_sync
433f777332bSRussell King  *  l2c210_inv_range (if 588369 is not applicable)
434f777332bSRussell King  *  l2c210_clean_range
435f777332bSRussell King  *  l2c210_flush_range (if 588369 is not applicable)
436f777332bSRussell King  *  l2c210_flush_all (if 727915 is not applicable)
437f777332bSRussell King  *
43875461f5cSRussell King  * Errata:
43975461f5cSRussell King  * 588369: PL310 R0P0->R1P0, fixed R2P0.
44075461f5cSRussell King  *	Affects: all clean+invalidate operations
44175461f5cSRussell King  *	clean and invalidate skips the invalidate step, so we need to issue
44275461f5cSRussell King  *	separate operations.  We also require the above debug workaround
44375461f5cSRussell King  *	enclosing this code fragment on affected parts.  On unaffected parts,
44475461f5cSRussell King  *	we must not use this workaround without the debug register writes
44575461f5cSRussell King  *	to avoid exposing a problem similar to 727915.
44675461f5cSRussell King  *
44775461f5cSRussell King  * 727915: PL310 R2P0->R3P0, fixed R3P1.
44875461f5cSRussell King  *	Affects: clean+invalidate by way
44975461f5cSRussell King  *	clean and invalidate by way runs in the background, and a store can
45075461f5cSRussell King  *	hit the line between the clean operation and invalidate operation,
45175461f5cSRussell King  *	resulting in the store being lost.
45275461f5cSRussell King  *
453a8875a09SRussell King  * 752271: PL310 R3P0->R3P1-50REL0, fixed R3P2.
454a8875a09SRussell King  *	Affects: 8x64-bit (double fill) line fetches
455a8875a09SRussell King  *	double fill line fetches can fail to cause dirty data to be evicted
456a8875a09SRussell King  *	from the cache before the new data overwrites the second line.
457a8875a09SRussell King  *
45875461f5cSRussell King  * 753970: PL310 R3P0, fixed R3P1.
45975461f5cSRussell King  *	Affects: sync
46075461f5cSRussell King  *	prevents merging writes after the sync operation, until another L2C
46175461f5cSRussell King  *	operation is performed (or a number of other conditions.)
46275461f5cSRussell King  *
46375461f5cSRussell King  * 769419: PL310 R0P0->R3P1, fixed R3P2.
46475461f5cSRussell King  *	Affects: store buffer
46575461f5cSRussell King  *	store buffer is not automatically drained.
46675461f5cSRussell King  */
l2c310_inv_range_erratum(unsigned long start,unsigned long end)467ebd4219fSRussell King static void l2c310_inv_range_erratum(unsigned long start, unsigned long end)
468ebd4219fSRussell King {
469ebd4219fSRussell King 	void __iomem *base = l2x0_base;
470ebd4219fSRussell King 
471ebd4219fSRussell King 	if ((start | end) & (CACHE_LINE_SIZE - 1)) {
472ebd4219fSRussell King 		unsigned long flags;
473ebd4219fSRussell King 
474ebd4219fSRussell King 		/* Erratum 588369 for both clean+invalidate operations */
475ebd4219fSRussell King 		raw_spin_lock_irqsave(&l2x0_lock, flags);
476ebd4219fSRussell King 		l2c_set_debug(base, 0x03);
477ebd4219fSRussell King 
478ebd4219fSRussell King 		if (start & (CACHE_LINE_SIZE - 1)) {
479ebd4219fSRussell King 			start &= ~(CACHE_LINE_SIZE - 1);
480ebd4219fSRussell King 			writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
481ebd4219fSRussell King 			writel_relaxed(start, base + L2X0_INV_LINE_PA);
482ebd4219fSRussell King 			start += CACHE_LINE_SIZE;
483ebd4219fSRussell King 		}
484ebd4219fSRussell King 
485ebd4219fSRussell King 		if (end & (CACHE_LINE_SIZE - 1)) {
486ebd4219fSRussell King 			end &= ~(CACHE_LINE_SIZE - 1);
487ebd4219fSRussell King 			writel_relaxed(end, base + L2X0_CLEAN_LINE_PA);
488ebd4219fSRussell King 			writel_relaxed(end, base + L2X0_INV_LINE_PA);
489ebd4219fSRussell King 		}
490ebd4219fSRussell King 
491ebd4219fSRussell King 		l2c_set_debug(base, 0x00);
492ebd4219fSRussell King 		raw_spin_unlock_irqrestore(&l2x0_lock, flags);
493ebd4219fSRussell King 	}
494ebd4219fSRussell King 
495ebd4219fSRussell King 	__l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end);
496ebd4219fSRussell King 	__l2c210_cache_sync(base);
497ebd4219fSRussell King }
498ebd4219fSRussell King 
l2c310_flush_range_erratum(unsigned long start,unsigned long end)499ebd4219fSRussell King static void l2c310_flush_range_erratum(unsigned long start, unsigned long end)
500ebd4219fSRussell King {
501ebd4219fSRussell King 	raw_spinlock_t *lock = &l2x0_lock;
502ebd4219fSRussell King 	unsigned long flags;
503ebd4219fSRussell King 	void __iomem *base = l2x0_base;
504ebd4219fSRussell King 
505ebd4219fSRussell King 	raw_spin_lock_irqsave(lock, flags);
506ebd4219fSRussell King 	while (start < end) {
507ebd4219fSRussell King 		unsigned long blk_end = start + min(end - start, 4096UL);
508ebd4219fSRussell King 
509ebd4219fSRussell King 		l2c_set_debug(base, 0x03);
510ebd4219fSRussell King 		while (start < blk_end) {
511ebd4219fSRussell King 			writel_relaxed(start, base + L2X0_CLEAN_LINE_PA);
512ebd4219fSRussell King 			writel_relaxed(start, base + L2X0_INV_LINE_PA);
513ebd4219fSRussell King 			start += CACHE_LINE_SIZE;
514ebd4219fSRussell King 		}
515ebd4219fSRussell King 		l2c_set_debug(base, 0x00);
516ebd4219fSRussell King 
517ebd4219fSRussell King 		if (blk_end < end) {
518ebd4219fSRussell King 			raw_spin_unlock_irqrestore(lock, flags);
519ebd4219fSRussell King 			raw_spin_lock_irqsave(lock, flags);
520ebd4219fSRussell King 		}
521ebd4219fSRussell King 	}
522ebd4219fSRussell King 	raw_spin_unlock_irqrestore(lock, flags);
523ebd4219fSRussell King 	__l2c210_cache_sync(base);
524ebd4219fSRussell King }
525ebd4219fSRussell King 
l2c310_flush_all_erratum(void)52699ca1772SRussell King static void l2c310_flush_all_erratum(void)
52799ca1772SRussell King {
52899ca1772SRussell King 	void __iomem *base = l2x0_base;
52999ca1772SRussell King 	unsigned long flags;
53099ca1772SRussell King 
53199ca1772SRussell King 	raw_spin_lock_irqsave(&l2x0_lock, flags);
53299ca1772SRussell King 	l2c_set_debug(base, 0x03);
53399ca1772SRussell King 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
53499ca1772SRussell King 	l2c_set_debug(base, 0x00);
53599ca1772SRussell King 	__l2c210_cache_sync(base);
53699ca1772SRussell King 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
53799ca1772SRussell King }
53899ca1772SRussell King 
l2c310_save(void __iomem * base)53909a5d180SRussell King static void __init l2c310_save(void __iomem *base)
540b98556f2SRussell King {
54109a5d180SRussell King 	unsigned revision;
542b98556f2SRussell King 
543ddf7d79bSRussell King 	l2c_save(base);
544ddf7d79bSRussell King 
545b98556f2SRussell King 	l2x0_saved_regs.tag_latency = readl_relaxed(base +
5461a5a954cSRussell King 		L310_TAG_LATENCY_CTRL);
547b98556f2SRussell King 	l2x0_saved_regs.data_latency = readl_relaxed(base +
5481a5a954cSRussell King 		L310_DATA_LATENCY_CTRL);
549b98556f2SRussell King 	l2x0_saved_regs.filter_end = readl_relaxed(base +
5501a5a954cSRussell King 		L310_ADDR_FILTER_END);
551b98556f2SRussell King 	l2x0_saved_regs.filter_start = readl_relaxed(base +
5521a5a954cSRussell King 		L310_ADDR_FILTER_START);
553b98556f2SRussell King 
55409a5d180SRussell King 	revision = readl_relaxed(base + L2X0_CACHE_ID) &
55509a5d180SRussell King 			L2X0_CACHE_ID_RTL_MASK;
55609a5d180SRussell King 
55709a5d180SRussell King 	/* From r2p0, there is Prefetch offset/control register */
55809a5d180SRussell King 	if (revision >= L310_CACHE_ID_RTL_R2P0)
559b98556f2SRussell King 		l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base +
5601a5a954cSRussell King 							L310_PREFETCH_CTRL);
56109a5d180SRussell King 
56209a5d180SRussell King 	/* From r3p0, there is Power control register */
56309a5d180SRussell King 	if (revision >= L310_CACHE_ID_RTL_R3P0)
564b98556f2SRussell King 		l2x0_saved_regs.pwr_ctrl = readl_relaxed(base +
5651a5a954cSRussell King 							L310_POWER_CTRL);
566b98556f2SRussell King }
567b98556f2SRussell King 
l2c310_configure(void __iomem * base)5686b49241aSTomasz Figa static void l2c310_configure(void __iomem *base)
569b98556f2SRussell King {
57009a5d180SRussell King 	unsigned revision;
57109a5d180SRussell King 
57250beefdeSRussell King 	l2c_configure(base);
57350beefdeSRussell King 
574b98556f2SRussell King 	/* restore pl310 setup */
57500218241SMarek Szyprowski 	l2c_write_sec(l2x0_saved_regs.tag_latency, base,
57600218241SMarek Szyprowski 		      L310_TAG_LATENCY_CTRL);
57700218241SMarek Szyprowski 	l2c_write_sec(l2x0_saved_regs.data_latency, base,
57800218241SMarek Szyprowski 		      L310_DATA_LATENCY_CTRL);
57900218241SMarek Szyprowski 	l2c_write_sec(l2x0_saved_regs.filter_end, base,
58000218241SMarek Szyprowski 		      L310_ADDR_FILTER_END);
58100218241SMarek Szyprowski 	l2c_write_sec(l2x0_saved_regs.filter_start, base,
58200218241SMarek Szyprowski 		      L310_ADDR_FILTER_START);
583b98556f2SRussell King 
58409a5d180SRussell King 	revision = readl_relaxed(base + L2X0_CACHE_ID) &
585b98556f2SRussell King 				 L2X0_CACHE_ID_RTL_MASK;
586b98556f2SRussell King 
58709a5d180SRussell King 	if (revision >= L310_CACHE_ID_RTL_R2P0)
5888abd259fSRussell King 		l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base,
5891a5a954cSRussell King 			      L310_PREFETCH_CTRL);
59009a5d180SRussell King 	if (revision >= L310_CACHE_ID_RTL_R3P0)
5918abd259fSRussell King 		l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base,
5921a5a954cSRussell King 			      L310_POWER_CTRL);
593b98556f2SRussell King }
594b98556f2SRussell King 
l2c310_starting_cpu(unsigned int cpu)5959eeb2264SRichard Cochran static int l2c310_starting_cpu(unsigned int cpu)
5968ef418c7SRussell King {
5978ef418c7SRussell King 	set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
5989eeb2264SRichard Cochran 	return 0;
5998ef418c7SRussell King }
6009eeb2264SRichard Cochran 
l2c310_dying_cpu(unsigned int cpu)6019eeb2264SRichard Cochran static int l2c310_dying_cpu(unsigned int cpu)
6029eeb2264SRichard Cochran {
6039eeb2264SRichard Cochran 	set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
6049eeb2264SRichard Cochran 	return 0;
6058ef418c7SRussell King }
6068ef418c7SRussell King 
l2c310_enable(void __iomem * base,unsigned num_lock)6075b290ec2SRussell King static void __init l2c310_enable(void __iomem *base, unsigned num_lock)
6084374d649SRussell King {
6099a2c33a4SRussell King 	unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK;
610af040ffcSRussell King 	bool cortex_a9 = read_cpuid_part() == ARM_CPU_PART_CORTEX_A9;
6115b290ec2SRussell King 	u32 aux = l2x0_saved_regs.aux_ctrl;
6124374d649SRussell King 
6134374d649SRussell King 	if (rev >= L310_CACHE_ID_RTL_R2P0) {
614471b5e42SChris Brandt 		if (cortex_a9 && !l2x0_bresp_disable) {
6154374d649SRussell King 			aux |= L310_AUX_CTRL_EARLY_BRESP;
6164374d649SRussell King 			pr_info("L2C-310 enabling early BRESP for Cortex-A9\n");
6174374d649SRussell King 		} else if (aux & L310_AUX_CTRL_EARLY_BRESP) {
6184374d649SRussell King 			pr_warn("L2C-310 early BRESP only supported with Cortex-A9\n");
6194374d649SRussell King 			aux &= ~L310_AUX_CTRL_EARLY_BRESP;
6204374d649SRussell King 		}
6214374d649SRussell King 	}
6224374d649SRussell King 
623471b5e42SChris Brandt 	if (cortex_a9 && !l2x0_flz_disable) {
6248ef418c7SRussell King 		u32 aux_cur = readl_relaxed(base + L2X0_AUX_CTRL);
6258ef418c7SRussell King 		u32 acr = get_auxcr();
6268ef418c7SRussell King 
6278ef418c7SRussell King 		pr_debug("Cortex-A9 ACR=0x%08x\n", acr);
6288ef418c7SRussell King 
6298ef418c7SRussell King 		if (acr & BIT(3) && !(aux_cur & L310_AUX_CTRL_FULL_LINE_ZERO))
6308ef418c7SRussell King 			pr_err("L2C-310: full line of zeros enabled in Cortex-A9 but not L2C-310 - invalid\n");
6318ef418c7SRussell King 
6328ef418c7SRussell King 		if (aux & L310_AUX_CTRL_FULL_LINE_ZERO && !(acr & BIT(3)))
6338ef418c7SRussell King 			pr_err("L2C-310: enabling full line of zeros but not enabled in Cortex-A9\n");
6348ef418c7SRussell King 
6358ef418c7SRussell King 		if (!(aux & L310_AUX_CTRL_FULL_LINE_ZERO) && !outer_cache.write_sec) {
6368ef418c7SRussell King 			aux |= L310_AUX_CTRL_FULL_LINE_ZERO;
6378ef418c7SRussell King 			pr_info("L2C-310 full line of zeros enabled for Cortex-A9\n");
6388ef418c7SRussell King 		}
6398ef418c7SRussell King 	} else if (aux & (L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP)) {
6408ef418c7SRussell King 		pr_err("L2C-310: disabling Cortex-A9 specific feature bits\n");
6418ef418c7SRussell King 		aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP);
6428ef418c7SRussell King 	}
6438ef418c7SRussell King 
6446b49241aSTomasz Figa 	/*
6456b49241aSTomasz Figa 	 * Always enable non-secure access to the lockdown registers -
6466b49241aSTomasz Figa 	 * we write to them as part of the L2C enable sequence so they
6476b49241aSTomasz Figa 	 * need to be accessible.
6486b49241aSTomasz Figa 	 */
6495b290ec2SRussell King 	l2x0_saved_regs.aux_ctrl = aux | L310_AUX_CTRL_NS_LOCKDOWN;
6506b49241aSTomasz Figa 
6515b290ec2SRussell King 	l2c_enable(base, num_lock);
6526b49241aSTomasz Figa 
6536b49241aSTomasz Figa 	/* Read back resulting AUX_CTRL value as it could have been altered. */
6546b49241aSTomasz Figa 	aux = readl_relaxed(base + L2X0_AUX_CTRL);
6556b49241aSTomasz Figa 
6568ef418c7SRussell King 	if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) {
6578ef418c7SRussell King 		u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL);
6588ef418c7SRussell King 
6598ef418c7SRussell King 		pr_info("L2C-310 %s%s prefetch enabled, offset %u lines\n",
6608ef418c7SRussell King 			aux & L310_AUX_CTRL_INSTR_PREFETCH ? "I" : "",
6618ef418c7SRussell King 			aux & L310_AUX_CTRL_DATA_PREFETCH ? "D" : "",
6628ef418c7SRussell King 			1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK));
6638ef418c7SRussell King 	}
6648ef418c7SRussell King 
6653a43b581SRussell King 	/* r3p0 or later has power control register */
6663a43b581SRussell King 	if (rev >= L310_CACHE_ID_RTL_R3P0) {
6673a43b581SRussell King 		u32 power_ctrl;
6683a43b581SRussell King 
6693a43b581SRussell King 		power_ctrl = readl_relaxed(base + L310_POWER_CTRL);
6703a43b581SRussell King 		pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n",
6713a43b581SRussell King 			power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis",
6723a43b581SRussell King 			power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis");
6733a43b581SRussell King 	}
6743a43b581SRussell King 
6759eeb2264SRichard Cochran 	if (aux & L310_AUX_CTRL_FULL_LINE_ZERO)
6769eeb2264SRichard Cochran 		cpuhp_setup_state(CPUHP_AP_ARM_L2X0_STARTING,
67773c1b41eSThomas Gleixner 				  "arm/l2x0:starting", l2c310_starting_cpu,
6789eeb2264SRichard Cochran 				  l2c310_dying_cpu);
6794374d649SRussell King }
6804374d649SRussell King 
l2c310_fixup(void __iomem * base,u32 cache_id,struct outer_cache_fns * fns)68175461f5cSRussell King static void __init l2c310_fixup(void __iomem *base, u32 cache_id,
68275461f5cSRussell King 	struct outer_cache_fns *fns)
68375461f5cSRussell King {
68475461f5cSRussell King 	unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK;
685a8875a09SRussell King 	const char *errata[8];
68675461f5cSRussell King 	unsigned n = 0;
68775461f5cSRussell King 
688ebd4219fSRussell King 	if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) &&
689ebd4219fSRussell King 	    revision < L310_CACHE_ID_RTL_R2P0 &&
690ebd4219fSRussell King 	    /* For bcm compatibility */
691f777332bSRussell King 	    fns->inv_range == l2c210_inv_range) {
692ebd4219fSRussell King 		fns->inv_range = l2c310_inv_range_erratum;
693ebd4219fSRussell King 		fns->flush_range = l2c310_flush_range_erratum;
694ebd4219fSRussell King 		errata[n++] = "588369";
695ebd4219fSRussell King 	}
696ebd4219fSRussell King 
69799ca1772SRussell King 	if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) &&
69899ca1772SRussell King 	    revision >= L310_CACHE_ID_RTL_R2P0 &&
69999ca1772SRussell King 	    revision < L310_CACHE_ID_RTL_R3P1) {
70099ca1772SRussell King 		fns->flush_all = l2c310_flush_all_erratum;
70199ca1772SRussell King 		errata[n++] = "727915";
70299ca1772SRussell King 	}
70399ca1772SRussell King 
704a8875a09SRussell King 	if (revision >= L310_CACHE_ID_RTL_R3P0 &&
705a8875a09SRussell King 	    revision < L310_CACHE_ID_RTL_R3P2) {
7066b49241aSTomasz Figa 		u32 val = l2x0_saved_regs.prefetch_ctrl;
70755604b7aSAndrey Smirnov 		if (val & L310_PREFETCH_CTRL_DBL_LINEFILL) {
70855604b7aSAndrey Smirnov 			val &= ~L310_PREFETCH_CTRL_DBL_LINEFILL;
7096b49241aSTomasz Figa 			l2x0_saved_regs.prefetch_ctrl = val;
710a8875a09SRussell King 			errata[n++] = "752271";
711a8875a09SRussell King 		}
712a8875a09SRussell King 	}
713a8875a09SRussell King 
71475461f5cSRussell King 	if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) &&
71575461f5cSRussell King 	    revision == L310_CACHE_ID_RTL_R3P0) {
71675461f5cSRussell King 		sync_reg_offset = L2X0_DUMMY_REG;
71775461f5cSRussell King 		errata[n++] = "753970";
71875461f5cSRussell King 	}
71975461f5cSRussell King 
72075461f5cSRussell King 	if (IS_ENABLED(CONFIG_PL310_ERRATA_769419))
72175461f5cSRussell King 		errata[n++] = "769419";
72275461f5cSRussell King 
72375461f5cSRussell King 	if (n) {
72475461f5cSRussell King 		unsigned i;
72575461f5cSRussell King 
72675461f5cSRussell King 		pr_info("L2C-310 errat%s", n > 1 ? "a" : "um");
72775461f5cSRussell King 		for (i = 0; i < n; i++)
72875461f5cSRussell King 			pr_cont(" %s", errata[i]);
72975461f5cSRussell King 		pr_cont(" enabled\n");
73075461f5cSRussell King 	}
73175461f5cSRussell King }
73275461f5cSRussell King 
l2c310_disable(void)7338ef418c7SRussell King static void l2c310_disable(void)
7348ef418c7SRussell King {
7358ef418c7SRussell King 	/*
7368ef418c7SRussell King 	 * If full-line-of-zeros is enabled, we must first disable it in the
7378ef418c7SRussell King 	 * Cortex-A9 auxiliary control register before disabling the L2 cache.
7388ef418c7SRussell King 	 */
7398ef418c7SRussell King 	if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
7408ef418c7SRussell King 		set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
7418ef418c7SRussell King 
7428ef418c7SRussell King 	l2c_disable();
7438ef418c7SRussell King }
7448ef418c7SRussell King 
l2c310_resume(void)7456b49241aSTomasz Figa static void l2c310_resume(void)
7466b49241aSTomasz Figa {
7476b49241aSTomasz Figa 	l2c_resume();
7486b49241aSTomasz Figa 
7496b49241aSTomasz Figa 	/* Re-enable full-line-of-zeros for Cortex-A9 */
7506b49241aSTomasz Figa 	if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO)
7516b49241aSTomasz Figa 		set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
7526b49241aSTomasz Figa }
7536b49241aSTomasz Figa 
l2c310_unlock(void __iomem * base,unsigned num_lock)754e946a8cbSRussell King static void l2c310_unlock(void __iomem *base, unsigned num_lock)
755e946a8cbSRussell King {
756e946a8cbSRussell King 	if (readl_relaxed(base + L2X0_AUX_CTRL) & L310_AUX_CTRL_NS_LOCKDOWN)
757e946a8cbSRussell King 		l2c_unlock(base, num_lock);
758e946a8cbSRussell King }
759e946a8cbSRussell King 
76075461f5cSRussell King static const struct l2c_init_data l2c310_init_fns __initconst = {
761051334bdSRussell King 	.type = "L2C-310",
7620493aef4SRussell King 	.way_size_0 = SZ_8K,
76375461f5cSRussell King 	.num_lock = 8,
7644374d649SRussell King 	.enable = l2c310_enable,
76575461f5cSRussell King 	.fixup = l2c310_fixup,
76609a5d180SRussell King 	.save = l2c310_save,
7676b49241aSTomasz Figa 	.configure = l2c310_configure,
768e946a8cbSRussell King 	.unlock = l2c310_unlock,
76975461f5cSRussell King 	.outer_cache = {
770f777332bSRussell King 		.inv_range = l2c210_inv_range,
771f777332bSRussell King 		.clean_range = l2c210_clean_range,
772f777332bSRussell King 		.flush_range = l2c210_flush_range,
773f777332bSRussell King 		.flush_all = l2c210_flush_all,
7748ef418c7SRussell King 		.disable = l2c310_disable,
775f777332bSRussell King 		.sync = l2c210_sync,
77609a5d180SRussell King 		.resume = l2c310_resume,
77775461f5cSRussell King 	},
77875461f5cSRussell King };
77975461f5cSRussell King 
__l2c_init(const struct l2c_init_data * data,u32 aux_val,u32 aux_mask,u32 cache_id,bool nosync)7806b49241aSTomasz Figa static int __init __l2c_init(const struct l2c_init_data *data,
78136f46d6dSLinus Walleij 			     u32 aux_val, u32 aux_mask, u32 cache_id, bool nosync)
782382266adSCatalin Marinas {
78375461f5cSRussell King 	struct outer_cache_fns fns;
7840493aef4SRussell King 	unsigned way_size_bits, ways;
785560be613SRussell King 	u32 aux, old_aux;
786382266adSCatalin Marinas 
787560be613SRussell King 	/*
7886b49241aSTomasz Figa 	 * Save the pointer globally so that callbacks which do not receive
7896b49241aSTomasz Figa 	 * context from callers can access the structure.
7906b49241aSTomasz Figa 	 */
7916b49241aSTomasz Figa 	l2x0_data = kmemdup(data, sizeof(*data), GFP_KERNEL);
7926b49241aSTomasz Figa 	if (!l2x0_data)
7936b49241aSTomasz Figa 		return -ENOMEM;
7946b49241aSTomasz Figa 
7956b49241aSTomasz Figa 	/*
796560be613SRussell King 	 * Sanity check the aux values.  aux_mask is the bits we preserve
797560be613SRussell King 	 * from reading the hardware register, and aux_val is the bits we
798560be613SRussell King 	 * set.
799560be613SRussell King 	 */
800560be613SRussell King 	if (aux_val & aux_mask)
801560be613SRussell King 		pr_alert("L2C: platform provided aux values permit register corruption.\n");
80264039be8SJason McMullan 
803560be613SRussell King 	old_aux = aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
8044082cfa7SSascha Hauer 	aux &= aux_mask;
8054082cfa7SSascha Hauer 	aux |= aux_val;
8064082cfa7SSascha Hauer 
807560be613SRussell King 	if (old_aux != aux)
808560be613SRussell King 		pr_warn("L2C: DT/platform modifies aux control register: 0x%08x -> 0x%08x\n",
809560be613SRussell King 		        old_aux, aux);
810560be613SRussell King 
81164039be8SJason McMullan 	/* Determine the number of ways */
8126e7aceebSRob Herring 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
81364039be8SJason McMullan 	case L2X0_CACHE_ID_PART_L310:
814314e47b7SRussell King 		if ((aux_val | ~aux_mask) & (L2C_AUX_CTRL_WAY_SIZE_MASK | L310_AUX_CTRL_ASSOCIATIVITY_16))
815314e47b7SRussell King 			pr_warn("L2C: DT/platform tries to modify or specify cache size\n");
81664039be8SJason McMullan 		if (aux & (1 << 16))
81764039be8SJason McMullan 			ways = 16;
81864039be8SJason McMullan 		else
81964039be8SJason McMullan 			ways = 8;
82064039be8SJason McMullan 		break;
82175461f5cSRussell King 
82264039be8SJason McMullan 	case L2X0_CACHE_ID_PART_L210:
8235f47c387SRussell King 	case L2X0_CACHE_ID_PART_L220:
82464039be8SJason McMullan 		ways = (aux >> 13) & 0xf;
82564039be8SJason McMullan 		break;
826b8db6b88SGregory CLEMENT 
827b8db6b88SGregory CLEMENT 	case AURORA_CACHE_ID:
828b8db6b88SGregory CLEMENT 		ways = (aux >> 13) & 0xf;
829b8db6b88SGregory CLEMENT 		ways = 2 << ((ways + 1) >> 2);
830b8db6b88SGregory CLEMENT 		break;
83175461f5cSRussell King 
83264039be8SJason McMullan 	default:
83364039be8SJason McMullan 		/* Assume unknown chips have 8 ways */
83464039be8SJason McMullan 		ways = 8;
83564039be8SJason McMullan 		break;
83664039be8SJason McMullan 	}
83764039be8SJason McMullan 
83864039be8SJason McMullan 	l2x0_way_mask = (1 << ways) - 1;
83964039be8SJason McMullan 
84048371cd3SSrinidhi Kasagar 	/*
8410493aef4SRussell King 	 * way_size_0 is the size that a way_size value of zero would be
8420493aef4SRussell King 	 * given the calculation: way_size = way_size_0 << way_size_bits.
8430493aef4SRussell King 	 * So, if way_size_bits=0 is reserved, but way_size_bits=1 is 16k,
8440493aef4SRussell King 	 * then way_size_0 would be 8k.
8450493aef4SRussell King 	 *
8460493aef4SRussell King 	 * L2 cache size = number of ways * way size.
8475ba70372SSantosh Shilimkar 	 */
8481a5a954cSRussell King 	way_size_bits = (aux & L2C_AUX_CTRL_WAY_SIZE_MASK) >>
8491a5a954cSRussell King 			L2C_AUX_CTRL_WAY_SIZE_SHIFT;
8500493aef4SRussell King 	l2x0_size = ways * (data->way_size_0 << way_size_bits);
8515ba70372SSantosh Shilimkar 
85275461f5cSRussell King 	fns = data->outer_cache;
8538abd259fSRussell King 	fns.write_sec = outer_cache.write_sec;
854c6d1a2d0STomasz Figa 	fns.configure = outer_cache.configure;
85575461f5cSRussell King 	if (data->fixup)
85675461f5cSRussell King 		data->fixup(l2x0_base, cache_id, &fns);
85736f46d6dSLinus Walleij 	if (nosync) {
85836f46d6dSLinus Walleij 		pr_info("L2C: disabling outer sync\n");
85936f46d6dSLinus Walleij 		fns.sync = NULL;
86036f46d6dSLinus Walleij 	}
86175461f5cSRussell King 
8625ba70372SSantosh Shilimkar 	/*
8633b8bad57SRussell King 	 * Check if l2x0 controller is already enabled.  If we are booting
8643b8bad57SRussell King 	 * in non-secure mode accessing the below registers will fault.
86548371cd3SSrinidhi Kasagar 	 */
8665b290ec2SRussell King 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
8675b290ec2SRussell King 		l2x0_saved_regs.aux_ctrl = aux;
8685b290ec2SRussell King 
8695b290ec2SRussell King 		data->enable(l2x0_base, data->num_lock);
8705b290ec2SRussell King 	}
871382266adSCatalin Marinas 
872ddf7d79bSRussell King 	outer_cache = fns;
873ddf7d79bSRussell King 
874ddf7d79bSRussell King 	/*
875ddf7d79bSRussell King 	 * It is strange to save the register state before initialisation,
876ddf7d79bSRussell King 	 * but hey, this is what the DT implementations decided to do.
877ddf7d79bSRussell King 	 */
878ddf7d79bSRussell King 	if (data->save)
879ddf7d79bSRussell King 		data->save(l2x0_base);
880ddf7d79bSRussell King 
8819d4876f0SYilu Mao 	/* Re-read it in case some bits are reserved. */
8829d4876f0SYilu Mao 	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
8839d4876f0SYilu Mao 
884cdef8689SRussell King 	pr_info("%s cache controller enabled, %d ways, %d kB\n",
885051334bdSRussell King 		data->type, ways, l2x0_size >> 10);
886cdef8689SRussell King 	pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n",
887051334bdSRussell King 		data->type, cache_id, aux);
8886b49241aSTomasz Figa 
889b828f960SMark Rutland 	l2x0_pmu_register(l2x0_base, cache_id);
890b828f960SMark Rutland 
8916b49241aSTomasz Figa 	return 0;
892382266adSCatalin Marinas }
8938c369264SRob Herring 
l2x0_init(void __iomem * base,u32 aux_val,u32 aux_mask)89496054b0aSRussell King void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
89596054b0aSRussell King {
89675461f5cSRussell King 	const struct l2c_init_data *data;
89796054b0aSRussell King 	u32 cache_id;
89896054b0aSRussell King 
89996054b0aSRussell King 	l2x0_base = base;
90096054b0aSRussell King 
90196054b0aSRussell King 	cache_id = readl_relaxed(base + L2X0_CACHE_ID);
90296054b0aSRussell King 
90375461f5cSRussell King 	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
90475461f5cSRussell King 	default:
9056a28cf59SRussell King 	case L2X0_CACHE_ID_PART_L210:
9066a28cf59SRussell King 		data = &l2c210_data;
9076a28cf59SRussell King 		break;
9086a28cf59SRussell King 
909733c6bbaSRussell King 	case L2X0_CACHE_ID_PART_L220:
910733c6bbaSRussell King 		data = &l2c220_data;
911733c6bbaSRussell King 		break;
912733c6bbaSRussell King 
91375461f5cSRussell King 	case L2X0_CACHE_ID_PART_L310:
91475461f5cSRussell King 		data = &l2c310_init_fns;
91575461f5cSRussell King 		break;
91675461f5cSRussell King 	}
91775461f5cSRussell King 
9186b49241aSTomasz Figa 	/* Read back current (default) hardware configuration */
9196b49241aSTomasz Figa 	if (data->save)
9206b49241aSTomasz Figa 		data->save(l2x0_base);
9216b49241aSTomasz Figa 
92236f46d6dSLinus Walleij 	__l2c_init(data, aux_val, aux_mask, cache_id, false);
92396054b0aSRussell King }
92496054b0aSRussell King 
9258c369264SRob Herring #ifdef CONFIG_OF
926b8db6b88SGregory CLEMENT static int l2_wt_override;
927b8db6b88SGregory CLEMENT 
92896054b0aSRussell King /* Aurora don't have the cache ID register available, so we have to
92996054b0aSRussell King  * pass it though the device tree */
93096054b0aSRussell King static u32 cache_id_part_number_from_dt;
93196054b0aSRussell King 
932f3354ab6SLinus Walleij /**
933f3354ab6SLinus Walleij  * l2x0_cache_size_of_parse() - read cache size parameters from DT
934f3354ab6SLinus Walleij  * @np: the device tree node for the l2 cache
935f3354ab6SLinus Walleij  * @aux_val: pointer to machine-supplied auxilary register value, to
936f3354ab6SLinus Walleij  * be augmented by the call (bits to be set to 1)
937f3354ab6SLinus Walleij  * @aux_mask: pointer to machine-supplied auxilary register mask, to
938f3354ab6SLinus Walleij  * be augmented by the call (bits to be set to 0)
939f3354ab6SLinus Walleij  * @associativity: variable to return the calculated associativity in
940f3354ab6SLinus Walleij  * @max_way_size: the maximum size in bytes for the cache ways
941f3354ab6SLinus Walleij  */
l2x0_cache_size_of_parse(const struct device_node * np,u32 * aux_val,u32 * aux_mask,u32 * associativity,u32 max_way_size)942d0b92845SFabio Estevam static int __init l2x0_cache_size_of_parse(const struct device_node *np,
943f3354ab6SLinus Walleij 					    u32 *aux_val, u32 *aux_mask,
944f3354ab6SLinus Walleij 					    u32 *associativity,
945f3354ab6SLinus Walleij 					    u32 max_way_size)
946f3354ab6SLinus Walleij {
947f3354ab6SLinus Walleij 	u32 mask = 0, val = 0;
948f3354ab6SLinus Walleij 	u32 cache_size = 0, sets = 0;
949f3354ab6SLinus Walleij 	u32 way_size_bits = 1;
950f3354ab6SLinus Walleij 	u32 way_size = 0;
951f3354ab6SLinus Walleij 	u32 block_size = 0;
952f3354ab6SLinus Walleij 	u32 line_size = 0;
953f3354ab6SLinus Walleij 
954f3354ab6SLinus Walleij 	of_property_read_u32(np, "cache-size", &cache_size);
955f3354ab6SLinus Walleij 	of_property_read_u32(np, "cache-sets", &sets);
956f3354ab6SLinus Walleij 	of_property_read_u32(np, "cache-block-size", &block_size);
957f3354ab6SLinus Walleij 	of_property_read_u32(np, "cache-line-size", &line_size);
958f3354ab6SLinus Walleij 
959f3354ab6SLinus Walleij 	if (!cache_size || !sets)
960d0b92845SFabio Estevam 		return -ENODEV;
961f3354ab6SLinus Walleij 
962f3354ab6SLinus Walleij 	/* All these l2 caches have the same line = block size actually */
963f3354ab6SLinus Walleij 	if (!line_size) {
964f3354ab6SLinus Walleij 		if (block_size) {
965f2c22731SGeert Uytterhoeven 			/* If linesize is not given, it is equal to blocksize */
966f3354ab6SLinus Walleij 			line_size = block_size;
967f3354ab6SLinus Walleij 		} else {
968f3354ab6SLinus Walleij 			/* Fall back to known size */
969f3354ab6SLinus Walleij 			pr_warn("L2C OF: no cache block/line size given: "
970f3354ab6SLinus Walleij 				"falling back to default size %d bytes\n",
971f3354ab6SLinus Walleij 				CACHE_LINE_SIZE);
972f3354ab6SLinus Walleij 			line_size = CACHE_LINE_SIZE;
973f3354ab6SLinus Walleij 		}
974f3354ab6SLinus Walleij 	}
975f3354ab6SLinus Walleij 
976f3354ab6SLinus Walleij 	if (line_size != CACHE_LINE_SIZE)
977f3354ab6SLinus Walleij 		pr_warn("L2C OF: DT supplied line size %d bytes does "
978f3354ab6SLinus Walleij 			"not match hardware line size of %d bytes\n",
979f3354ab6SLinus Walleij 			line_size,
980f3354ab6SLinus Walleij 			CACHE_LINE_SIZE);
981f3354ab6SLinus Walleij 
982f3354ab6SLinus Walleij 	/*
983f3354ab6SLinus Walleij 	 * Since:
984f3354ab6SLinus Walleij 	 * set size = cache size / sets
985f3354ab6SLinus Walleij 	 * ways = cache size / (sets * line size)
986f3354ab6SLinus Walleij 	 * way size = cache size / (cache size / (sets * line size))
987f3354ab6SLinus Walleij 	 * way size = sets * line size
988f3354ab6SLinus Walleij 	 * associativity = ways = cache size / way size
989f3354ab6SLinus Walleij 	 */
990f3354ab6SLinus Walleij 	way_size = sets * line_size;
991f3354ab6SLinus Walleij 	*associativity = cache_size / way_size;
992f3354ab6SLinus Walleij 
993f3354ab6SLinus Walleij 	if (way_size > max_way_size) {
994f3354ab6SLinus Walleij 		pr_err("L2C OF: set size %dKB is too large\n", way_size);
995d0b92845SFabio Estevam 		return -EINVAL;
996f3354ab6SLinus Walleij 	}
997f3354ab6SLinus Walleij 
998f3354ab6SLinus Walleij 	pr_info("L2C OF: override cache size: %d bytes (%dKB)\n",
999f3354ab6SLinus Walleij 		cache_size, cache_size >> 10);
1000f3354ab6SLinus Walleij 	pr_info("L2C OF: override line size: %d bytes\n", line_size);
1001f3354ab6SLinus Walleij 	pr_info("L2C OF: override way size: %d bytes (%dKB)\n",
1002f3354ab6SLinus Walleij 		way_size, way_size >> 10);
1003f3354ab6SLinus Walleij 	pr_info("L2C OF: override associativity: %d\n", *associativity);
1004f3354ab6SLinus Walleij 
1005f3354ab6SLinus Walleij 	/*
1006f3354ab6SLinus Walleij 	 * Calculates the bits 17:19 to set for way size:
1007f3354ab6SLinus Walleij 	 * 512KB -> 6, 256KB -> 5, ... 16KB -> 1
1008f3354ab6SLinus Walleij 	 */
1009f3354ab6SLinus Walleij 	way_size_bits = ilog2(way_size >> 10) - 3;
1010f3354ab6SLinus Walleij 	if (way_size_bits < 1 || way_size_bits > 6) {
1011f3354ab6SLinus Walleij 		pr_err("L2C OF: cache way size illegal: %dKB is not mapped\n",
1012f3354ab6SLinus Walleij 		       way_size);
1013d0b92845SFabio Estevam 		return -EINVAL;
1014f3354ab6SLinus Walleij 	}
1015f3354ab6SLinus Walleij 
1016f3354ab6SLinus Walleij 	mask |= L2C_AUX_CTRL_WAY_SIZE_MASK;
1017f3354ab6SLinus Walleij 	val |= (way_size_bits << L2C_AUX_CTRL_WAY_SIZE_SHIFT);
1018f3354ab6SLinus Walleij 
1019f3354ab6SLinus Walleij 	*aux_val &= ~mask;
1020f3354ab6SLinus Walleij 	*aux_val |= val;
1021f3354ab6SLinus Walleij 	*aux_mask &= ~mask;
1022d0b92845SFabio Estevam 
1023d0b92845SFabio Estevam 	return 0;
1024f3354ab6SLinus Walleij }
1025f3354ab6SLinus Walleij 
l2x0_of_parse(const struct device_node * np,u32 * aux_val,u32 * aux_mask)1026da3627fbSRussell King static void __init l2x0_of_parse(const struct device_node *np,
1027da3627fbSRussell King 				 u32 *aux_val, u32 *aux_mask)
1028da3627fbSRussell King {
1029da3627fbSRussell King 	u32 data[2] = { 0, 0 };
1030da3627fbSRussell King 	u32 tag = 0;
1031da3627fbSRussell King 	u32 dirty = 0;
1032da3627fbSRussell King 	u32 val = 0, mask = 0;
1033f3354ab6SLinus Walleij 	u32 assoc;
1034d0b92845SFabio Estevam 	int ret;
1035da3627fbSRussell King 
1036da3627fbSRussell King 	of_property_read_u32(np, "arm,tag-latency", &tag);
1037da3627fbSRussell King 	if (tag) {
1038da3627fbSRussell King 		mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK;
1039da3627fbSRussell King 		val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT;
1040da3627fbSRussell King 	}
1041da3627fbSRussell King 
1042da3627fbSRussell King 	of_property_read_u32_array(np, "arm,data-latency",
1043da3627fbSRussell King 				   data, ARRAY_SIZE(data));
1044da3627fbSRussell King 	if (data[0] && data[1]) {
1045da3627fbSRussell King 		mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK |
1046da3627fbSRussell King 			L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK;
1047da3627fbSRussell King 		val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) |
1048da3627fbSRussell King 		       ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT);
1049da3627fbSRussell King 	}
1050da3627fbSRussell King 
1051da3627fbSRussell King 	of_property_read_u32(np, "arm,dirty-latency", &dirty);
1052da3627fbSRussell King 	if (dirty) {
1053da3627fbSRussell King 		mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK;
1054da3627fbSRussell King 		val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
1055da3627fbSRussell King 	}
1056da3627fbSRussell King 
1057b522842cSLinus Walleij 	if (of_property_read_bool(np, "arm,parity-enable")) {
1058b522842cSLinus Walleij 		mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
1059b522842cSLinus Walleij 		val |= L2C_AUX_CTRL_PARITY_ENABLE;
1060b522842cSLinus Walleij 	} else if (of_property_read_bool(np, "arm,parity-disable")) {
1061b522842cSLinus Walleij 		mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
1062b522842cSLinus Walleij 	}
1063b522842cSLinus Walleij 
1064b522842cSLinus Walleij 	if (of_property_read_bool(np, "arm,shared-override")) {
1065b522842cSLinus Walleij 		mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
1066b522842cSLinus Walleij 		val |= L2C_AUX_CTRL_SHARED_OVERRIDE;
1067b522842cSLinus Walleij 	}
1068b522842cSLinus Walleij 
1069d0b92845SFabio Estevam 	ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_256K);
1070d0b92845SFabio Estevam 	if (ret)
1071d0b92845SFabio Estevam 		return;
1072d0b92845SFabio Estevam 
1073f3354ab6SLinus Walleij 	if (assoc > 8) {
1074f3354ab6SLinus Walleij 		pr_err("l2x0 of: cache setting yield too high associativity\n");
1075f3354ab6SLinus Walleij 		pr_err("l2x0 of: %d calculated, max 8\n", assoc);
1076f3354ab6SLinus Walleij 	} else {
1077f3354ab6SLinus Walleij 		mask |= L2X0_AUX_CTRL_ASSOC_MASK;
1078f3354ab6SLinus Walleij 		val |= (assoc << L2X0_AUX_CTRL_ASSOC_SHIFT);
1079f3354ab6SLinus Walleij 	}
1080f3354ab6SLinus Walleij 
1081da3627fbSRussell King 	*aux_val &= ~mask;
1082da3627fbSRussell King 	*aux_val |= val;
1083da3627fbSRussell King 	*aux_mask &= ~mask;
1084da3627fbSRussell King }
1085da3627fbSRussell King 
10866a28cf59SRussell King static const struct l2c_init_data of_l2c210_data __initconst = {
1087051334bdSRussell King 	.type = "L2C-210",
10880493aef4SRussell King 	.way_size_0 = SZ_8K,
10896a28cf59SRussell King 	.num_lock = 1,
10906a28cf59SRussell King 	.of_parse = l2x0_of_parse,
10916a28cf59SRussell King 	.enable = l2c_enable,
1092ddf7d79bSRussell King 	.save = l2c_save,
109350beefdeSRussell King 	.configure = l2c_configure,
1094e946a8cbSRussell King 	.unlock = l2c_unlock,
10956a28cf59SRussell King 	.outer_cache = {
10966a28cf59SRussell King 		.inv_range   = l2c210_inv_range,
10976a28cf59SRussell King 		.clean_range = l2c210_clean_range,
10986a28cf59SRussell King 		.flush_range = l2c210_flush_range,
10996a28cf59SRussell King 		.flush_all   = l2c210_flush_all,
11006a28cf59SRussell King 		.disable     = l2c_disable,
11016a28cf59SRussell King 		.sync        = l2c210_sync,
11026b49241aSTomasz Figa 		.resume      = l2c_resume,
11036a28cf59SRussell King 	},
11046a28cf59SRussell King };
11056a28cf59SRussell King 
1106733c6bbaSRussell King static const struct l2c_init_data of_l2c220_data __initconst = {
1107051334bdSRussell King 	.type = "L2C-220",
11080493aef4SRussell King 	.way_size_0 = SZ_8K,
1109733c6bbaSRussell King 	.num_lock = 1,
1110da3627fbSRussell King 	.of_parse = l2x0_of_parse,
1111a4b041a0SRussell King 	.enable = l2c220_enable,
1112ddf7d79bSRussell King 	.save = l2c_save,
111350beefdeSRussell King 	.configure = l2c_configure,
1114e946a8cbSRussell King 	.unlock = l2c220_unlock,
1115da3627fbSRussell King 	.outer_cache = {
1116733c6bbaSRussell King 		.inv_range   = l2c220_inv_range,
1117733c6bbaSRussell King 		.clean_range = l2c220_clean_range,
1118733c6bbaSRussell King 		.flush_range = l2c220_flush_range,
1119733c6bbaSRussell King 		.flush_all   = l2c220_flush_all,
1120733c6bbaSRussell King 		.disable     = l2c_disable,
1121733c6bbaSRussell King 		.sync        = l2c220_sync,
11226b49241aSTomasz Figa 		.resume      = l2c_resume,
1123da3627fbSRussell King 	},
1124da3627fbSRussell King };
1125da3627fbSRussell King 
l2c310_of_parse(const struct device_node * np,u32 * aux_val,u32 * aux_mask)1126f777332bSRussell King static void __init l2c310_of_parse(const struct device_node *np,
1127da3627fbSRussell King 	u32 *aux_val, u32 *aux_mask)
1128da3627fbSRussell King {
1129da3627fbSRussell King 	u32 data[3] = { 0, 0, 0 };
1130da3627fbSRussell King 	u32 tag[3] = { 0, 0, 0 };
1131da3627fbSRussell King 	u32 filter[2] = { 0, 0 };
1132f3354ab6SLinus Walleij 	u32 assoc;
1133cf0681caSTomasz Figa 	u32 prefetch;
1134204932dfSBrad Mouring 	u32 power;
1135cf0681caSTomasz Figa 	u32 val;
1136d0b92845SFabio Estevam 	int ret;
1137da3627fbSRussell King 
1138da3627fbSRussell King 	of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag));
1139da3627fbSRussell King 	if (tag[0] && tag[1] && tag[2])
11406b49241aSTomasz Figa 		l2x0_saved_regs.tag_latency =
11411a5a954cSRussell King 			L310_LATENCY_CTRL_RD(tag[0] - 1) |
11421a5a954cSRussell King 			L310_LATENCY_CTRL_WR(tag[1] - 1) |
11436b49241aSTomasz Figa 			L310_LATENCY_CTRL_SETUP(tag[2] - 1);
1144da3627fbSRussell King 
1145da3627fbSRussell King 	of_property_read_u32_array(np, "arm,data-latency",
1146da3627fbSRussell King 				   data, ARRAY_SIZE(data));
1147da3627fbSRussell King 	if (data[0] && data[1] && data[2])
11486b49241aSTomasz Figa 		l2x0_saved_regs.data_latency =
11491a5a954cSRussell King 			L310_LATENCY_CTRL_RD(data[0] - 1) |
11501a5a954cSRussell King 			L310_LATENCY_CTRL_WR(data[1] - 1) |
11516b49241aSTomasz Figa 			L310_LATENCY_CTRL_SETUP(data[2] - 1);
1152da3627fbSRussell King 
1153da3627fbSRussell King 	of_property_read_u32_array(np, "arm,filter-ranges",
1154da3627fbSRussell King 				   filter, ARRAY_SIZE(filter));
1155da3627fbSRussell King 	if (filter[1]) {
11566b49241aSTomasz Figa 		l2x0_saved_regs.filter_end =
11576b49241aSTomasz Figa 					ALIGN(filter[0] + filter[1], SZ_1M);
11586b49241aSTomasz Figa 		l2x0_saved_regs.filter_start = (filter[0] & ~(SZ_1M - 1))
11596b49241aSTomasz Figa 					| L310_ADDR_FILTER_EN;
1160da3627fbSRussell King 	}
1161f3354ab6SLinus Walleij 
1162d0b92845SFabio Estevam 	ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_512K);
11635c95ed47SFabrice Gasnier 	if (!ret) {
1164f3354ab6SLinus Walleij 		switch (assoc) {
1165f3354ab6SLinus Walleij 		case 16:
1166f3354ab6SLinus Walleij 			*aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1167f3354ab6SLinus Walleij 			*aux_val |= L310_AUX_CTRL_ASSOCIATIVITY_16;
1168f3354ab6SLinus Walleij 			*aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1169f3354ab6SLinus Walleij 			break;
1170f3354ab6SLinus Walleij 		case 8:
1171f3354ab6SLinus Walleij 			*aux_val &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1172f3354ab6SLinus Walleij 			*aux_mask &= ~L2X0_AUX_CTRL_ASSOC_MASK;
1173f3354ab6SLinus Walleij 			break;
1174f3354ab6SLinus Walleij 		default:
11756d0ec1ddSFabio Estevam 			pr_err("L2C-310 OF cache associativity %d invalid, only 8 or 16 permitted\n",
11766d0ec1ddSFabio Estevam 			       assoc);
1177f3354ab6SLinus Walleij 			break;
1178f3354ab6SLinus Walleij 		}
11795c95ed47SFabrice Gasnier 	}
1180cf0681caSTomasz Figa 
1181eeedcea6SGeert Uytterhoeven 	if (of_property_read_bool(np, "arm,shared-override")) {
1182eeedcea6SGeert Uytterhoeven 		*aux_val |= L2C_AUX_CTRL_SHARED_OVERRIDE;
1183eeedcea6SGeert Uytterhoeven 		*aux_mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
1184eeedcea6SGeert Uytterhoeven 	}
1185eeedcea6SGeert Uytterhoeven 
1186b522842cSLinus Walleij 	if (of_property_read_bool(np, "arm,parity-enable")) {
1187b522842cSLinus Walleij 		*aux_val |= L2C_AUX_CTRL_PARITY_ENABLE;
1188b522842cSLinus Walleij 		*aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
1189b522842cSLinus Walleij 	} else if (of_property_read_bool(np, "arm,parity-disable")) {
1190b522842cSLinus Walleij 		*aux_val &= ~L2C_AUX_CTRL_PARITY_ENABLE;
1191b522842cSLinus Walleij 		*aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
1192b522842cSLinus Walleij 	}
1193b522842cSLinus Walleij 
1194471b5e42SChris Brandt 	if (of_property_read_bool(np, "arm,early-bresp-disable"))
1195471b5e42SChris Brandt 		l2x0_bresp_disable = true;
1196471b5e42SChris Brandt 
1197471b5e42SChris Brandt 	if (of_property_read_bool(np, "arm,full-line-zero-disable"))
1198471b5e42SChris Brandt 		l2x0_flz_disable = true;
1199471b5e42SChris Brandt 
1200cf0681caSTomasz Figa 	prefetch = l2x0_saved_regs.prefetch_ctrl;
1201cf0681caSTomasz Figa 
1202cf0681caSTomasz Figa 	ret = of_property_read_u32(np, "arm,double-linefill", &val);
1203cf0681caSTomasz Figa 	if (ret == 0) {
1204cf0681caSTomasz Figa 		if (val)
1205cf0681caSTomasz Figa 			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL;
1206cf0681caSTomasz Figa 		else
1207cf0681caSTomasz Figa 			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL;
1208cf0681caSTomasz Figa 	} else if (ret != -EINVAL) {
1209cf0681caSTomasz Figa 		pr_err("L2C-310 OF arm,double-linefill property value is missing\n");
1210cf0681caSTomasz Figa 	}
1211cf0681caSTomasz Figa 
1212cf0681caSTomasz Figa 	ret = of_property_read_u32(np, "arm,double-linefill-incr", &val);
1213cf0681caSTomasz Figa 	if (ret == 0) {
1214cf0681caSTomasz Figa 		if (val)
1215cf0681caSTomasz Figa 			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_INCR;
1216cf0681caSTomasz Figa 		else
1217cf0681caSTomasz Figa 			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_INCR;
1218cf0681caSTomasz Figa 	} else if (ret != -EINVAL) {
1219cf0681caSTomasz Figa 		pr_err("L2C-310 OF arm,double-linefill-incr property value is missing\n");
1220cf0681caSTomasz Figa 	}
1221cf0681caSTomasz Figa 
1222cf0681caSTomasz Figa 	ret = of_property_read_u32(np, "arm,double-linefill-wrap", &val);
1223cf0681caSTomasz Figa 	if (ret == 0) {
1224cf0681caSTomasz Figa 		if (!val)
1225cf0681caSTomasz Figa 			prefetch |= L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP;
1226cf0681caSTomasz Figa 		else
1227cf0681caSTomasz Figa 			prefetch &= ~L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP;
1228cf0681caSTomasz Figa 	} else if (ret != -EINVAL) {
1229cf0681caSTomasz Figa 		pr_err("L2C-310 OF arm,double-linefill-wrap property value is missing\n");
1230cf0681caSTomasz Figa 	}
1231cf0681caSTomasz Figa 
1232cf0681caSTomasz Figa 	ret = of_property_read_u32(np, "arm,prefetch-drop", &val);
1233cf0681caSTomasz Figa 	if (ret == 0) {
1234cf0681caSTomasz Figa 		if (val)
1235cf0681caSTomasz Figa 			prefetch |= L310_PREFETCH_CTRL_PREFETCH_DROP;
1236cf0681caSTomasz Figa 		else
1237cf0681caSTomasz Figa 			prefetch &= ~L310_PREFETCH_CTRL_PREFETCH_DROP;
1238cf0681caSTomasz Figa 	} else if (ret != -EINVAL) {
1239cf0681caSTomasz Figa 		pr_err("L2C-310 OF arm,prefetch-drop property value is missing\n");
1240cf0681caSTomasz Figa 	}
1241cf0681caSTomasz Figa 
1242cf0681caSTomasz Figa 	ret = of_property_read_u32(np, "arm,prefetch-offset", &val);
1243cf0681caSTomasz Figa 	if (ret == 0) {
1244cf0681caSTomasz Figa 		prefetch &= ~L310_PREFETCH_CTRL_OFFSET_MASK;
1245cf0681caSTomasz Figa 		prefetch |= val & L310_PREFETCH_CTRL_OFFSET_MASK;
1246cf0681caSTomasz Figa 	} else if (ret != -EINVAL) {
1247cf0681caSTomasz Figa 		pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n");
1248cf0681caSTomasz Figa 	}
1249cf0681caSTomasz Figa 
1250ec3bd0e6SHauke Mehrtens 	ret = of_property_read_u32(np, "prefetch-data", &val);
1251ec3bd0e6SHauke Mehrtens 	if (ret == 0) {
1252*8e007b36SGuillaume Tucker 		if (val) {
1253ec3bd0e6SHauke Mehrtens 			prefetch |= L310_PREFETCH_CTRL_DATA_PREFETCH;
1254*8e007b36SGuillaume Tucker 			*aux_val |= L310_PREFETCH_CTRL_DATA_PREFETCH;
1255*8e007b36SGuillaume Tucker 		} else {
1256ec3bd0e6SHauke Mehrtens 			prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
1257*8e007b36SGuillaume Tucker 			*aux_val &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
1258*8e007b36SGuillaume Tucker 		}
1259*8e007b36SGuillaume Tucker 		*aux_mask &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
1260ec3bd0e6SHauke Mehrtens 	} else if (ret != -EINVAL) {
1261ec3bd0e6SHauke Mehrtens 		pr_err("L2C-310 OF prefetch-data property value is missing\n");
1262ec3bd0e6SHauke Mehrtens 	}
1263ec3bd0e6SHauke Mehrtens 
1264ec3bd0e6SHauke Mehrtens 	ret = of_property_read_u32(np, "prefetch-instr", &val);
1265ec3bd0e6SHauke Mehrtens 	if (ret == 0) {
1266*8e007b36SGuillaume Tucker 		if (val) {
1267ec3bd0e6SHauke Mehrtens 			prefetch |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
1268*8e007b36SGuillaume Tucker 			*aux_val |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
1269*8e007b36SGuillaume Tucker 		} else {
1270ec3bd0e6SHauke Mehrtens 			prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
1271*8e007b36SGuillaume Tucker 			*aux_val &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
1272*8e007b36SGuillaume Tucker 		}
1273*8e007b36SGuillaume Tucker 		*aux_mask &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
1274ec3bd0e6SHauke Mehrtens 	} else if (ret != -EINVAL) {
1275ec3bd0e6SHauke Mehrtens 		pr_err("L2C-310 OF prefetch-instr property value is missing\n");
1276ec3bd0e6SHauke Mehrtens 	}
1277ec3bd0e6SHauke Mehrtens 
1278cf0681caSTomasz Figa 	l2x0_saved_regs.prefetch_ctrl = prefetch;
1279204932dfSBrad Mouring 
1280204932dfSBrad Mouring 	power = l2x0_saved_regs.pwr_ctrl |
1281204932dfSBrad Mouring 		L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN;
1282204932dfSBrad Mouring 
1283204932dfSBrad Mouring 	ret = of_property_read_u32(np, "arm,dynamic-clock-gating", &val);
1284204932dfSBrad Mouring 	if (!ret) {
1285204932dfSBrad Mouring 		if (!val)
1286204932dfSBrad Mouring 			power &= ~L310_DYNAMIC_CLK_GATING_EN;
1287204932dfSBrad Mouring 	} else if (ret != -EINVAL) {
1288204932dfSBrad Mouring 		pr_err("L2C-310 OF dynamic-clock-gating property value is missing or invalid\n");
1289204932dfSBrad Mouring 	}
1290204932dfSBrad Mouring 	ret = of_property_read_u32(np, "arm,standby-mode", &val);
1291204932dfSBrad Mouring 	if (!ret) {
1292204932dfSBrad Mouring 		if (!val)
1293204932dfSBrad Mouring 			power &= ~L310_STNDBY_MODE_EN;
1294204932dfSBrad Mouring 	} else if (ret != -EINVAL) {
1295204932dfSBrad Mouring 		pr_err("L2C-310 OF standby-mode property value is missing or invalid\n");
1296204932dfSBrad Mouring 	}
1297204932dfSBrad Mouring 
1298204932dfSBrad Mouring 	l2x0_saved_regs.pwr_ctrl = power;
1299da3627fbSRussell King }
1300da3627fbSRussell King 
1301f777332bSRussell King static const struct l2c_init_data of_l2c310_data __initconst = {
1302051334bdSRussell King 	.type = "L2C-310",
13030493aef4SRussell King 	.way_size_0 = SZ_8K,
13043b8bad57SRussell King 	.num_lock = 8,
1305f777332bSRussell King 	.of_parse = l2c310_of_parse,
13064374d649SRussell King 	.enable = l2c310_enable,
130775461f5cSRussell King 	.fixup = l2c310_fixup,
130809a5d180SRussell King 	.save  = l2c310_save,
13096b49241aSTomasz Figa 	.configure = l2c310_configure,
1310e946a8cbSRussell King 	.unlock = l2c310_unlock,
1311da3627fbSRussell King 	.outer_cache = {
1312f777332bSRussell King 		.inv_range   = l2c210_inv_range,
1313f777332bSRussell King 		.clean_range = l2c210_clean_range,
1314f777332bSRussell King 		.flush_range = l2c210_flush_range,
1315f777332bSRussell King 		.flush_all   = l2c210_flush_all,
13168ef418c7SRussell King 		.disable     = l2c310_disable,
1317f777332bSRussell King 		.sync        = l2c210_sync,
131809a5d180SRussell King 		.resume      = l2c310_resume,
1319da3627fbSRussell King 	},
1320da3627fbSRussell King };
1321da3627fbSRussell King 
1322b8db6b88SGregory CLEMENT /*
132398ea2dbaSThomas Petazzoni  * This is a variant of the of_l2c310_data with .sync set to
132498ea2dbaSThomas Petazzoni  * NULL. Outer sync operations are not needed when the system is I/O
132598ea2dbaSThomas Petazzoni  * coherent, and potentially harmful in certain situations (PCIe/PL310
132698ea2dbaSThomas Petazzoni  * deadlock on Armada 375/38x due to hardware I/O coherency). The
132798ea2dbaSThomas Petazzoni  * other operations are kept because they are infrequent (therefore do
132898ea2dbaSThomas Petazzoni  * not cause the deadlock in practice) and needed for secondary CPU
132998ea2dbaSThomas Petazzoni  * boot and other power management activities.
133098ea2dbaSThomas Petazzoni  */
133198ea2dbaSThomas Petazzoni static const struct l2c_init_data of_l2c310_coherent_data __initconst = {
133298ea2dbaSThomas Petazzoni 	.type = "L2C-310 Coherent",
133398ea2dbaSThomas Petazzoni 	.way_size_0 = SZ_8K,
133498ea2dbaSThomas Petazzoni 	.num_lock = 8,
133598ea2dbaSThomas Petazzoni 	.of_parse = l2c310_of_parse,
133698ea2dbaSThomas Petazzoni 	.enable = l2c310_enable,
133798ea2dbaSThomas Petazzoni 	.fixup = l2c310_fixup,
133898ea2dbaSThomas Petazzoni 	.save  = l2c310_save,
13396b49241aSTomasz Figa 	.configure = l2c310_configure,
1340e946a8cbSRussell King 	.unlock = l2c310_unlock,
134198ea2dbaSThomas Petazzoni 	.outer_cache = {
134298ea2dbaSThomas Petazzoni 		.inv_range   = l2c210_inv_range,
134398ea2dbaSThomas Petazzoni 		.clean_range = l2c210_clean_range,
134498ea2dbaSThomas Petazzoni 		.flush_range = l2c210_flush_range,
134598ea2dbaSThomas Petazzoni 		.flush_all   = l2c210_flush_all,
134698ea2dbaSThomas Petazzoni 		.disable     = l2c310_disable,
134798ea2dbaSThomas Petazzoni 		.resume      = l2c310_resume,
134898ea2dbaSThomas Petazzoni 	},
134998ea2dbaSThomas Petazzoni };
135098ea2dbaSThomas Petazzoni 
135198ea2dbaSThomas Petazzoni /*
1352b8db6b88SGregory CLEMENT  * Note that the end addresses passed to Linux primitives are
1353b8db6b88SGregory CLEMENT  * noninclusive, while the hardware cache range operations use
1354b8db6b88SGregory CLEMENT  * inclusive start and end addresses.
1355b8db6b88SGregory CLEMENT  */
aurora_range_end(unsigned long start,unsigned long end)13561d889679SArnd Bergmann static unsigned long aurora_range_end(unsigned long start, unsigned long end)
1357b8db6b88SGregory CLEMENT {
1358b8db6b88SGregory CLEMENT 	/*
1359b8db6b88SGregory CLEMENT 	 * Limit the number of cache lines processed at once,
1360b8db6b88SGregory CLEMENT 	 * since cache range operations stall the CPU pipeline
1361b8db6b88SGregory CLEMENT 	 * until completion.
1362b8db6b88SGregory CLEMENT 	 */
13631a85cb4bSJan Luebbe 	if (end > start + AURORA_MAX_RANGE_SIZE)
13641a85cb4bSJan Luebbe 		end = start + AURORA_MAX_RANGE_SIZE;
1365b8db6b88SGregory CLEMENT 
1366b8db6b88SGregory CLEMENT 	/*
1367b8db6b88SGregory CLEMENT 	 * Cache range operations can't straddle a page boundary.
1368b8db6b88SGregory CLEMENT 	 */
1369b8db6b88SGregory CLEMENT 	if (end > PAGE_ALIGN(start+1))
1370b8db6b88SGregory CLEMENT 		end = PAGE_ALIGN(start+1);
1371b8db6b88SGregory CLEMENT 
1372b8db6b88SGregory CLEMENT 	return end;
1373b8db6b88SGregory CLEMENT }
1374b8db6b88SGregory CLEMENT 
aurora_pa_range(unsigned long start,unsigned long end,unsigned long offset)1375b8db6b88SGregory CLEMENT static void aurora_pa_range(unsigned long start, unsigned long end,
1376b8db6b88SGregory CLEMENT 			    unsigned long offset)
1377b8db6b88SGregory CLEMENT {
137820e783e3SArnd Bergmann 	void __iomem *base = l2x0_base;
13791d889679SArnd Bergmann 	unsigned long range_end;
1380b8db6b88SGregory CLEMENT 	unsigned long flags;
1381b8db6b88SGregory CLEMENT 
1382b8db6b88SGregory CLEMENT 	/*
1383b8db6b88SGregory CLEMENT 	 * round start and end adresses up to cache line size
1384b8db6b88SGregory CLEMENT 	 */
1385b8db6b88SGregory CLEMENT 	start &= ~(CACHE_LINE_SIZE - 1);
1386b8db6b88SGregory CLEMENT 	end = ALIGN(end, CACHE_LINE_SIZE);
1387b8db6b88SGregory CLEMENT 
1388b8db6b88SGregory CLEMENT 	/*
13891d889679SArnd Bergmann 	 * perform operation on all full cache lines between 'start' and 'end'
1390b8db6b88SGregory CLEMENT 	 */
1391b8db6b88SGregory CLEMENT 	while (start < end) {
13921d889679SArnd Bergmann 		range_end = aurora_range_end(start, end);
13931d889679SArnd Bergmann 
13941d889679SArnd Bergmann 		raw_spin_lock_irqsave(&l2x0_lock, flags);
13951d889679SArnd Bergmann 		writel_relaxed(start, base + AURORA_RANGE_BASE_ADDR_REG);
13961d889679SArnd Bergmann 		writel_relaxed(range_end - CACHE_LINE_SIZE, base + offset);
13971d889679SArnd Bergmann 		raw_spin_unlock_irqrestore(&l2x0_lock, flags);
13981d889679SArnd Bergmann 
13991d889679SArnd Bergmann 		writel_relaxed(0, base + AURORA_SYNC_REG);
1400b8db6b88SGregory CLEMENT 		start = range_end;
1401b8db6b88SGregory CLEMENT 	}
1402b8db6b88SGregory CLEMENT }
aurora_inv_range(unsigned long start,unsigned long end)14031d889679SArnd Bergmann static void aurora_inv_range(unsigned long start, unsigned long end)
14041d889679SArnd Bergmann {
14051d889679SArnd Bergmann 	aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG);
14061d889679SArnd Bergmann }
1407b8db6b88SGregory CLEMENT 
aurora_clean_range(unsigned long start,unsigned long end)1408b8db6b88SGregory CLEMENT static void aurora_clean_range(unsigned long start, unsigned long end)
1409b8db6b88SGregory CLEMENT {
1410b8db6b88SGregory CLEMENT 	/*
1411b8db6b88SGregory CLEMENT 	 * If L2 is forced to WT, the L2 will always be clean and we
1412b8db6b88SGregory CLEMENT 	 * don't need to do anything here.
1413b8db6b88SGregory CLEMENT 	 */
14141d889679SArnd Bergmann 	if (!l2_wt_override)
14151d889679SArnd Bergmann 		aurora_pa_range(start, end, AURORA_CLEAN_RANGE_REG);
1416b8db6b88SGregory CLEMENT }
1417b8db6b88SGregory CLEMENT 
aurora_flush_range(unsigned long start,unsigned long end)1418b8db6b88SGregory CLEMENT static void aurora_flush_range(unsigned long start, unsigned long end)
1419b8db6b88SGregory CLEMENT {
14208b827c60SGregory CLEMENT 	if (l2_wt_override)
14211d889679SArnd Bergmann 		aurora_pa_range(start, end, AURORA_INVAL_RANGE_REG);
14228b827c60SGregory CLEMENT 	else
14231d889679SArnd Bergmann 		aurora_pa_range(start, end, AURORA_FLUSH_RANGE_REG);
1424b8db6b88SGregory CLEMENT }
1425b8db6b88SGregory CLEMENT 
aurora_flush_all(void)142620e783e3SArnd Bergmann static void aurora_flush_all(void)
142720e783e3SArnd Bergmann {
142820e783e3SArnd Bergmann 	void __iomem *base = l2x0_base;
142920e783e3SArnd Bergmann 	unsigned long flags;
143020e783e3SArnd Bergmann 
143120e783e3SArnd Bergmann 	/* clean all ways */
143220e783e3SArnd Bergmann 	raw_spin_lock_irqsave(&l2x0_lock, flags);
143320e783e3SArnd Bergmann 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
143420e783e3SArnd Bergmann 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
143520e783e3SArnd Bergmann 
143620e783e3SArnd Bergmann 	writel_relaxed(0, base + AURORA_SYNC_REG);
143720e783e3SArnd Bergmann }
143820e783e3SArnd Bergmann 
aurora_cache_sync(void)143920e783e3SArnd Bergmann static void aurora_cache_sync(void)
144020e783e3SArnd Bergmann {
144120e783e3SArnd Bergmann 	writel_relaxed(0, l2x0_base + AURORA_SYNC_REG);
144220e783e3SArnd Bergmann }
144320e783e3SArnd Bergmann 
aurora_disable(void)144420e783e3SArnd Bergmann static void aurora_disable(void)
144520e783e3SArnd Bergmann {
144620e783e3SArnd Bergmann 	void __iomem *base = l2x0_base;
144720e783e3SArnd Bergmann 	unsigned long flags;
144820e783e3SArnd Bergmann 
144920e783e3SArnd Bergmann 	raw_spin_lock_irqsave(&l2x0_lock, flags);
145020e783e3SArnd Bergmann 	__l2c_op_way(base + L2X0_CLEAN_INV_WAY);
145120e783e3SArnd Bergmann 	writel_relaxed(0, base + AURORA_SYNC_REG);
145220e783e3SArnd Bergmann 	l2c_write_sec(0, base, L2X0_CTRL);
145320e783e3SArnd Bergmann 	dsb(st);
145420e783e3SArnd Bergmann 	raw_spin_unlock_irqrestore(&l2x0_lock, flags);
14558c369264SRob Herring }
14568c369264SRob Herring 
aurora_save(void __iomem * base)1457da3627fbSRussell King static void aurora_save(void __iomem *base)
1458da3627fbSRussell King {
1459da3627fbSRussell King 	l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL);
1460da3627fbSRussell King 	l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL);
1461da3627fbSRussell King }
1462da3627fbSRussell King 
146340266d6fSRussell King /*
146440266d6fSRussell King  * For Aurora cache in no outer mode, enable via the CP15 coprocessor
146540266d6fSRussell King  * broadcasting of cache commands to L2.
146640266d6fSRussell King  */
aurora_enable_no_outer(void __iomem * base,unsigned num_lock)14675b290ec2SRussell King static void __init aurora_enable_no_outer(void __iomem *base,
146840266d6fSRussell King 	unsigned num_lock)
1469da3627fbSRussell King {
147040266d6fSRussell King 	u32 u;
147140266d6fSRussell King 
147240266d6fSRussell King 	asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u));
1473da3627fbSRussell King 	u |= AURORA_CTRL_FW;		/* Set the FW bit */
147440266d6fSRussell King 	asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u));
147540266d6fSRussell King 
1476da3627fbSRussell King 	isb();
147740266d6fSRussell King 
14785b290ec2SRussell King 	l2c_enable(base, num_lock);
1479da3627fbSRussell King }
1480da3627fbSRussell King 
aurora_fixup(void __iomem * base,u32 cache_id,struct outer_cache_fns * fns)148175461f5cSRussell King static void __init aurora_fixup(void __iomem *base, u32 cache_id,
148275461f5cSRussell King 	struct outer_cache_fns *fns)
148375461f5cSRussell King {
148475461f5cSRussell King 	sync_reg_offset = AURORA_SYNC_REG;
148575461f5cSRussell King }
148675461f5cSRussell King 
aurora_of_parse(const struct device_node * np,u32 * aux_val,u32 * aux_mask)1487da3627fbSRussell King static void __init aurora_of_parse(const struct device_node *np,
1488da3627fbSRussell King 				u32 *aux_val, u32 *aux_mask)
1489da3627fbSRussell King {
1490da3627fbSRussell King 	u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU;
1491da3627fbSRussell King 	u32 mask =  AURORA_ACR_REPLACEMENT_MASK;
1492da3627fbSRussell King 
1493da3627fbSRussell King 	of_property_read_u32(np, "cache-id-part",
1494da3627fbSRussell King 			&cache_id_part_number_from_dt);
1495da3627fbSRussell King 
1496da3627fbSRussell King 	/* Determine and save the write policy */
1497da3627fbSRussell King 	l2_wt_override = of_property_read_bool(np, "wt-override");
1498da3627fbSRussell King 
1499da3627fbSRussell King 	if (l2_wt_override) {
1500da3627fbSRussell King 		val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY;
1501da3627fbSRussell King 		mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
1502da3627fbSRussell King 	}
1503da3627fbSRussell King 
1504c8abbd6fSChris Packham 	if (of_property_read_bool(np, "marvell,ecc-enable")) {
1505c8abbd6fSChris Packham 		mask |= AURORA_ACR_ECC_EN;
1506c8abbd6fSChris Packham 		val |= AURORA_ACR_ECC_EN;
1507c8abbd6fSChris Packham 	}
1508c8abbd6fSChris Packham 
1509fd3bbde7SChris Packham 	if (of_property_read_bool(np, "arm,parity-enable")) {
1510fd3bbde7SChris Packham 		mask |= AURORA_ACR_PARITY_EN;
1511fd3bbde7SChris Packham 		val |= AURORA_ACR_PARITY_EN;
1512fd3bbde7SChris Packham 	} else if (of_property_read_bool(np, "arm,parity-disable")) {
1513fd3bbde7SChris Packham 		mask |= AURORA_ACR_PARITY_EN;
1514fd3bbde7SChris Packham 	}
1515fd3bbde7SChris Packham 
1516da3627fbSRussell King 	*aux_val &= ~mask;
1517da3627fbSRussell King 	*aux_val |= val;
1518da3627fbSRussell King 	*aux_mask &= ~mask;
1519da3627fbSRussell King }
1520da3627fbSRussell King 
1521da3627fbSRussell King static const struct l2c_init_data of_aurora_with_outer_data __initconst = {
1522051334bdSRussell King 	.type = "Aurora",
15230493aef4SRussell King 	.way_size_0 = SZ_4K,
15243b8bad57SRussell King 	.num_lock = 4,
1525da3627fbSRussell King 	.of_parse = aurora_of_parse,
15263b8bad57SRussell King 	.enable = l2c_enable,
152775461f5cSRussell King 	.fixup = aurora_fixup,
1528da3627fbSRussell King 	.save  = aurora_save,
152950beefdeSRussell King 	.configure = l2c_configure,
1530e946a8cbSRussell King 	.unlock = l2c_unlock,
1531da3627fbSRussell King 	.outer_cache = {
1532da3627fbSRussell King 		.inv_range   = aurora_inv_range,
1533da3627fbSRussell King 		.clean_range = aurora_clean_range,
1534da3627fbSRussell King 		.flush_range = aurora_flush_range,
153520e783e3SArnd Bergmann 		.flush_all   = aurora_flush_all,
153620e783e3SArnd Bergmann 		.disable     = aurora_disable,
153720e783e3SArnd Bergmann 		.sync	     = aurora_cache_sync,
15386b49241aSTomasz Figa 		.resume      = l2c_resume,
1539da3627fbSRussell King 	},
1540da3627fbSRussell King };
1541da3627fbSRussell King 
1542da3627fbSRussell King static const struct l2c_init_data of_aurora_no_outer_data __initconst = {
1543051334bdSRussell King 	.type = "Aurora",
15440493aef4SRussell King 	.way_size_0 = SZ_4K,
15453b8bad57SRussell King 	.num_lock = 4,
1546da3627fbSRussell King 	.of_parse = aurora_of_parse,
154740266d6fSRussell King 	.enable = aurora_enable_no_outer,
154875461f5cSRussell King 	.fixup = aurora_fixup,
1549da3627fbSRussell King 	.save  = aurora_save,
155050beefdeSRussell King 	.configure = l2c_configure,
1551e946a8cbSRussell King 	.unlock = l2c_unlock,
1552da3627fbSRussell King 	.outer_cache = {
15536b49241aSTomasz Figa 		.resume      = l2c_resume,
1554da3627fbSRussell King 	},
1555da3627fbSRussell King };
1556da3627fbSRussell King 
15573b656fedSChristian Daudt /*
15583b656fedSChristian Daudt  * For certain Broadcom SoCs, depending on the address range, different offsets
15593b656fedSChristian Daudt  * need to be added to the address before passing it to L2 for
15603b656fedSChristian Daudt  * invalidation/clean/flush
15613b656fedSChristian Daudt  *
15623b656fedSChristian Daudt  * Section Address Range              Offset        EMI
15633b656fedSChristian Daudt  *   1     0x00000000 - 0x3FFFFFFF    0x80000000    VC
15643b656fedSChristian Daudt  *   2     0x40000000 - 0xBFFFFFFF    0x40000000    SYS
15653b656fedSChristian Daudt  *   3     0xC0000000 - 0xFFFFFFFF    0x80000000    VC
15663b656fedSChristian Daudt  *
15673b656fedSChristian Daudt  * When the start and end addresses have crossed two different sections, we
15683b656fedSChristian Daudt  * need to break the L2 operation into two, each within its own section.
15693b656fedSChristian Daudt  * For example, if we need to invalidate addresses starts at 0xBFFF0000 and
15703b656fedSChristian Daudt  * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2)
15713b656fedSChristian Daudt  * 0xC0000000 - 0xC0001000
15723b656fedSChristian Daudt  *
15733b656fedSChristian Daudt  * Note 1:
15743b656fedSChristian Daudt  * By breaking a single L2 operation into two, we may potentially suffer some
15753b656fedSChristian Daudt  * performance hit, but keep in mind the cross section case is very rare
15763b656fedSChristian Daudt  *
15773b656fedSChristian Daudt  * Note 2:
15783b656fedSChristian Daudt  * We do not need to handle the case when the start address is in
15793b656fedSChristian Daudt  * Section 1 and the end address is in Section 3, since it is not a valid use
15803b656fedSChristian Daudt  * case
15813b656fedSChristian Daudt  *
15823b656fedSChristian Daudt  * Note 3:
15833b656fedSChristian Daudt  * Section 1 in practical terms can no longer be used on rev A2. Because of
15843b656fedSChristian Daudt  * that the code does not need to handle section 1 at all.
15853b656fedSChristian Daudt  *
15863b656fedSChristian Daudt  */
15873b656fedSChristian Daudt #define BCM_SYS_EMI_START_ADDR        0x40000000UL
15883b656fedSChristian Daudt #define BCM_VC_EMI_SEC3_START_ADDR    0xC0000000UL
15893b656fedSChristian Daudt 
15903b656fedSChristian Daudt #define BCM_SYS_EMI_OFFSET            0x40000000UL
15913b656fedSChristian Daudt #define BCM_VC_EMI_OFFSET             0x80000000UL
15923b656fedSChristian Daudt 
bcm_addr_is_sys_emi(unsigned long addr)15933b656fedSChristian Daudt static inline int bcm_addr_is_sys_emi(unsigned long addr)
15943b656fedSChristian Daudt {
15953b656fedSChristian Daudt 	return (addr >= BCM_SYS_EMI_START_ADDR) &&
15963b656fedSChristian Daudt 		(addr < BCM_VC_EMI_SEC3_START_ADDR);
15973b656fedSChristian Daudt }
15983b656fedSChristian Daudt 
bcm_l2_phys_addr(unsigned long addr)15993b656fedSChristian Daudt static inline unsigned long bcm_l2_phys_addr(unsigned long addr)
16003b656fedSChristian Daudt {
16013b656fedSChristian Daudt 	if (bcm_addr_is_sys_emi(addr))
16023b656fedSChristian Daudt 		return addr + BCM_SYS_EMI_OFFSET;
16033b656fedSChristian Daudt 	else
16043b656fedSChristian Daudt 		return addr + BCM_VC_EMI_OFFSET;
16053b656fedSChristian Daudt }
16063b656fedSChristian Daudt 
bcm_inv_range(unsigned long start,unsigned long end)16073b656fedSChristian Daudt static void bcm_inv_range(unsigned long start, unsigned long end)
16083b656fedSChristian Daudt {
16093b656fedSChristian Daudt 	unsigned long new_start, new_end;
16103b656fedSChristian Daudt 
16113b656fedSChristian Daudt 	BUG_ON(start < BCM_SYS_EMI_START_ADDR);
16123b656fedSChristian Daudt 
16133b656fedSChristian Daudt 	if (unlikely(end <= start))
16143b656fedSChristian Daudt 		return;
16153b656fedSChristian Daudt 
16163b656fedSChristian Daudt 	new_start = bcm_l2_phys_addr(start);
16173b656fedSChristian Daudt 	new_end = bcm_l2_phys_addr(end);
16183b656fedSChristian Daudt 
16193b656fedSChristian Daudt 	/* normal case, no cross section between start and end */
16203b656fedSChristian Daudt 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
162190811148SRussell King 		l2c210_inv_range(new_start, new_end);
16223b656fedSChristian Daudt 		return;
16233b656fedSChristian Daudt 	}
16243b656fedSChristian Daudt 
16253b656fedSChristian Daudt 	/* They cross sections, so it can only be a cross from section
16263b656fedSChristian Daudt 	 * 2 to section 3
16273b656fedSChristian Daudt 	 */
162890811148SRussell King 	l2c210_inv_range(new_start,
16293b656fedSChristian Daudt 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
163090811148SRussell King 	l2c210_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
16313b656fedSChristian Daudt 		new_end);
16323b656fedSChristian Daudt }
16333b656fedSChristian Daudt 
bcm_clean_range(unsigned long start,unsigned long end)16343b656fedSChristian Daudt static void bcm_clean_range(unsigned long start, unsigned long end)
16353b656fedSChristian Daudt {
16363b656fedSChristian Daudt 	unsigned long new_start, new_end;
16373b656fedSChristian Daudt 
16383b656fedSChristian Daudt 	BUG_ON(start < BCM_SYS_EMI_START_ADDR);
16393b656fedSChristian Daudt 
16403b656fedSChristian Daudt 	if (unlikely(end <= start))
16413b656fedSChristian Daudt 		return;
16423b656fedSChristian Daudt 
16433b656fedSChristian Daudt 	new_start = bcm_l2_phys_addr(start);
16443b656fedSChristian Daudt 	new_end = bcm_l2_phys_addr(end);
16453b656fedSChristian Daudt 
16463b656fedSChristian Daudt 	/* normal case, no cross section between start and end */
16473b656fedSChristian Daudt 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
164890811148SRussell King 		l2c210_clean_range(new_start, new_end);
16493b656fedSChristian Daudt 		return;
16503b656fedSChristian Daudt 	}
16513b656fedSChristian Daudt 
16523b656fedSChristian Daudt 	/* They cross sections, so it can only be a cross from section
16533b656fedSChristian Daudt 	 * 2 to section 3
16543b656fedSChristian Daudt 	 */
165590811148SRussell King 	l2c210_clean_range(new_start,
16563b656fedSChristian Daudt 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
165790811148SRussell King 	l2c210_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
16583b656fedSChristian Daudt 		new_end);
16593b656fedSChristian Daudt }
16603b656fedSChristian Daudt 
bcm_flush_range(unsigned long start,unsigned long end)16613b656fedSChristian Daudt static void bcm_flush_range(unsigned long start, unsigned long end)
16623b656fedSChristian Daudt {
16633b656fedSChristian Daudt 	unsigned long new_start, new_end;
16643b656fedSChristian Daudt 
16653b656fedSChristian Daudt 	BUG_ON(start < BCM_SYS_EMI_START_ADDR);
16663b656fedSChristian Daudt 
16673b656fedSChristian Daudt 	if (unlikely(end <= start))
16683b656fedSChristian Daudt 		return;
16693b656fedSChristian Daudt 
16703b656fedSChristian Daudt 	if ((end - start) >= l2x0_size) {
167190811148SRussell King 		outer_cache.flush_all();
16723b656fedSChristian Daudt 		return;
16733b656fedSChristian Daudt 	}
16743b656fedSChristian Daudt 
16753b656fedSChristian Daudt 	new_start = bcm_l2_phys_addr(start);
16763b656fedSChristian Daudt 	new_end = bcm_l2_phys_addr(end);
16773b656fedSChristian Daudt 
16783b656fedSChristian Daudt 	/* normal case, no cross section between start and end */
16793b656fedSChristian Daudt 	if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
168090811148SRussell King 		l2c210_flush_range(new_start, new_end);
16813b656fedSChristian Daudt 		return;
16823b656fedSChristian Daudt 	}
16833b656fedSChristian Daudt 
16843b656fedSChristian Daudt 	/* They cross sections, so it can only be a cross from section
16853b656fedSChristian Daudt 	 * 2 to section 3
16863b656fedSChristian Daudt 	 */
168790811148SRussell King 	l2c210_flush_range(new_start,
16883b656fedSChristian Daudt 		bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
168990811148SRussell King 	l2c210_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
16903b656fedSChristian Daudt 		new_end);
16913b656fedSChristian Daudt }
16923b656fedSChristian Daudt 
169390811148SRussell King /* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */
1694da3627fbSRussell King static const struct l2c_init_data of_bcm_l2x0_data __initconst = {
1695051334bdSRussell King 	.type = "BCM-L2C-310",
16960493aef4SRussell King 	.way_size_0 = SZ_8K,
16973b8bad57SRussell King 	.num_lock = 8,
1698f777332bSRussell King 	.of_parse = l2c310_of_parse,
16994374d649SRussell King 	.enable = l2c310_enable,
170009a5d180SRussell King 	.save  = l2c310_save,
17016b49241aSTomasz Figa 	.configure = l2c310_configure,
1702e946a8cbSRussell King 	.unlock = l2c310_unlock,
1703da3627fbSRussell King 	.outer_cache = {
1704da3627fbSRussell King 		.inv_range   = bcm_inv_range,
1705da3627fbSRussell King 		.clean_range = bcm_clean_range,
1706da3627fbSRussell King 		.flush_range = bcm_flush_range,
1707f777332bSRussell King 		.flush_all   = l2c210_flush_all,
17088ef418c7SRussell King 		.disable     = l2c310_disable,
1709f777332bSRussell King 		.sync        = l2c210_sync,
171009a5d180SRussell King 		.resume      = l2c310_resume,
1711da3627fbSRussell King 	},
1712da3627fbSRussell King };
1713b8db6b88SGregory CLEMENT 
tauros3_save(void __iomem * base)17149846dfc9SRussell King static void __init tauros3_save(void __iomem *base)
1715e68f31f4SSebastian Hesselbarth {
1716ddf7d79bSRussell King 	l2c_save(base);
1717ddf7d79bSRussell King 
1718e68f31f4SSebastian Hesselbarth 	l2x0_saved_regs.aux2_ctrl =
17199846dfc9SRussell King 		readl_relaxed(base + TAUROS3_AUX2_CTRL);
1720e68f31f4SSebastian Hesselbarth 	l2x0_saved_regs.prefetch_ctrl =
17211a5a954cSRussell King 		readl_relaxed(base + L310_PREFETCH_CTRL);
1722e68f31f4SSebastian Hesselbarth }
1723e68f31f4SSebastian Hesselbarth 
tauros3_configure(void __iomem * base)17246b49241aSTomasz Figa static void tauros3_configure(void __iomem *base)
1725e68f31f4SSebastian Hesselbarth {
172650beefdeSRussell King 	l2c_configure(base);
172709a5d180SRussell King 	writel_relaxed(l2x0_saved_regs.aux2_ctrl,
172809a5d180SRussell King 		       base + TAUROS3_AUX2_CTRL);
172909a5d180SRussell King 	writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
17301a5a954cSRussell King 		       base + L310_PREFETCH_CTRL);
1731e68f31f4SSebastian Hesselbarth }
1732e68f31f4SSebastian Hesselbarth 
1733c02642bcSRussell King static const struct l2c_init_data of_tauros3_data __initconst = {
1734051334bdSRussell King 	.type = "Tauros3",
17350493aef4SRussell King 	.way_size_0 = SZ_8K,
17363b8bad57SRussell King 	.num_lock = 8,
17373b8bad57SRussell King 	.enable = l2c_enable,
1738e68f31f4SSebastian Hesselbarth 	.save  = tauros3_save,
17396b49241aSTomasz Figa 	.configure = tauros3_configure,
1740e946a8cbSRussell King 	.unlock = l2c_unlock,
1741e68f31f4SSebastian Hesselbarth 	/* Tauros3 broadcasts L1 cache operations to L2 */
1742e68f31f4SSebastian Hesselbarth 	.outer_cache = {
17436b49241aSTomasz Figa 		.resume      = l2c_resume,
1744e68f31f4SSebastian Hesselbarth 	},
1745e68f31f4SSebastian Hesselbarth };
1746e68f31f4SSebastian Hesselbarth 
1747a65bb925SRussell King #define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns }
17488c369264SRob Herring static const struct of_device_id l2x0_ids[] __initconst = {
17496a28cf59SRussell King 	L2C_ID("arm,l210-cache", of_l2c210_data),
1750733c6bbaSRussell King 	L2C_ID("arm,l220-cache", of_l2c220_data),
1751f777332bSRussell King 	L2C_ID("arm,pl310-cache", of_l2c310_data),
1752c02642bcSRussell King 	L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
1753c02642bcSRussell King 	L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data),
1754c02642bcSRussell King 	L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data),
1755c02642bcSRussell King 	L2C_ID("marvell,tauros3-cache", of_tauros3_data),
1756a65bb925SRussell King 	/* Deprecated IDs */
1757c02642bcSRussell King 	L2C_ID("bcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data),
17588c369264SRob Herring 	{}
17598c369264SRob Herring };
17608c369264SRob Herring 
l2x0_of_init(u32 aux_val,u32 aux_mask)17613e175ca4SRussell King int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
17628c369264SRob Herring {
1763c02642bcSRussell King 	const struct l2c_init_data *data;
17648c369264SRob Herring 	struct device_node *np;
176591c2ebb9SBarry Song 	struct resource res;
1766560be613SRussell King 	u32 cache_id, old_aux;
17671b4bd608SFlorian Fainelli 	u32 cache_level = 2;
176836f46d6dSLinus Walleij 	bool nosync = false;
17698c369264SRob Herring 
17708c369264SRob Herring 	np = of_find_matching_node(NULL, l2x0_ids);
17718c369264SRob Herring 	if (!np)
17728c369264SRob Herring 		return -ENODEV;
177391c2ebb9SBarry Song 
177491c2ebb9SBarry Song 	if (of_address_to_resource(np, 0, &res))
177591c2ebb9SBarry Song 		return -ENODEV;
177691c2ebb9SBarry Song 
177791c2ebb9SBarry Song 	l2x0_base = ioremap(res.start, resource_size(&res));
17788c369264SRob Herring 	if (!l2x0_base)
17798c369264SRob Herring 		return -ENOMEM;
17808c369264SRob Herring 
178191c2ebb9SBarry Song 	l2x0_saved_regs.phy_base = res.start;
178291c2ebb9SBarry Song 
178391c2ebb9SBarry Song 	data = of_match_node(l2x0_ids, np)->data;
178491c2ebb9SBarry Song 
178598ea2dbaSThomas Petazzoni 	if (of_device_is_compatible(np, "arm,pl310-cache") &&
178698ea2dbaSThomas Petazzoni 	    of_property_read_bool(np, "arm,io-coherent"))
178798ea2dbaSThomas Petazzoni 		data = &of_l2c310_coherent_data;
178898ea2dbaSThomas Petazzoni 
1789560be613SRussell King 	old_aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
1790560be613SRussell King 	if (old_aux != ((old_aux & aux_mask) | aux_val)) {
1791560be613SRussell King 		pr_warn("L2C: platform modifies aux control register: 0x%08x -> 0x%08x\n",
1792560be613SRussell King 		        old_aux, (old_aux & aux_mask) | aux_val);
1793560be613SRussell King 	} else if (aux_mask != ~0U && aux_val != 0) {
1794560be613SRussell King 		pr_alert("L2C: platform provided aux values match the hardware, so have no effect.  Please remove them.\n");
1795560be613SRussell King 	}
1796560be613SRussell King 
1797d9d1f3e2SRussell King 	/* All L2 caches are unified, so this property should be specified */
1798d9d1f3e2SRussell King 	if (!of_property_read_bool(np, "cache-unified"))
1799d9d1f3e2SRussell King 		pr_err("L2C: device tree omits to specify unified cache\n");
1800d9d1f3e2SRussell King 
18011b4bd608SFlorian Fainelli 	if (of_property_read_u32(np, "cache-level", &cache_level))
18021b4bd608SFlorian Fainelli 		pr_err("L2C: device tree omits to specify cache-level\n");
18031b4bd608SFlorian Fainelli 
18041b4bd608SFlorian Fainelli 	if (cache_level != 2)
18051b4bd608SFlorian Fainelli 		pr_err("L2C: device tree specifies invalid cache level\n");
18061b4bd608SFlorian Fainelli 
180736f46d6dSLinus Walleij 	nosync = of_property_read_bool(np, "arm,outer-sync-disable");
180836f46d6dSLinus Walleij 
18096b49241aSTomasz Figa 	/* Read back current (default) hardware configuration */
18106b49241aSTomasz Figa 	if (data->save)
18116b49241aSTomasz Figa 		data->save(l2x0_base);
18126b49241aSTomasz Figa 
18138c369264SRob Herring 	/* L2 configuration can only be changed if the cache is disabled */
181440266d6fSRussell King 	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
1815c02642bcSRussell King 		if (data->of_parse)
1816c02642bcSRussell King 			data->of_parse(np, &aux_val, &aux_mask);
1817b8db6b88SGregory CLEMENT 
181896054b0aSRussell King 	if (cache_id_part_number_from_dt)
181996054b0aSRussell King 		cache_id = cache_id_part_number_from_dt;
182096054b0aSRussell King 	else
182196054b0aSRussell King 		cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
182296054b0aSRussell King 
182336f46d6dSLinus Walleij 	return __l2c_init(data, aux_val, aux_mask, cache_id, nosync);
18248c369264SRob Herring }
18258c369264SRob Herring #endif
1826