1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 Intel Corporation <www.intel.com>
4  *
5  */
6 #include <dm.h>
7 #include <hang.h>
8 #include <wait_bit.h>
9 
10 #include <asm/io.h>
11 #include <linux/bitops.h>
12 
13 /* Directory */
14 #define DIRUSFER		0x80010
15 #define DIRUCASER0		0x80040
16 #define DIRUSFMCR		0x80080
17 #define DIRUSFMAR		0x80084
18 
19 #define DIRUSFMCR_SFID_SHIFT	16
20 
21 /* Coherent cache agent interface */
22 #define CAIUIDR			0x00ffc
23 
24 #define CAIUIDR_CA_GET(v)	(((v) & 0x00008000) >> 15)
25 #define CAIUIDR_TYPE_GET(v)	(((v) & 0x000f0000) >> 16)
26 #define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT	0
27 #define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT	1
28 
29 /* Coherent subsystem */
30 #define CSADSER0		0xff040
31 #define CSUIDR			0xffff8
32 #define CSIDR			0xffffc
33 
34 #define CSUIDR_NUMCAIUS_GET(v)	(((v) & 0x0000007f) >> 0)
35 #define CSUIDR_NUMDIRUS_GET(v)	(((v) & 0x003f0000) >> 16)
36 #define CSUIDR_NUMCMIUS_GET(v)	(((v) & 0x3f000000) >> 24)
37 
38 #define CSIDR_NUMSFS_GET(v)	(((v) & 0x007c0000) >> 18)
39 
40 #define DIR_REG_SZ		0x1000
41 #define CAIU_REG_SZ		0x1000
42 
43 #define CCU_DIR_REG_ADDR(base, reg, dir)	\
44 		((base) + (reg) + ((dir) * DIR_REG_SZ))
45 
46 /* OCRAM firewall register */
47 #define OCRAM_FW_01			0x100204
48 #define OCRAM_SECURE_REGIONS		4
49 
50 #define OCRAM_PRIVILEGED_MASK		BIT(29)
51 #define OCRAM_SECURE_MASK		BIT(30)
52 
ncore_ccu_init_dirs(void __iomem * base)53 static void ncore_ccu_init_dirs(void __iomem *base)
54 {
55 	ulong i, f;
56 	int ret;
57 	u32 num_of_dirs;
58 	u32 num_of_snoop_filters;
59 	u32 reg;
60 
61 	num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
62 	num_of_snoop_filters =
63 		CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1;
64 
65 	/* Initialize each snoop filter in each directory */
66 	for (f = 0; f < num_of_snoop_filters; f++) {
67 		reg = f << DIRUSFMCR_SFID_SHIFT;
68 		for (i = 0; i < num_of_dirs; i++) {
69 			/* Initialize all entries */
70 			writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i));
71 
72 			/* Poll snoop filter maintenance operation active
73 			 * bit become 0.
74 			 */
75 			ret = wait_for_bit_le32((const void *)
76 						CCU_DIR_REG_ADDR(base,
77 								 DIRUSFMAR, i),
78 						BIT(0), false, 1000, false);
79 			if (ret) {
80 				puts("CCU: Directory initialization failed!\n");
81 				hang();
82 			}
83 
84 			/* Enable snoop filter, a bit per snoop filter */
85 			setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i),
86 				     BIT(f));
87 		}
88 	}
89 }
90 
ncore_ccu_init_coh_agent(void __iomem * base)91 static void ncore_ccu_init_coh_agent(void __iomem *base)
92 {
93 	u32 num_of_coh_agent_intf;
94 	u32 num_of_dirs;
95 	u32 reg;
96 	u32 type;
97 	u32 i, dir;
98 
99 	num_of_coh_agent_intf =
100 		CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR));
101 	num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR));
102 
103 	for (i = 0; i < num_of_coh_agent_intf; i++) {
104 		reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ));
105 		if (CAIUIDR_CA_GET(reg)) {
106 			/* Caching agent bit is enabled, enable caching agent
107 			 * snoop in each directory
108 			 */
109 			for (dir = 0; dir < num_of_dirs; dir++) {
110 				setbits_le32((ulong)
111 					     CCU_DIR_REG_ADDR(base, DIRUCASER0,
112 							      dir),
113 					     BIT(i));
114 			}
115 		}
116 
117 		type = CAIUIDR_TYPE_GET(reg);
118 		if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT ||
119 		    type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) {
120 			/* DVM support is enabled, enable ACE DVM snoop*/
121 			setbits_le32((ulong)(base + CSADSER0),
122 				     BIT(i));
123 		}
124 	}
125 }
126 
ocram_bypass_firewall(void __iomem * base)127 static void ocram_bypass_firewall(void __iomem *base)
128 {
129 	int i;
130 
131 	for (i = 0; i < OCRAM_SECURE_REGIONS; i++) {
132 		clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)),
133 			     OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK);
134 	}
135 }
136 
ncore_ccu_probe(struct udevice * dev)137 static int ncore_ccu_probe(struct udevice *dev)
138 {
139 	void __iomem *base;
140 	fdt_addr_t addr;
141 
142 	addr = dev_read_addr(dev);
143 	if (addr == FDT_ADDR_T_NONE)
144 		return -EINVAL;
145 
146 	base = (void __iomem *)addr;
147 
148 	ncore_ccu_init_dirs(base);
149 	ncore_ccu_init_coh_agent(base);
150 	ocram_bypass_firewall(base);
151 
152 	return 0;
153 }
154 
155 static const struct udevice_id ncore_ccu_ids[] = {
156 	{ .compatible = "arteris,ncore-ccu" },
157 	{}
158 };
159 
160 U_BOOT_DRIVER(ncore_ccu) = {
161 	.name   = "ncore_ccu",
162 	.id     = UCLASS_CACHE,
163 	.of_match = ncore_ccu_ids,
164 	.probe	= ncore_ccu_probe,
165 	.flags  = DM_FLAG_PRE_RELOC,
166 };
167