diff options
Diffstat (limited to 'drivers/cache/cache-ncore.c')
| -rw-r--r-- | drivers/cache/cache-ncore.c | 164 | 
1 files changed, 164 insertions, 0 deletions
| diff --git a/drivers/cache/cache-ncore.c b/drivers/cache/cache-ncore.c new file mode 100644 index 00000000000..e3aca360713 --- /dev/null +++ b/drivers/cache/cache-ncore.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + * + */ +#include <dm.h> +#include <wait_bit.h> + +#include <asm/io.h> + +/* Directory */ +#define DIRUSFER		0x80010 +#define DIRUCASER0		0x80040 +#define DIRUSFMCR		0x80080 +#define DIRUSFMAR		0x80084 + +#define DIRUSFMCR_SFID_SHIFT	16 + +/* Coherent cache agent interface */ +#define CAIUIDR			0x00ffc + +#define CAIUIDR_CA_GET(v)	(((v) & 0x00008000) >> 15) +#define CAIUIDR_TYPE_GET(v)	(((v) & 0x000f0000) >> 16) +#define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT	0 +#define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT	1 + +/* Coherent subsystem */ +#define CSADSER0		0xff040 +#define CSUIDR			0xffff8 +#define CSIDR			0xffffc + +#define CSUIDR_NUMCAIUS_GET(v)	(((v) & 0x0000007f) >> 0) +#define CSUIDR_NUMDIRUS_GET(v)	(((v) & 0x003f0000) >> 16) +#define CSUIDR_NUMCMIUS_GET(v)	(((v) & 0x3f000000) >> 24) + +#define CSIDR_NUMSFS_GET(v)	(((v) & 0x007c0000) >> 18) + +#define DIR_REG_SZ		0x1000 +#define CAIU_REG_SZ		0x1000 + +#define CCU_DIR_REG_ADDR(base, reg, dir)	\ +		((base) + (reg) + ((dir) * DIR_REG_SZ)) + +/* OCRAM firewall register */ +#define OCRAM_FW_01			0x100204 +#define OCRAM_SECURE_REGIONS		4 + +#define OCRAM_PRIVILEGED_MASK		BIT(29) +#define OCRAM_SECURE_MASK		BIT(30) + +static void ncore_ccu_init_dirs(void __iomem *base) +{ +	ulong i, f; +	int ret; +	u32 num_of_dirs; +	u32 num_of_snoop_filters; +	u32 reg; + +	num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR)); +	num_of_snoop_filters = +		CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1; + +	/* Initialize each snoop filter in each directory */ +	for (f = 0; f < num_of_snoop_filters; f++) { +		reg = f << DIRUSFMCR_SFID_SHIFT; +		for (i = 0; i < num_of_dirs; i++) { +			/* Initialize all entries */ +			writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i)); + +			/* Poll snoop filter maintenance operation active +			 * bit become 0. +			 */ +			ret = wait_for_bit_le32((const void *) +						CCU_DIR_REG_ADDR(base, +								 DIRUSFMAR, i), +						BIT(0), false, 1000, false); +			if (ret) { +				puts("CCU: Directory initialization failed!\n"); +				hang(); +			} + +			/* Enable snoop filter, a bit per snoop filter */ +			setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i), +				     BIT(f)); +		} +	} +} + +static void ncore_ccu_init_coh_agent(void __iomem *base) +{ +	u32 num_of_coh_agent_intf; +	u32 num_of_dirs; +	u32 reg; +	u32 type; +	u32 i, dir; + +	num_of_coh_agent_intf = +		CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR)); +	num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR)); + +	for (i = 0; i < num_of_coh_agent_intf; i++) { +		reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ)); +		if (CAIUIDR_CA_GET(reg)) { +			/* Caching agent bit is enabled, enable caching agent +			 * snoop in each directory +			 */ +			for (dir = 0; dir < num_of_dirs; dir++) { +				setbits_le32((ulong) +					     CCU_DIR_REG_ADDR(base, DIRUCASER0, +							      dir), +					     BIT(i)); +			} +		} + +		type = CAIUIDR_TYPE_GET(reg); +		if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT || +		    type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) { +			/* DVM support is enabled, enable ACE DVM snoop*/ +			setbits_le32((ulong)(base + CSADSER0), +				     BIT(i)); +		} +	} +} + +static void ocram_bypass_firewall(void __iomem *base) +{ +	int i; + +	for (i = 0; i < OCRAM_SECURE_REGIONS; i++) { +		clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)), +			     OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); +	} +} + +static int ncore_ccu_probe(struct udevice *dev) +{ +	void __iomem *base; +	fdt_addr_t addr; + +	addr = dev_read_addr(dev); +	if (addr == FDT_ADDR_T_NONE) +		return -EINVAL; + +	base = (void __iomem *)addr; + +	ncore_ccu_init_dirs(base); +	ncore_ccu_init_coh_agent(base); +	ocram_bypass_firewall(base); + +	return 0; +} + +static const struct udevice_id ncore_ccu_ids[] = { +	{ .compatible = "arteris,ncore-ccu" }, +	{} +}; + +U_BOOT_DRIVER(ncore_ccu) = { +	.name   = "ncore_ccu", +	.id     = UCLASS_CACHE, +	.of_match = ncore_ccu_ids, +	.probe	= ncore_ccu_probe, +	.flags  = DM_FLAG_PRE_RELOC, +}; | 
