1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "synquacer_ddr.h"
9
10 #include <internal/ccn512.h>
11
12 #include <mod_ccn512.h>
13
14 #include <fwk_assert.h>
15 #include <fwk_id.h>
16 #include <fwk_log.h>
17 #include <fwk_module.h>
18 #include <fwk_module_idx.h>
19 #include <fwk_status.h>
20
21 #include <fmw_cmsis.h>
22
23 #include <stddef.h>
24 #include <stdint.h>
25
26 #define HNF_COUNT 8
27 #define SNF_ID_DMC1 0x8ULL
28 #define SNF_ID_DMC3 0x1AULL
29
30 #define SNF_MP_ID_DMC0 0x8ULL
31 #define SNF_MP_ID_DMC1 0x1AULL
32
ccn512_qos_init(ccn512_reg_t * ccn512)33 static void ccn512_qos_init(ccn512_reg_t *ccn512)
34 {
35 /*
36 * Setting QOS priority for each CPU cluster to 0xE and setting the
37 * enable bit so the new setting takes effect. This function must be
38 * called when there are no ongoing transactions on the ports being
39 * configured, so it must be called after powering on SYSTOP and before
40 * the applications cores/clusters are released from reset.
41 *
42 * See "Device 0 Port QoS Control register" in the Corelink CCN512 Cache
43 * Coherent Network technical reference manual.
44 */
45 ccn512->XP_ID_0.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 0 */
46 ccn512->XP_ID_1.DEV0_QOS_CONTROL = 0; /* not Cluster */
47 ccn512->XP_ID_2.DEV0_QOS_CONTROL = 0; /* not Cluster */
48 ccn512->XP_ID_3.DEV0_QOS_CONTROL = 0; /* not Cluster */
49 ccn512->XP_ID_4.DEV0_QOS_CONTROL = 0; /* not Cluster */
50 ccn512->XP_ID_5.DEV0_QOS_CONTROL = 0xE0004; /* PCIE1 */
51 ccn512->XP_ID_6.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 6 */
52 ccn512->XP_ID_7.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 8 */
53 ccn512->XP_ID_8.DEV0_QOS_CONTROL = 0; /* not Cluster */
54 ccn512->XP_ID_9.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 1 */
55 ccn512->XP_ID_10.DEV0_QOS_CONTROL = 0; /* not Cluster */
56 ccn512->XP_ID_11.DEV0_QOS_CONTROL = 0; /* not Cluster */
57 ccn512->XP_ID_12.DEV0_QOS_CONTROL = 0; /* not Cluster */
58 ccn512->XP_ID_13.DEV0_QOS_CONTROL = 0; /* not Cluster */
59 ccn512->XP_ID_14.DEV0_QOS_CONTROL = 0; /* not Cluster */
60 ccn512->XP_ID_15.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 7 */
61 ccn512->XP_ID_16.DEV0_QOS_CONTROL = 0xE0004; /* Cluster 9 */
62 ccn512->XP_ID_17.DEV0_QOS_CONTROL = 0;
63
64 ccn512->XP_ID_0.DEV1_QOS_CONTROL = 0; /* not Cluster */
65 ccn512->XP_ID_1.DEV1_QOS_CONTROL = 0; /* not Cluster */
66 ccn512->XP_ID_2.DEV1_QOS_CONTROL = 0; /* not Cluster */
67 ccn512->XP_ID_3.DEV1_QOS_CONTROL = 0; /* not Cluster */
68 ccn512->XP_ID_4.DEV1_QOS_CONTROL = 0; /* not Cluster */
69 ccn512->XP_ID_5.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 2 */
70 ccn512->XP_ID_6.DEV1_QOS_CONTROL = 0; /* not Cluster */
71 ccn512->XP_ID_7.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 10 */
72 ccn512->XP_ID_8.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 5 */
73 ccn512->XP_ID_9.DEV1_QOS_CONTROL = 0xE0004; /* PCIE0 */
74 ccn512->XP_ID_10.DEV1_QOS_CONTROL = 0; /* not Cluster */
75 ccn512->XP_ID_11.DEV1_QOS_CONTROL = 0; /* not Cluster */
76 ccn512->XP_ID_12.DEV1_QOS_CONTROL = 0; /* not Cluster */
77 ccn512->XP_ID_13.DEV1_QOS_CONTROL = 0; /* not Cluster */
78 ccn512->XP_ID_14.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 3 */
79 ccn512->XP_ID_15.DEV1_QOS_CONTROL = 0; /* not Cluster */
80 ccn512->XP_ID_16.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 11 */
81 ccn512->XP_ID_17.DEV1_QOS_CONTROL = 0xE0004; /* Cluster 4 */
82 }
83
ccn512_dmc_init(ccn512_reg_t * ccn512)84 static void ccn512_dmc_init(ccn512_reg_t *ccn512)
85 {
86 unsigned int i;
87 ccn5xx_hnf_reg_t *hnf = &ccn512->HNF_ID_2;
88 uint64_t ddr_ch0_id, ddr_ch1_id;
89
90 uint8_t ddr_memory_used_ch;
91 ddr_memory_used_ch = fw_get_used_memory_ch();
92
93 ddr_ch0_id = SNF_MP_ID_DMC0;
94 ddr_ch1_id = SNF_MP_ID_DMC1;
95
96 /*
97 * On SynQuacer, there are only 2 DMCs (IDs 1 and 3).
98 * All traffic from the first half of the HN-Fs must go to DMC1 and the
99 * second half to DMC3.
100 * If this setup is not done, the traffic for the DMCs that do not
101 * exist will lock-up the system.
102 */
103 for (i = 0; i < HNF_COUNT; i++) {
104 if (ddr_memory_used_ch == DDR_USE_CH0) {
105 hnf[i].HNF_SAM_CONTROL = ddr_ch0_id;
106 } else if (ddr_memory_used_ch == DDR_USE_CH1) {
107 hnf[i].HNF_SAM_CONTROL = ddr_ch1_id;
108 } else {
109 hnf[i].HNF_SAM_CONTROL =
110 (i < (HNF_COUNT / 2) ? ddr_ch0_id : ddr_ch1_id);
111 }
112 }
113 }
114
ccn512_secure_init(ccn512_reg_t * ccn512)115 static void ccn512_secure_init(ccn512_reg_t *ccn512)
116 {
117 /* set Non-secure access enable */
118 ccn512->MN_ID_34.SECURE_ACCESS |= 0x1;
119 }
120
fw_ccn512_init(ccn512_reg_t * ccn512)121 void fw_ccn512_init(ccn512_reg_t *ccn512)
122 {
123 ccn512_secure_init(ccn512);
124 ccn512_qos_init(ccn512);
125 ccn512_dmc_init(ccn512);
126
127 /* Wait for write operations to finish. */
128 __DMB();
129 }
130
fw_ccn512_exit(void)131 void fw_ccn512_exit(void)
132 {
133 const struct mod_ccn512_module_config *module_config;
134 ccn512_reg_t *ccn512;
135 unsigned int i;
136
137 module_config = fwk_module_get_data(fwk_module_id_ccn512);
138 fwk_assert(module_config != NULL);
139
140 ccn512 = module_config->reg_base;
141
142 ccn5xx_hnf_reg_t *hnf = &ccn512->HNF_ID_2;
143
144 FWK_LOG_INFO("[CCN512] CCN512 exit.");
145
146 /* exit ALL CA53 CPU SNOOP */
147 for (i = 0; i < HNF_COUNT; i++)
148 hnf[i].SNOOP_DOMAIN_CTL_CLR = hnf[i].SNOOP_DOMAIN_CTL;
149
150 /* Wait for write operations to finish. */
151 __DMB();
152
153 FWK_LOG_INFO("[CCN512] CCN512 exit end.");
154 }
155
ccn512_config(ccn512_reg_t * ccn512)156 static int ccn512_config(ccn512_reg_t *ccn512)
157 {
158 FWK_LOG_INFO("[CCN512] Initialising ccn512 at 0x%x", (uintptr_t)ccn512);
159
160 fw_ccn512_init(ccn512);
161
162 FWK_LOG_INFO("[CCN512] CCN512 init done.");
163
164 return FWK_SUCCESS;
165 }
166
167 static struct mod_ccn512_api module_api = {
168 .ccn512_exit = fw_ccn512_exit,
169 };
170
171 /* Framework API */
mod_ccn512_init(fwk_id_t module_id,unsigned int element_count,const void * data)172 static int mod_ccn512_init(
173 fwk_id_t module_id,
174 unsigned int element_count,
175 const void *data)
176 {
177 return FWK_SUCCESS;
178 }
179
mod_ccn512_element_init(fwk_id_t element_id,unsigned int unused,const void * data)180 static int mod_ccn512_element_init(
181 fwk_id_t element_id,
182 unsigned int unused,
183 const void *data)
184 {
185 fwk_assert(data != NULL);
186
187 return FWK_SUCCESS;
188 }
189
mod_ccn512_bind(fwk_id_t id,unsigned int round)190 static int mod_ccn512_bind(fwk_id_t id, unsigned int round)
191 {
192 /* Nothing to do in the second round of calls. */
193 if (round == 1)
194 return FWK_SUCCESS;
195
196 /* Nothing to do in case of elements. */
197 if (fwk_module_is_valid_element_id(id))
198 return FWK_SUCCESS;
199
200 return FWK_SUCCESS;
201 }
202
mod_ccn512_start(fwk_id_t id)203 static int mod_ccn512_start(fwk_id_t id)
204 {
205 const struct mod_ccn512_module_config *module_config;
206 ccn512_reg_t *ccn512;
207
208 module_config = fwk_module_get_data(fwk_module_id_ccn512);
209 fwk_assert(module_config != NULL);
210
211 ccn512 = module_config->reg_base;
212
213 return ccn512_config(ccn512);
214 }
215
mod_ccn512_process_bind_request(fwk_id_t requester_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)216 static int mod_ccn512_process_bind_request(
217 fwk_id_t requester_id,
218 fwk_id_t target_id,
219 fwk_id_t api_id,
220 const void **api)
221 {
222 *api = &module_api;
223
224 return FWK_SUCCESS;
225 }
226
227 const struct fwk_module module_ccn512 = {
228 .type = FWK_MODULE_TYPE_DRIVER,
229 .init = mod_ccn512_init,
230 .element_init = mod_ccn512_element_init,
231 .bind = mod_ccn512_bind,
232 .start = mod_ccn512_start,
233 .process_bind_request = mod_ccn512_process_bind_request,
234 .api_count = 1,
235 .event_count = 0,
236 };
237