1 /*
2  * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "sdkconfig.h"
8 #include <stdint.h>
9 #include "soc/soc_caps.h"
10 #include "esp_rom_caps.h"
11 #include "soc/extmem_reg.h"
12 #include "xtensa/xtruntime.h"
13 #if CONFIG_IDF_TARGET_ESP32S3
14 #include "esp32s3/rom/cache.h"
15 #endif
16 
17 #define ALIGN_UP(addr, align) (((addr) + (align)-1) & ~((align)-1))
18 #define ALIGN_DOWN(addr, align)  ((addr) & ~((align) - 1))
19 
20 // this api is renamed for patch
21 extern uint32_t rom_Cache_Count_Flash_Pages(uint32_t bus, uint32_t * page0_mapped);
Cache_Count_Flash_Pages(uint32_t bus,uint32_t * page0_mapped)22 uint32_t Cache_Count_Flash_Pages(uint32_t bus, uint32_t * page0_mapped)
23 {
24     uint32_t page0_before_count = *page0_mapped;
25     uint32_t flash_pages = 0;
26     flash_pages = rom_Cache_Count_Flash_Pages(bus, page0_mapped);
27 
28 /* No page mapped to page0, in this condition, the rom api will return
29  * unexpected value + 1.
30  */
31     if (page0_before_count == *page0_mapped) {
32         flash_pages--;
33     }
34     return flash_pages;
35 }
36 extern uint32_t Cache_Count_Flash_Pages(uint32_t bus, uint32_t * page0_mapped);
37 
38 #if ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG
Cache_Wait_Idle(int icache)39 static inline void Cache_Wait_Idle(int icache)
40 {
41     if (icache) {
42         while (REG_GET_FIELD(EXTMEM_CACHE_STATE_REG, EXTMEM_ICACHE_STATE) != 1) {
43             ;
44         }
45     } else {
46         while (REG_GET_FIELD(EXTMEM_CACHE_STATE_REG, EXTMEM_DCACHE_STATE) != 1) {
47             ;
48         }
49     }
50 }
51 // renamed for patch
52 extern uint32_t rom_Cache_Suspend_ICache(void);
Cache_Suspend_ICache(void)53 uint32_t Cache_Suspend_ICache(void)
54 {
55     uint32_t ret = rom_Cache_Suspend_ICache();
56     Cache_Wait_Idle(1);
57     return ret;
58 }
59 extern uint32_t Cache_Suspend_ICache(void);
60 
61 // renamed for patch
62 extern uint32_t rom_Cache_Suspend_DCache(void);
Cache_Suspend_DCache(void)63 uint32_t Cache_Suspend_DCache(void)
64 {
65     uint32_t ret = rom_Cache_Suspend_DCache();
66     Cache_Wait_Idle(0);
67     return ret;
68 }
69 extern uint32_t Cache_Suspend_DCache(void);
70 
71 #if SOC_CACHE_FREEZE_SUPPORTED
72 // renamed for patch
73 extern void rom_Cache_Freeze_ICache_Enable(cache_freeze_mode_t mode);
Cache_Freeze_ICache_Enable(cache_freeze_mode_t mode)74 void Cache_Freeze_ICache_Enable(cache_freeze_mode_t mode)
75 {
76     rom_Cache_Freeze_ICache_Enable(mode);
77     Cache_Wait_Idle(1);
78 }
79 extern void Cache_Freeze_ICache_Enable(cache_freeze_mode_t mode);
80 
81 // renamed for patch
82 extern void rom_Cache_Freeze_DCache_Enable(cache_freeze_mode_t mode);
Cache_Freeze_DCache_Enable(cache_freeze_mode_t mode)83 void Cache_Freeze_DCache_Enable(cache_freeze_mode_t mode)
84 {
85     rom_Cache_Freeze_DCache_Enable(mode);
86     Cache_Wait_Idle(0);
87 }
88 extern void Cache_Freeze_DCache_Enable(cache_freeze_mode_t mode);
89 #endif  //#if SOC_CACHE_FREEZE_SUPPORTED
90 #endif  //#if ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG
91 
92 #if ESP_ROM_HAS_CACHE_WRITEBACK_BUG
93 /* Defined in esp_rom_cache_writeback_esp32s3.S */
94 extern void cache_writeback_items_freeze(uint32_t addr, uint32_t items);
95 // renamed for patch
96 extern int rom_Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
Cache_WriteBack_Addr(uint32_t addr,uint32_t size)97 int Cache_WriteBack_Addr(uint32_t addr, uint32_t size)
98 {
99     /* Do special processing for unaligned memory at the start and end of the cache writeback memory.
100      * 1. Disable the interrupt to prevent the current CPU accessing the same cacheline.
101      * 2. Enable dcache freeze to prevent the another CPU accessing the same cacheline.
102      */
103     uint32_t irq_status;
104     uint32_t start_len, end_len;
105     uint32_t start, end;
106     uint32_t dcache_line_size;
107     uint32_t autoload;
108     int ret = 0;
109     start = addr;
110     end = addr + size;
111     dcache_line_size = Cache_Get_DCache_Line_Size();
112 
113     if (size == 0) {
114         return 0;
115     }
116 
117     /*the start address is unaligned*/
118     if (start & (dcache_line_size -1)) {
119         addr = ALIGN_UP(start, dcache_line_size);
120         start_len = addr - start;
121         size = (size < start_len) ? 0 : (size - start_len);
122 
123         /*writeback start unaligned mem, one cacheline*/
124         irq_status = XTOS_SET_INTLEVEL(XCHAL_NMILEVEL);//mask all interrupts
125         cache_writeback_items_freeze(start, 1);
126         XTOS_RESTORE_INTLEVEL(irq_status);
127 
128         if (size == 0) {
129             return 0;
130         }
131     }
132 
133     /*the end address is unaligned*/
134     if (end & (dcache_line_size -1)) {
135         end = ALIGN_DOWN(end, dcache_line_size);
136         end_len = addr + size - end;
137         size = (size - end_len);
138 
139         /*writeback end unaligned mem, one cacheline*/
140         irq_status = XTOS_SET_INTLEVEL(XCHAL_NMILEVEL);//mask all interrupts
141         cache_writeback_items_freeze(end, 1);
142         XTOS_RESTORE_INTLEVEL(irq_status);
143 
144         if (size == 0) {
145             return 0;
146         }
147     }
148 
149     /*suspend autoload, avoid load cachelines being written back*/
150     autoload = Cache_Suspend_DCache_Autoload();
151     ret = rom_Cache_WriteBack_Addr(addr, size);
152     Cache_Resume_DCache_Autoload(autoload);
153 
154     return ret;
155 }
156 extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
157 #endif  //#if ESP_ROM_HAS_CACHE_WRITEBACK_BUG
158