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