ARM: 7547/4: cache-l2x0: add support for Aurora L2 cache ctrl
Aurora Cache Controller was designed to be compatible with the ARM L2 Cache Controller. It comes with some difference or improvement such as: - no cache id part number available through hardware (need to get it by the DT). - always write through mode available. - two flavors of the controller outer cache and system cache (meaning maintenance operations on L1 are broadcasted to the L2 and L2 performs the same operation). - in outer cache mode, the cache maintenance operations are improved and can be done on a range inside a page and are not limited to a cache line. Tested-and-Reviewed-by: Lior Amsalem <alior@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Yehuda Yitschak <yehuday@marvell.com> Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
		
					parent
					
						
							
								c3545236e8
							
						
					
				
			
			
				commit
				
					
						b8db6b886a
					
				
			
		
					 3 changed files with 269 additions and 13 deletions
				
			
		| 
						 | 
					@ -102,6 +102,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define L2X0_ADDR_FILTER_EN		1
 | 
					#define L2X0_ADDR_FILTER_EN		1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define L2X0_CTRL_EN			1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define L2X0_WAY_SIZE_SHIFT		3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __ASSEMBLY__
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
 | 
					extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
 | 
				
			||||||
#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
 | 
					#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										55
									
								
								arch/arm/mm/cache-aurora-l2.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								arch/arm/mm/cache-aurora-l2.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * AURORA shared L2 cache controller support
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2012 Marvell
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Yehuda Yitschak <yehuday@marvell.com>
 | 
				
			||||||
 | 
					 * Gregory CLEMENT <gregory.clement@free-electrons.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is licensed under the terms of the GNU General Public
 | 
				
			||||||
 | 
					 * License version 2.  This program is licensed "as is" without any
 | 
				
			||||||
 | 
					 * warranty of any kind, whether express or implied.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASM_ARM_HARDWARE_AURORA_L2_H
 | 
				
			||||||
 | 
					#define __ASM_ARM_HARDWARE_AURORA_L2_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AURORA_SYNC_REG		    0x700
 | 
				
			||||||
 | 
					#define AURORA_RANGE_BASE_ADDR_REG  0x720
 | 
				
			||||||
 | 
					#define AURORA_FLUSH_PHY_ADDR_REG   0x7f0
 | 
				
			||||||
 | 
					#define AURORA_INVAL_RANGE_REG	    0x774
 | 
				
			||||||
 | 
					#define AURORA_CLEAN_RANGE_REG	    0x7b4
 | 
				
			||||||
 | 
					#define AURORA_FLUSH_RANGE_REG	    0x7f4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AURORA_ACR_REPLACEMENT_OFFSET	    27
 | 
				
			||||||
 | 
					#define AURORA_ACR_REPLACEMENT_MASK	     \
 | 
				
			||||||
 | 
						(0x3 << AURORA_ACR_REPLACEMENT_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_REPLACEMENT_TYPE_WAYRR    \
 | 
				
			||||||
 | 
						(0 << AURORA_ACR_REPLACEMENT_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_REPLACEMENT_TYPE_LFSR     \
 | 
				
			||||||
 | 
						(1 << AURORA_ACR_REPLACEMENT_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU \
 | 
				
			||||||
 | 
						(3 << AURORA_ACR_REPLACEMENT_OFFSET)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AURORA_ACR_FORCE_WRITE_POLICY_OFFSET	0
 | 
				
			||||||
 | 
					#define AURORA_ACR_FORCE_WRITE_POLICY_MASK	\
 | 
				
			||||||
 | 
						(0x3 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_FORCE_WRITE_POLICY_DIS	\
 | 
				
			||||||
 | 
						(0 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_FORCE_WRITE_BACK_POLICY	\
 | 
				
			||||||
 | 
						(1 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
 | 
				
			||||||
 | 
					#define AURORA_ACR_FORCE_WRITE_THRO_POLICY	\
 | 
				
			||||||
 | 
						(2 << AURORA_ACR_FORCE_WRITE_POLICY_OFFSET)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_RANGE_SIZE		1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AURORA_WAY_SIZE_SHIFT	2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AURORA_CTRL_FW		0x100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* chose a number outside L2X0_CACHE_ID_PART_MASK to be sure to make
 | 
				
			||||||
 | 
					 * the distinction between a number coming from hardware and a number
 | 
				
			||||||
 | 
					 * coming from the device tree */
 | 
				
			||||||
 | 
					#define AURORA_CACHE_ID	       0x100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __ASM_ARM_HARDWARE_AURORA_L2_H */
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/cacheflush.h>
 | 
					#include <asm/cacheflush.h>
 | 
				
			||||||
#include <asm/hardware/cache-l2x0.h>
 | 
					#include <asm/hardware/cache-l2x0.h>
 | 
				
			||||||
 | 
					#include "cache-aurora-l2.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CACHE_LINE_SIZE		32
 | 
					#define CACHE_LINE_SIZE		32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +35,10 @@ static u32 l2x0_way_mask;	/* Bitmask of active ways */
 | 
				
			||||||
static u32 l2x0_size;
 | 
					static u32 l2x0_size;
 | 
				
			||||||
static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
 | 
					static unsigned long sync_reg_offset = L2X0_CACHE_SYNC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Aurora don't have the cache ID register available, so we have to
 | 
				
			||||||
 | 
					 * pass it though the device tree */
 | 
				
			||||||
 | 
					static u32  cache_id_part_number_from_dt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct l2x0_regs l2x0_saved_regs;
 | 
					struct l2x0_regs l2x0_saved_regs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct l2x0_of_data {
 | 
					struct l2x0_of_data {
 | 
				
			||||||
| 
						 | 
					@ -170,7 +175,7 @@ static void l2x0_inv_all(void)
 | 
				
			||||||
	/* invalidate all ways */
 | 
						/* invalidate all ways */
 | 
				
			||||||
	raw_spin_lock_irqsave(&l2x0_lock, flags);
 | 
						raw_spin_lock_irqsave(&l2x0_lock, flags);
 | 
				
			||||||
	/* Invalidating when L2 is enabled is a nono */
 | 
						/* Invalidating when L2 is enabled is a nono */
 | 
				
			||||||
	BUG_ON(readl(l2x0_base + L2X0_CTRL) & 1);
 | 
						BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN);
 | 
				
			||||||
	writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
 | 
						writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY);
 | 
				
			||||||
	cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
 | 
						cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask);
 | 
				
			||||||
	cache_sync();
 | 
						cache_sync();
 | 
				
			||||||
| 
						 | 
					@ -294,11 +299,18 @@ static void l2x0_unlock(u32 cache_id)
 | 
				
			||||||
	int lockregs;
 | 
						int lockregs;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cache_id == L2X0_CACHE_ID_PART_L310)
 | 
						switch (cache_id) {
 | 
				
			||||||
 | 
						case L2X0_CACHE_ID_PART_L310:
 | 
				
			||||||
		lockregs = 8;
 | 
							lockregs = 8;
 | 
				
			||||||
	else
 | 
							break;
 | 
				
			||||||
 | 
						case AURORA_CACHE_ID:
 | 
				
			||||||
 | 
							lockregs = 4;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
		/* L210 and unknown types */
 | 
							/* L210 and unknown types */
 | 
				
			||||||
		lockregs = 1;
 | 
							lockregs = 1;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < lockregs; i++) {
 | 
						for (i = 0; i < lockregs; i++) {
 | 
				
			||||||
		writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
 | 
							writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
 | 
				
			||||||
| 
						 | 
					@ -314,18 +326,22 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
	u32 cache_id;
 | 
						u32 cache_id;
 | 
				
			||||||
	u32 way_size = 0;
 | 
						u32 way_size = 0;
 | 
				
			||||||
	int ways;
 | 
						int ways;
 | 
				
			||||||
 | 
						int way_size_shift = L2X0_WAY_SIZE_SHIFT;
 | 
				
			||||||
	const char *type;
 | 
						const char *type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l2x0_base = base;
 | 
						l2x0_base = base;
 | 
				
			||||||
 | 
						if (cache_id_part_number_from_dt)
 | 
				
			||||||
	cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
 | 
							cache_id = cache_id_part_number_from_dt;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID)
 | 
				
			||||||
 | 
								& L2X0_CACHE_ID_PART_MASK;
 | 
				
			||||||
	aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 | 
						aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	aux &= aux_mask;
 | 
						aux &= aux_mask;
 | 
				
			||||||
	aux |= aux_val;
 | 
						aux |= aux_val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Determine the number of ways */
 | 
						/* Determine the number of ways */
 | 
				
			||||||
	switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
 | 
						switch (cache_id) {
 | 
				
			||||||
	case L2X0_CACHE_ID_PART_L310:
 | 
						case L2X0_CACHE_ID_PART_L310:
 | 
				
			||||||
		if (aux & (1 << 16))
 | 
							if (aux & (1 << 16))
 | 
				
			||||||
			ways = 16;
 | 
								ways = 16;
 | 
				
			||||||
| 
						 | 
					@ -342,6 +358,14 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
		ways = (aux >> 13) & 0xf;
 | 
							ways = (aux >> 13) & 0xf;
 | 
				
			||||||
		type = "L210";
 | 
							type = "L210";
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case AURORA_CACHE_ID:
 | 
				
			||||||
 | 
							sync_reg_offset = AURORA_SYNC_REG;
 | 
				
			||||||
 | 
							ways = (aux >> 13) & 0xf;
 | 
				
			||||||
 | 
							ways = 2 << ((ways + 1) >> 2);
 | 
				
			||||||
 | 
							way_size_shift = AURORA_WAY_SIZE_SHIFT;
 | 
				
			||||||
 | 
							type = "Aurora";
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* Assume unknown chips have 8 ways */
 | 
							/* Assume unknown chips have 8 ways */
 | 
				
			||||||
		ways = 8;
 | 
							ways = 8;
 | 
				
			||||||
| 
						 | 
					@ -355,7 +379,8 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
	 * L2 cache Size =  Way size * Number of ways
 | 
						 * L2 cache Size =  Way size * Number of ways
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
 | 
						way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
 | 
				
			||||||
	way_size = 1 << (way_size + 3);
 | 
						way_size = 1 << (way_size + way_size_shift);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l2x0_size = ways * way_size * SZ_1K;
 | 
						l2x0_size = ways * way_size * SZ_1K;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -363,7 +388,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
	 * If you are booting from non-secure mode
 | 
						 * If you are booting from non-secure mode
 | 
				
			||||||
	 * accessing the below registers will fault.
 | 
						 * accessing the below registers will fault.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
 | 
						if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 | 
				
			||||||
		/* Make sure that I&D is not locked down when starting */
 | 
							/* Make sure that I&D is not locked down when starting */
 | 
				
			||||||
		l2x0_unlock(cache_id);
 | 
							l2x0_unlock(cache_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -373,7 +398,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
		l2x0_inv_all();
 | 
							l2x0_inv_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* enable L2X0 */
 | 
							/* enable L2X0 */
 | 
				
			||||||
		writel_relaxed(1, l2x0_base + L2X0_CTRL);
 | 
							writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Re-read it in case some bits are reserved. */
 | 
						/* Re-read it in case some bits are reserved. */
 | 
				
			||||||
| 
						 | 
					@ -398,6 +423,100 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_OF
 | 
					#ifdef CONFIG_OF
 | 
				
			||||||
 | 
					static int l2_wt_override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Note that the end addresses passed to Linux primitives are
 | 
				
			||||||
 | 
					 * noninclusive, while the hardware cache range operations use
 | 
				
			||||||
 | 
					 * inclusive start and end addresses.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static unsigned long calc_range_end(unsigned long start, unsigned long end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Limit the number of cache lines processed at once,
 | 
				
			||||||
 | 
						 * since cache range operations stall the CPU pipeline
 | 
				
			||||||
 | 
						 * until completion.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (end > start + MAX_RANGE_SIZE)
 | 
				
			||||||
 | 
							end = start + MAX_RANGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Cache range operations can't straddle a page boundary.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (end > PAGE_ALIGN(start+1))
 | 
				
			||||||
 | 
							end = PAGE_ALIGN(start+1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return end;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Make sure 'start' and 'end' reference the same page, as L2 is PIPT
 | 
				
			||||||
 | 
					 * and range operations only do a TLB lookup on the start address.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void aurora_pa_range(unsigned long start, unsigned long end,
 | 
				
			||||||
 | 
								unsigned long offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						raw_spin_lock_irqsave(&l2x0_lock, flags);
 | 
				
			||||||
 | 
						writel(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG);
 | 
				
			||||||
 | 
						writel(end, l2x0_base + offset);
 | 
				
			||||||
 | 
						raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cache_sync();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void aurora_inv_range(unsigned long start, unsigned long end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * round start and end adresses up to cache line size
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						start &= ~(CACHE_LINE_SIZE - 1);
 | 
				
			||||||
 | 
						end = ALIGN(end, CACHE_LINE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Invalidate all full cache lines between 'start' and 'end'.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						while (start < end) {
 | 
				
			||||||
 | 
							unsigned long range_end = calc_range_end(start, end);
 | 
				
			||||||
 | 
							aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
 | 
				
			||||||
 | 
									AURORA_INVAL_RANGE_REG);
 | 
				
			||||||
 | 
							start = range_end;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void aurora_clean_range(unsigned long start, unsigned long end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If L2 is forced to WT, the L2 will always be clean and we
 | 
				
			||||||
 | 
						 * don't need to do anything here.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!l2_wt_override) {
 | 
				
			||||||
 | 
							start &= ~(CACHE_LINE_SIZE - 1);
 | 
				
			||||||
 | 
							end = ALIGN(end, CACHE_LINE_SIZE);
 | 
				
			||||||
 | 
							while (start != end) {
 | 
				
			||||||
 | 
								unsigned long range_end = calc_range_end(start, end);
 | 
				
			||||||
 | 
								aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
 | 
				
			||||||
 | 
										AURORA_CLEAN_RANGE_REG);
 | 
				
			||||||
 | 
								start = range_end;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void aurora_flush_range(unsigned long start, unsigned long end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!l2_wt_override) {
 | 
				
			||||||
 | 
							start &= ~(CACHE_LINE_SIZE - 1);
 | 
				
			||||||
 | 
							end = ALIGN(end, CACHE_LINE_SIZE);
 | 
				
			||||||
 | 
							while (start != end) {
 | 
				
			||||||
 | 
								unsigned long range_end = calc_range_end(start, end);
 | 
				
			||||||
 | 
								aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
 | 
				
			||||||
 | 
										AURORA_FLUSH_RANGE_REG);
 | 
				
			||||||
 | 
								start = range_end;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __init l2x0_of_setup(const struct device_node *np,
 | 
					static void __init l2x0_of_setup(const struct device_node *np,
 | 
				
			||||||
				 u32 *aux_val, u32 *aux_mask)
 | 
									 u32 *aux_val, u32 *aux_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -495,9 +614,15 @@ static void __init pl310_save(void)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void aurora_save(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL);
 | 
				
			||||||
 | 
						l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void l2x0_resume(void)
 | 
					static void l2x0_resume(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
 | 
						if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 | 
				
			||||||
		/* restore aux ctrl and enable l2 */
 | 
							/* restore aux ctrl and enable l2 */
 | 
				
			||||||
		l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
 | 
							l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -506,7 +631,7 @@ static void l2x0_resume(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		l2x0_inv_all();
 | 
							l2x0_inv_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		writel_relaxed(1, l2x0_base + L2X0_CTRL);
 | 
							writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -514,7 +639,7 @@ static void pl310_resume(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 l2x0_revision;
 | 
						u32 l2x0_revision;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
 | 
						if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 | 
				
			||||||
		/* restore pl310 setup */
 | 
							/* restore pl310 setup */
 | 
				
			||||||
		writel_relaxed(l2x0_saved_regs.tag_latency,
 | 
							writel_relaxed(l2x0_saved_regs.tag_latency,
 | 
				
			||||||
			l2x0_base + L2X0_TAG_LATENCY_CTRL);
 | 
								l2x0_base + L2X0_TAG_LATENCY_CTRL);
 | 
				
			||||||
| 
						 | 
					@ -540,6 +665,46 @@ static void pl310_resume(void)
 | 
				
			||||||
	l2x0_resume();
 | 
						l2x0_resume();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void aurora_resume(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 | 
				
			||||||
 | 
							writel(l2x0_saved_regs.aux_ctrl, l2x0_base + L2X0_AUX_CTRL);
 | 
				
			||||||
 | 
							writel(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __init aurora_broadcast_l2_commands(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__u32 u;
 | 
				
			||||||
 | 
						/* Enable Broadcasting of cache commands to L2*/
 | 
				
			||||||
 | 
						__asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u));
 | 
				
			||||||
 | 
						u |= AURORA_CTRL_FW;		/* Set the FW bit */
 | 
				
			||||||
 | 
						__asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u));
 | 
				
			||||||
 | 
						isb();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __init aurora_of_setup(const struct device_node *np,
 | 
				
			||||||
 | 
									u32 *aux_val, u32 *aux_mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU;
 | 
				
			||||||
 | 
						u32 mask =  AURORA_ACR_REPLACEMENT_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						of_property_read_u32(np, "cache-id-part",
 | 
				
			||||||
 | 
								&cache_id_part_number_from_dt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Determine and save the write policy */
 | 
				
			||||||
 | 
						l2_wt_override = of_property_read_bool(np, "wt-override");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (l2_wt_override) {
 | 
				
			||||||
 | 
							val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY;
 | 
				
			||||||
 | 
							mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*aux_val &= ~mask;
 | 
				
			||||||
 | 
						*aux_val |= val;
 | 
				
			||||||
 | 
						*aux_mask &= ~mask;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct l2x0_of_data pl310_data = {
 | 
					static const struct l2x0_of_data pl310_data = {
 | 
				
			||||||
	.setup = pl310_of_setup,
 | 
						.setup = pl310_of_setup,
 | 
				
			||||||
	.save  = pl310_save,
 | 
						.save  = pl310_save,
 | 
				
			||||||
| 
						 | 
					@ -571,10 +736,37 @@ static const struct l2x0_of_data l2x0_data = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct l2x0_of_data aurora_with_outer_data = {
 | 
				
			||||||
 | 
						.setup = aurora_of_setup,
 | 
				
			||||||
 | 
						.save  = aurora_save,
 | 
				
			||||||
 | 
						.outer_cache = {
 | 
				
			||||||
 | 
							.resume      = aurora_resume,
 | 
				
			||||||
 | 
							.inv_range   = aurora_inv_range,
 | 
				
			||||||
 | 
							.clean_range = aurora_clean_range,
 | 
				
			||||||
 | 
							.flush_range = aurora_flush_range,
 | 
				
			||||||
 | 
							.sync        = l2x0_cache_sync,
 | 
				
			||||||
 | 
							.flush_all   = l2x0_flush_all,
 | 
				
			||||||
 | 
							.inv_all     = l2x0_inv_all,
 | 
				
			||||||
 | 
							.disable     = l2x0_disable,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct l2x0_of_data aurora_no_outer_data = {
 | 
				
			||||||
 | 
						.setup = aurora_of_setup,
 | 
				
			||||||
 | 
						.save  = aurora_save,
 | 
				
			||||||
 | 
						.outer_cache = {
 | 
				
			||||||
 | 
							.resume      = aurora_resume,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id l2x0_ids[] __initconst = {
 | 
					static const struct of_device_id l2x0_ids[] __initconst = {
 | 
				
			||||||
	{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
 | 
						{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
 | 
				
			||||||
	{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
 | 
						{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
 | 
				
			||||||
	{ .compatible = "arm,l210-cache", .data = (void *)&l2x0_data },
 | 
						{ .compatible = "arm,l210-cache", .data = (void *)&l2x0_data },
 | 
				
			||||||
 | 
						{ .compatible = "marvell,aurora-system-cache",
 | 
				
			||||||
 | 
						  .data = (void *)&aurora_no_outer_data},
 | 
				
			||||||
 | 
						{ .compatible = "marvell,aurora-outer-cache",
 | 
				
			||||||
 | 
						  .data = (void *)&aurora_with_outer_data},
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -600,9 +792,14 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 | 
				
			||||||
	data = of_match_node(l2x0_ids, np)->data;
 | 
						data = of_match_node(l2x0_ids, np)->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* L2 configuration can only be changed if the cache is disabled */
 | 
						/* L2 configuration can only be changed if the cache is disabled */
 | 
				
			||||||
	if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
 | 
						if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
 | 
				
			||||||
		if (data->setup)
 | 
							if (data->setup)
 | 
				
			||||||
			data->setup(np, &aux_val, &aux_mask);
 | 
								data->setup(np, &aux_val, &aux_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* For aurora cache in no outer mode select the
 | 
				
			||||||
 | 
							 * correct mode using the coprocessor*/
 | 
				
			||||||
 | 
							if (data == &aurora_no_outer_data)
 | 
				
			||||||
 | 
								aurora_broadcast_l2_commands();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (data->save)
 | 
						if (data->save)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue