1 /*******************************************************************************
2  * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * MPFS HAL Embedded Software
7  *
8  */
9 /*******************************************************************************
10  * @file mss_l2_cache.c
11  * @author Microchip-FPGA Embedded Systems Solutions
12  * @brief The code in this file is executed before any code/data sections are
13  * copied. This code must not rely sdata/data section content. Hence, global
14  * variables should not be used unless they are constants.
15  *
16  */
17 /*==============================================================================
18  *
19  */
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include "mpfs_hal/mss_hal.h"
24 #include "mss_l2_cache.h"
25 
26 /*==============================================================================
27  * Local defines
28  */
29 #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0)
30 static const uint64_t g_init_marker = INIT_MARKER;
31 #endif
32 
33 /*==============================================================================
34  * Local functions.
35  */
36 static void check_config_l2_scratchpad(void);
37 
38 
39 /*==============================================================================
40  * This code should only be executed from E51 to be functional.
41  * Configure the L2 cache memory:
42  *  - Set the number of cache ways used as cache based on the MSS Configurator
43  *    settings.
44  *  - Configure some of the enabled ways as scratchpad based on linker
45  *    configuration and space allocated by configurator.
46  */
config_l2_cache(void)47 __attribute__((weak)) void config_l2_cache(void)
48 {
49     ASSERT(LIBERO_SETTING_WAY_ENABLE < 16U);
50 
51     /*
52      * Set the number of ways that will be shared between cache and scratchpad.
53      */
54     CACHE_CTRL->WAY_ENABLE = LIBERO_SETTING_WAY_ENABLE;
55 
56     /*
57      * shutdown L2 as directed
58      */
59     SYSREG->L2_SHUTDOWN_CR = LIBERO_SETTING_L2_SHUTDOWN_CR;
60 
61     /* The scratchpad has already been set-up, first check enough space before copying */
62     check_config_l2_scratchpad();
63 
64     /* If you are not using scratchpad, no need to include the following code */
65 
66     ASSERT(LIBERO_SETTING_WAY_ENABLE >= LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS);
67 
68 
69 
70     /*
71      * Compute the mask used to specify ways that will be used by the
72      * scratchpad.
73      */
74 
75     uint32_t scratchpad_ways_mask = 0U;
76 #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0)
77     uint32_t inc;
78     uint32_t seed_ways_mask = 0x1U << LIBERO_SETTING_WAY_ENABLE;
79     for(inc = 0; inc < LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS; ++inc)
80     {
81         scratchpad_ways_mask |= (seed_ways_mask >> inc) ;
82     }
83 #else
84     (void)scratchpad_ways_mask;
85 #endif
86 
87     /*
88      * Make sure ways are masked if being used as scratchpad
89      */
90     ASSERT((LIBERO_SETTING_WAY_MASK_DMA & scratchpad_ways_mask) == 0UL);
91     ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_0 & scratchpad_ways_mask) == 0UL);
92     ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_1 & scratchpad_ways_mask) == 0UL);
93     ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_2 & scratchpad_ways_mask) == 0UL);
94     ASSERT((LIBERO_SETTING_WAY_MASK_AXI4_PORT_3 & scratchpad_ways_mask) == 0UL);
95     ASSERT((LIBERO_SETTING_WAY_MASK_E51_DCACHE & scratchpad_ways_mask) == 0UL);
96     ASSERT((LIBERO_SETTING_WAY_MASK_E51_ICACHE & scratchpad_ways_mask) == 0UL);
97     ASSERT((LIBERO_SETTING_WAY_MASK_U54_1_DCACHE & scratchpad_ways_mask) == 0UL);
98     ASSERT((LIBERO_SETTING_WAY_MASK_U54_2_DCACHE & scratchpad_ways_mask) == 0UL);
99     ASSERT((LIBERO_SETTING_WAY_MASK_U54_3_DCACHE & scratchpad_ways_mask) == 0UL);
100     ASSERT((LIBERO_SETTING_WAY_MASK_U54_4_DCACHE & scratchpad_ways_mask) == 0UL);
101     ASSERT((LIBERO_SETTING_WAY_MASK_U54_1_ICACHE & scratchpad_ways_mask) == 0UL);
102     ASSERT((LIBERO_SETTING_WAY_MASK_U54_2_ICACHE & scratchpad_ways_mask) == 0UL);
103     ASSERT((LIBERO_SETTING_WAY_MASK_U54_3_ICACHE & scratchpad_ways_mask) == 0UL);
104     ASSERT((LIBERO_SETTING_WAY_MASK_U54_4_ICACHE & scratchpad_ways_mask) == 0UL);
105 
106     /*
107      * Setup all masters, apart from one we are using to setup scratch
108      */
109     CACHE_CTRL->WAY_MASK_DMA = LIBERO_SETTING_WAY_MASK_DMA;
110     CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_0 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_0;
111     CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_1 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_1;
112     CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_2 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_2;
113     CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_3 = LIBERO_SETTING_WAY_MASK_AXI4_PORT_3;
114     CACHE_CTRL->WAY_MASK_E51_ICACHE = LIBERO_SETTING_WAY_MASK_E51_ICACHE;
115     CACHE_CTRL->WAY_MASK_U54_1_DCACHE = LIBERO_SETTING_WAY_MASK_U54_1_DCACHE;
116     CACHE_CTRL->WAY_MASK_U54_1_ICACHE = LIBERO_SETTING_WAY_MASK_U54_1_ICACHE;
117     CACHE_CTRL->WAY_MASK_U54_2_DCACHE = LIBERO_SETTING_WAY_MASK_U54_2_DCACHE;
118     CACHE_CTRL->WAY_MASK_U54_2_ICACHE = LIBERO_SETTING_WAY_MASK_U54_2_ICACHE;
119     CACHE_CTRL->WAY_MASK_U54_3_DCACHE = LIBERO_SETTING_WAY_MASK_U54_3_DCACHE;
120     CACHE_CTRL->WAY_MASK_U54_3_ICACHE = LIBERO_SETTING_WAY_MASK_U54_3_ICACHE;
121     CACHE_CTRL->WAY_MASK_U54_4_DCACHE = LIBERO_SETTING_WAY_MASK_U54_4_DCACHE;
122     CACHE_CTRL->WAY_MASK_U54_4_ICACHE = LIBERO_SETTING_WAY_MASK_U54_4_ICACHE;
123 
124 #if (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0)
125     /*
126      * Assign ways to Zero Device
127      */
128     uint64_t * p_scratchpad = (uint64_t *)ZERO_DEVICE_BOTTOM;
129     uint32_t ways_inc;
130     uint64_t current_way = 0x1U << (((LIBERO_SETTING_WAY_ENABLE + 1U) - LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS) );
131     for(ways_inc = 0; ways_inc < LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS; ++ways_inc)
132     {
133         /*
134          * Populate the scratchpad memory one way at a time.
135          */
136         CACHE_CTRL->WAY_MASK_E51_DCACHE = current_way;
137         mb();
138         /*
139          * Write to the first 64-bit location of each cache block.
140          */
141         for(inc = 0; inc < (WAY_BYTE_LENGTH / CACHE_BLOCK_BYTE_LENGTH); ++inc)
142         {
143             *p_scratchpad = g_init_marker + inc;
144             p_scratchpad += CACHE_BLOCK_BYTE_LENGTH / UINT64_BYTE_LENGTH;
145         }
146         current_way = current_way << 1U;
147         mb();
148     }
149 #endif  /* (LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS != 0) */
150     /*
151      * Prevent E51 from evicting from scratchpad ways.
152      */
153     CACHE_CTRL->WAY_MASK_E51_DCACHE = LIBERO_SETTING_WAY_MASK_E51_DCACHE;
154     mb();
155 
156 }
157 
158 
159 /*==============================================================================
160  * Configure the L2 scratchpad based on linker symbols:
161  *  __l2_scratchpad_vma_start
162  *  __l2_scratchpad_vma_end
163  *
164  *  These linker symbols specify the start address and length of the scratchpad.
165  *  The scratchpad must be located within the Zero Device memory range.
166  */
check_config_l2_scratchpad(void)167 static void check_config_l2_scratchpad(void)
168 {
169     extern char __l2_scratchpad_vma_start;
170     extern char __l2_scratchpad_vma_end;
171 
172     uint8_t n_scratchpad_ways;
173     const uint64_t end = (const uint64_t)&__l2_scratchpad_vma_end;
174     const uint64_t start = (const uint64_t)&__l2_scratchpad_vma_start;
175     uint64_t modulo;
176 
177     ASSERT(start >= (uint64_t)ZERO_DEVICE_BOTTOM);
178     ASSERT(end < (uint64_t)ZERO_DEVICE_TOP);
179     ASSERT(end >= start);
180 
181     /*
182      * Figure out how many cache ways will be required from linker script
183      * symbols.
184      */
185     n_scratchpad_ways = (uint8_t)((end - start) / WAY_BYTE_LENGTH);
186     modulo = (end - start) % WAY_BYTE_LENGTH;
187     if(modulo > 0)
188     {
189         ++n_scratchpad_ways;
190     }
191 
192     ASSERT(LIBERO_SETTING_NUM_SCRATCH_PAD_WAYS >= n_scratchpad_ways);
193 }
194 
195 #if 0 // todo - remove, no longer used
196 
197 
198 /*==============================================================================
199  * Reserve a number of cache ways to be used as scratchpad memory.
200  *
201  * @param nways
202  *  Number of ways to be used as scratchpad. One way is 128Kbytes.
203  *
204  * @param scratchpad_start
205  *  Start address within the Zero Device memory range in which the scratchpad
206  *  will be located.
207  */
208 static void reserve_scratchpad_ways(uint8_t nways, uint64_t * scratchpad_start)
209 {
210     uint8_t way_enable;
211     uint64_t available_ways = 1;
212     uint64_t scratchpad_ways = 0;
213     uint64_t non_scratchpad_ways;
214     uint32_t inc;
215 
216     ASSERT(scratchpad_start >= (uint64_t *)ZERO_DEVICE_BOTTOM);
217     ASSERT(scratchpad_start < (uint64_t *)ZERO_DEVICE_TOP);
218 
219     /*
220      * Ensure at least one way remains available as cache.
221      */
222     way_enable = CACHE_CTRL->WAY_ENABLE;
223     ASSERT(nways <= way_enable);
224     if(nways <= way_enable)
225     {
226         /*
227          * Compute the mask used to specify ways that will be used by the
228          * scratchpad.
229          */
230 
231         for(inc = 0; inc < way_enable; ++inc)
232         {
233             available_ways = (available_ways << 1) | (uint64_t)0x01;
234             if(inc < nways)
235             {
236                 scratchpad_ways = (scratchpad_ways << 1) | (uint64_t)0x01;
237             }
238         }
239 
240         /*
241          * Prevent other masters from evicting cache lines from scratchpad ways.
242          * Only allow E51 to evict from scratchpad ways.
243          */
244         non_scratchpad_ways = available_ways &  ~scratchpad_ways;
245 
246         CACHE_CTRL->WAY_MASK_DMA = non_scratchpad_ways;
247 
248         CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_0 = non_scratchpad_ways;
249         CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_1 = non_scratchpad_ways;
250         CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_2 = non_scratchpad_ways;
251         CACHE_CTRL->WAY_MASK_AXI4_SLAVE_PORT_3 = non_scratchpad_ways;
252 
253         CACHE_CTRL->WAY_MASK_E51_ICACHE = non_scratchpad_ways;
254 
255         CACHE_CTRL->WAY_MASK_U54_1_DCACHE = non_scratchpad_ways;
256         CACHE_CTRL->WAY_MASK_U54_1_ICACHE = non_scratchpad_ways;
257 
258         CACHE_CTRL->WAY_MASK_U54_2_DCACHE = non_scratchpad_ways;
259         CACHE_CTRL->WAY_MASK_U54_2_ICACHE = non_scratchpad_ways;
260 
261         CACHE_CTRL->WAY_MASK_U54_3_DCACHE = non_scratchpad_ways;
262         CACHE_CTRL->WAY_MASK_U54_3_ICACHE = non_scratchpad_ways;
263 
264         CACHE_CTRL->WAY_MASK_U54_4_DCACHE = non_scratchpad_ways;
265         CACHE_CTRL->WAY_MASK_U54_4_ICACHE = non_scratchpad_ways;
266 
267         /*
268          * Assign ways to Zero Device
269          */
270         uint64_t * p_scratchpad = scratchpad_start;
271         int ways_inc;
272         uint64_t current_way = 1;
273         for(ways_inc = 0; ways_inc < nways; ++ways_inc)
274         {
275             /*
276              * Populate the scratchpad memory one way at a time.
277              */
278             CACHE_CTRL->WAY_MASK_E51_DCACHE = current_way;
279             /*
280              * Write to the first 64-bit location of each cache block.
281              */
282             for(inc = 0; inc < (WAY_BYTE_LENGTH / CACHE_BLOCK_BYTE_LENGTH); ++inc)
283             {
284                 *p_scratchpad = g_init_marker + inc;
285                 p_scratchpad += CACHE_BLOCK_BYTE_LENGTH / UINT64_BYTE_LENGTH;
286             }
287             current_way = current_way << 1U;
288             mb();
289         }
290 
291         /*
292          * Prevent E51 from evicting from scratchpad ways.
293          */
294         CACHE_CTRL->WAY_MASK_E51_DCACHE = non_scratchpad_ways;
295     }
296 }
297 #endif
298