2 * Copyright (C) 2018 Marvell International Ltd.
4 * SPDX-License-Identifier: BSD-3-Clause
5 * https://spdx.org/licenses
8 /* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */
10 #include <common/debug.h>
11 #include <drivers/marvell/ccu.h>
14 #include <armada_common.h>
16 #include <mvebu_def.h>
18 #if LOG_LEVEL >= LOG_LEVEL_INFO
19 #define DEBUG_ADDR_MAP
23 #define WIN_ENABLE_BIT (0x1)
24 /* Physical address of the base of the window = {AddrLow[19:0],20'h0} */
25 #define ADDRESS_SHIFT (20 - 4)
26 #define ADDRESS_MASK (0xFFFFFFF0)
27 #define CCU_WIN_ALIGNMENT (0x100000)
29 #define IS_DRAM_TARGET(tgt) ((((tgt) == DRAM_0_TID) || \
30 ((tgt) == DRAM_1_TID) || \
31 ((tgt) == RAR_TID)) ? 1 : 0)
33 /* For storage of CR, SCR, ALR, AHR abd GCR */
34 static uint32_t ccu_regs_save
[MVEBU_CCU_MAX_WINS
* 4 + 1];
37 static void dump_ccu(int ap_index
)
39 uint32_t win_id
, win_cr
, alr
, ahr
;
43 /* Dump all AP windows */
44 printf("\tbank target start end\n");
45 printf("\t----------------------------------------------------\n");
46 for (win_id
= 0; win_id
< MVEBU_CCU_MAX_WINS
; win_id
++) {
47 win_cr
= mmio_read_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
));
48 if (win_cr
& WIN_ENABLE_BIT
) {
49 target_id
= (win_cr
>> CCU_TARGET_ID_OFFSET
) &
51 alr
= mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index
,
53 ahr
= mmio_read_32(CCU_WIN_AHR_OFFSET(ap_index
,
55 start
= ((uint64_t)alr
<< ADDRESS_SHIFT
);
56 end
= (((uint64_t)ahr
+ 0x10) << ADDRESS_SHIFT
);
57 printf("\tccu %02x 0x%016llx 0x%016llx\n",
58 target_id
, start
, end
);
61 win_cr
= mmio_read_32(CCU_WIN_GCR_OFFSET(ap_index
));
62 target_id
= (win_cr
>> CCU_GCR_TARGET_OFFSET
) & CCU_GCR_TARGET_MASK
;
63 printf("\tccu GCR %d - all other transactions\n", target_id
);
67 void ccu_win_check(struct addr_map_win
*win
)
69 /* check if address is aligned to 1M */
70 if (IS_NOT_ALIGN(win
->base_addr
, CCU_WIN_ALIGNMENT
)) {
71 win
->base_addr
= ALIGN_UP(win
->base_addr
, CCU_WIN_ALIGNMENT
);
72 NOTICE("%s: Align up the base address to 0x%llx\n",
73 __func__
, win
->base_addr
);
76 /* size parameter validity check */
77 if (IS_NOT_ALIGN(win
->win_size
, CCU_WIN_ALIGNMENT
)) {
78 win
->win_size
= ALIGN_UP(win
->win_size
, CCU_WIN_ALIGNMENT
);
79 NOTICE("%s: Aligning size to 0x%llx\n",
80 __func__
, win
->win_size
);
84 void ccu_enable_win(int ap_index
, struct addr_map_win
*win
, uint32_t win_id
)
90 if ((win_id
== 0) || (win_id
> MVEBU_CCU_MAX_WINS
)) {
91 ERROR("Enabling wrong CCU window %d!\n", win_id
);
95 end_addr
= (win
->base_addr
+ win
->win_size
- 1);
96 alr
= (uint32_t)((win
->base_addr
>> ADDRESS_SHIFT
) & ADDRESS_MASK
);
97 ahr
= (uint32_t)((end_addr
>> ADDRESS_SHIFT
) & ADDRESS_MASK
);
99 mmio_write_32(CCU_WIN_ALR_OFFSET(ap_index
, win_id
), alr
);
100 mmio_write_32(CCU_WIN_AHR_OFFSET(ap_index
, win_id
), ahr
);
102 ccu_win_reg
= WIN_ENABLE_BIT
;
103 ccu_win_reg
|= (win
->target_id
& CCU_TARGET_ID_MASK
)
104 << CCU_TARGET_ID_OFFSET
;
105 mmio_write_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
), ccu_win_reg
);
108 static void ccu_disable_win(int ap_index
, uint32_t win_id
)
112 if ((win_id
== 0) || (win_id
> MVEBU_CCU_MAX_WINS
)) {
113 ERROR("Disabling wrong CCU window %d!\n", win_id
);
117 win_reg
= mmio_read_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
));
118 win_reg
&= ~WIN_ENABLE_BIT
;
119 mmio_write_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
), win_reg
);
122 /* Insert/Remove temporary window for using the out-of reset default
123 * CPx base address to access the CP configuration space prior to
124 * the further base address update in accordance with address mapping
127 * NOTE: Use the same window array for insertion and removal of
130 void ccu_temp_win_insert(int ap_index
, struct addr_map_win
*win
, int size
)
134 for (int i
= 0; i
< size
; i
++) {
135 win_id
= MVEBU_CCU_MAX_WINS
- 1 - i
;
137 ccu_enable_win(ap_index
, win
, win_id
);
143 * NOTE: Use the same window array for insertion and removal of
146 void ccu_temp_win_remove(int ap_index
, struct addr_map_win
*win
, int size
)
150 for (int i
= 0; i
< size
; i
++) {
154 win_id
= MVEBU_CCU_MAX_WINS
- 1 - i
;
156 target
= mmio_read_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
));
157 target
>>= CCU_TARGET_ID_OFFSET
;
158 target
&= CCU_TARGET_ID_MASK
;
160 base
= mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index
, win_id
));
161 base
<<= ADDRESS_SHIFT
;
163 if ((win
->target_id
!= target
) || (win
->base_addr
!= base
)) {
164 ERROR("%s: Trying to remove bad window-%d!\n",
168 ccu_disable_win(ap_index
, win_id
);
173 /* Returns current DRAM window target (DRAM_0_TID, DRAM_1_TID, RAR_TID)
174 * NOTE: Call only once for each AP.
175 * The AP0 DRAM window is located at index 2 only at the BL31 execution start.
176 * Then it relocated to index 1 for matching the rest of APs DRAM settings.
177 * Calling this function after relocation will produce wrong results on AP0
179 static uint32_t ccu_dram_target_get(int ap_index
)
181 /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
182 * All the rest of detected APs will use window at index 1.
183 * The AP0 DRAM window is moved from index 2 to 1 during
184 * init_ccu() execution.
186 const uint32_t win_id
= (ap_index
== 0) ? 2 : 1;
189 target
= mmio_read_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
));
190 target
>>= CCU_TARGET_ID_OFFSET
;
191 target
&= CCU_TARGET_ID_MASK
;
196 void ccu_dram_target_set(int ap_index
, uint32_t target
)
198 /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
199 * All the rest of detected APs will use window at index 1.
200 * The AP0 DRAM window is moved from index 2 to 1
201 * during init_ccu() execution.
203 const uint32_t win_id
= (ap_index
== 0) ? 2 : 1;
206 dram_cr
= mmio_read_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
));
207 dram_cr
&= ~(CCU_TARGET_ID_MASK
<< CCU_TARGET_ID_OFFSET
);
208 dram_cr
|= (target
& CCU_TARGET_ID_MASK
) << CCU_TARGET_ID_OFFSET
;
209 mmio_write_32(CCU_WIN_CR_OFFSET(ap_index
, win_id
), dram_cr
);
212 /* Setup CCU DRAM window and enable it */
213 void ccu_dram_win_config(int ap_index
, struct addr_map_win
*win
)
215 #if IMAGE_BLE /* BLE */
216 /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2.
217 * Since the BootROM is not accessing DRAM at BLE stage,
218 * the DRAM window can be temporarely disabled.
220 const uint32_t win_id
= (ap_index
== 0) ? 2 : 1;
221 #else /* end of BLE */
222 /* At the ccu_init() execution stage, DRAM windows of all APs
223 * are arranged at index 1.
224 * The AP0 still has the old window BootROM DRAM at index 2, so
225 * the window-1 can be safely disabled without breaking the DRAM access.
227 const uint32_t win_id
= 1;
230 ccu_disable_win(ap_index
, win_id
);
231 /* enable write secure (and clear read secure) */
232 mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index
, win_id
),
233 CCU_WIN_ENA_WRITE_SECURE
);
235 ccu_enable_win(ap_index
, win
, win_id
);
238 /* Save content of CCU window + GCR */
239 static void ccu_save_win_range(int ap_id
, int win_first
,
240 int win_last
, uint32_t *buffer
)
244 for (idx
= 0, win_id
= win_first
; win_id
<= win_last
; win_id
++) {
245 buffer
[idx
++] = mmio_read_32(CCU_WIN_CR_OFFSET(ap_id
, win_id
));
246 buffer
[idx
++] = mmio_read_32(CCU_WIN_SCR_OFFSET(ap_id
, win_id
));
247 buffer
[idx
++] = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_id
, win_id
));
248 buffer
[idx
++] = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_id
, win_id
));
250 buffer
[idx
] = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_id
));
253 /* Restore content of CCU window + GCR */
254 static void ccu_restore_win_range(int ap_id
, int win_first
,
255 int win_last
, uint32_t *buffer
)
259 for (idx
= 0, win_id
= win_first
; win_id
<= win_last
; win_id
++) {
260 mmio_write_32(CCU_WIN_CR_OFFSET(ap_id
, win_id
), buffer
[idx
++]);
261 mmio_write_32(CCU_WIN_SCR_OFFSET(ap_id
, win_id
), buffer
[idx
++]);
262 mmio_write_32(CCU_WIN_ALR_OFFSET(ap_id
, win_id
), buffer
[idx
++]);
263 mmio_write_32(CCU_WIN_AHR_OFFSET(ap_id
, win_id
), buffer
[idx
++]);
265 mmio_write_32(CCU_WIN_GCR_OFFSET(ap_id
), buffer
[idx
]);
268 void ccu_save_win_all(int ap_id
)
270 ccu_save_win_range(ap_id
, 0, MVEBU_CCU_MAX_WINS
- 1, ccu_regs_save
);
273 void ccu_restore_win_all(int ap_id
)
275 ccu_restore_win_range(ap_id
, 0, MVEBU_CCU_MAX_WINS
- 1, ccu_regs_save
);
278 int init_ccu(int ap_index
)
280 struct addr_map_win
*win
, *dram_win
;
281 uint32_t win_id
, win_reg
;
282 uint32_t win_count
, array_id
;
283 uint32_t dram_target
;
285 /* In BootROM context CCU Window-1
286 * has SRAM_TID target and should not be disabled
288 const uint32_t win_start
= 2;
290 const uint32_t win_start
= 1;
293 INFO("Initializing CCU Address decoding\n");
295 /* Get the array of the windows and fill the map data */
296 marvell_get_ccu_memory_map(ap_index
, &win
, &win_count
);
297 if (win_count
<= 0) {
298 INFO("No windows configurations found\n");
299 } else if (win_count
> (MVEBU_CCU_MAX_WINS
- 1)) {
300 ERROR("CCU mem map array > than max available windows (%d)\n",
302 win_count
= MVEBU_CCU_MAX_WINS
;
305 /* Need to set GCR to DRAM before all CCU windows are disabled for
306 * securing the normal access to DRAM location, which the ATF is running
307 * from. Once all CCU windows are set, which have to include the
308 * dedicated DRAM window as well, the GCR can be switched to the target
309 * defined by the platform configuration.
311 dram_target
= ccu_dram_target_get(ap_index
);
312 win_reg
= (dram_target
& CCU_GCR_TARGET_MASK
) << CCU_GCR_TARGET_OFFSET
;
313 mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index
), win_reg
);
315 /* If the DRAM window was already configured at the BLE stage,
316 * only the window target considered valid, the address range should be
317 * updated according to the platform configuration.
319 for (dram_win
= win
, array_id
= 0; array_id
< win_count
;
320 array_id
++, dram_win
++) {
321 if (IS_DRAM_TARGET(dram_win
->target_id
)) {
322 dram_win
->target_id
= dram_target
;
327 /* Disable all AP CCU windows
328 * Window-0 is always bypassed since it already contains
329 * data allowing the internal configuration space access
331 for (win_id
= win_start
; win_id
< MVEBU_CCU_MAX_WINS
; win_id
++) {
332 ccu_disable_win(ap_index
, win_id
);
333 /* enable write secure (and clear read secure) */
334 mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index
, win_id
),
335 CCU_WIN_ENA_WRITE_SECURE
);
338 /* win_id is the index of the current ccu window
339 * array_id is the index of the current memory map window entry
341 for (win_id
= win_start
, array_id
= 0;
342 ((win_id
< MVEBU_CCU_MAX_WINS
) && (array_id
< win_count
));
345 ccu_enable_win(ap_index
, win
, win_id
);
350 /* Get & set the default target according to board topology */
351 win_reg
= (marvell_get_ccu_gcr_target(ap_index
) & CCU_GCR_TARGET_MASK
)
352 << CCU_GCR_TARGET_OFFSET
;
353 mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index
), win_reg
);
355 #ifdef DEBUG_ADDR_MAP
359 INFO("Done CCU Address decoding Initializing\n");