summaryrefslogtreecommitdiff
path: root/drivers/cache/cache-ncore.c
blob: 0aab7ee19147bbd77a215912422ebb2b6fcf46b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019 Intel Corporation <www.intel.com>
 *
 */
#include <dm.h>
#include <hang.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,
};