blob: 3beff780de0fdb2276d8c8db68d0c3c64da36d11 [file] [log] [blame]
Ley Foon Tanfec7ddc2019-11-27 15:55:24 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2019 Intel Corporation <www.intel.com>
4 *
5 */
6#include <dm.h>
Simon Glassdb41d652019-12-28 10:45:07 -07007#include <hang.h>
Ley Foon Tanfec7ddc2019-11-27 15:55:24 +08008#include <wait_bit.h>
9
10#include <asm/io.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <linux/bitops.h>
Ley Foon Tanfec7ddc2019-11-27 15:55:24 +080012
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
53static 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
91static 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
127static 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
137static 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
155static const struct udevice_id ncore_ccu_ids[] = {
156 { .compatible = "arteris,ncore-ccu" },
157 {}
158};
159
160U_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};