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 "esp_bit_defs.h"
9#include "soc/extmem_reg.h"
10
11/**
12  * @brief Write back the cache items of DCache, enable cache freeze during writeback.
13  *        Operation will be done CACHE_LINE_SIZE aligned.
14  *        If the region is not in DCache addr room, nothing will be done.
15  *        Please do not call this function in your SDK application.
16  * @param  uint32_t addr: start address to write back
17  * @param  uint32_t items: cache lines to invalidate, items * cache_line_size should
18  *         not exceed the bus address size(4MB)
19  *
20  * void cache_writeback_items_freeze(uint32_t addr, uint32_t items)
21*/
22
23/*******************************************************************************
24
25This function is a cache write-back function that works around the following
26hardware errata on the ESP32-S3:
27
28- Core X manually triggers (via the EXTMEM_DCACHE_SYNC_CTRL_REG register) the
29write-back of one or more cache lines.
30- While the write-back is in progress, there are two scenarios that may cause
31cache hit error.
32    - Core X enters the interrupt handler and access the same cache line
33      being written back.
34    - Core Y access the same cache line being written back.
35
36To workaround this errata, the following steps must be taken when manually
37triggering a cache write-back:
38
39- Core X must disable interrupts so that it cannot be preempted
40- Core X must freeze the cache (via the EXTMEM_DCACHE_FREEZE_REG register) to
41prevent Core Y from accessing the same cache lines that are about to be written
42back.
43- Core X now triggers the cache write-back. During the write-back...
44    - If Core Y attempts the access any address in the cache region, Core Y will
45    busy wait until the cache is unfrozen.
46    - Core X must ensure that it does not access any address in the cache region,
47    otherwise Core X will busy wait thus causing a deadlock.
48- After the write-back is complete, Core X unfreezes the cache, and reenables
49interrupts.
50
51Notes:
52
53- Please do not modify this function, it must strictly follow the current execution
54sequence, otherwise it may cause unexpected errors.
55- This function is written in assmebly to ensure that the function itself never
56accesses any cache address while the cache is frozen. Unexpected cache access
57could occur if...
58    - the function triggers an window overflow onto a stack placed in PSRAM.
59    Thus, we only use two window panes (a0 to a8) in this function and trigger
60    all window overflows before freezing the cache.
61    - the function accesses literals/read-only variables placed in Flash.
62
63*******************************************************************************/
64
65    .align  4
66    /*
67    Create dedicated literal pool for this function. Mostly used to store out
68    of range movi transformations.
69    */
70    .literal_position
71    .global cache_writeback_items_freeze
72    .type   cache_writeback_items_freeze, @function
73cache_writeback_items_freeze:
74    entry   sp, 32
75
76    /* REG_WRITE(EXTMEM_DCACHE_SYNC_ADDR_REG, addr); */
77    movi a4, EXTMEM_DCACHE_SYNC_ADDR_REG
78    s32i a2, a4, 0
79    /* REG_WRITE(EXTMEM_DCACHE_SYNC_SIZE_REG, items); */
80    movi a4, EXTMEM_DCACHE_SYNC_SIZE_REG
81    s32i a3, a4, 0
82    memw    /* About to freeze the cache. Ensure all previous memory R/W are completed */
83
84    movi a2, EXTMEM_DCACHE_FREEZE_REG
85    movi a3, EXTMEM_DCACHE_SYNC_CTRL_REG
86
87    /*
88    REG_CLR_BIT(EXTMEM_DCACHE_FREEZE_REG, EXTMEM_DCACHE_FREEZE_MODE);
89    REG_SET_BIT(EXTMEM_DCACHE_FREEZE_REG, EXTMEM_DCACHE_FREEZE_ENA);
90    */
91    l32i a4, a2, 0  /* a4 = *(EXTMEM_DCACHE_FREEZE_REG) */
92    movi a5, ~(EXTMEM_DCACHE_FREEZE_MODE_M)
93    and a4, a4, a5
94    movi a5, EXTMEM_DCACHE_FREEZE_ENA_M
95    or a4, a4, a5
96    s32i a4, a2, 0  /* *(EXTMEM_DCACHE_FREEZE_REG) = a4 */
97
98    /* while (!REG_GET_BIT(EXTMEM_DCACHE_FREEZE_REG, EXTMEM_DCACHE_FREEZE_DONE)); */
99    movi a5, EXTMEM_DCACHE_FREEZE_DONE_M
100_wait_freeze_done:
101    l32i a4, a2, 0  /* a4 = *(EXTMEM_DCACHE_FREEZE_REG) */
102    memw
103    bnone a4, a5, _wait_freeze_done
104
105    /* REG_SET_BIT(EXTMEM_DCACHE_SYNC_CTRL_REG, EXTMEM_DCACHE_WRITEBACK_ENA); */
106    l32i a4, a3, 0  /* a4 = *(EXTMEM_DCACHE_SYNC_CTRL_REG) */
107    movi a5, EXTMEM_DCACHE_WRITEBACK_ENA_M
108    or a4, a4, a5
109    s32i a4, a3, 0  /* *(EXTMEM_DCACHE_SYNC_CTRL_REG) = a4 */
110
111    /* while(!REG_GET_BIT(EXTMEM_DCACHE_SYNC_CTRL_REG, EXTMEM_DCACHE_SYNC_DONE)); */
112    movi a5, EXTMEM_DCACHE_SYNC_DONE_M
113_wait_writeback_done:
114    l32i a4, a3, 0  /* a4 = *(EXTMEM_DCACHE_SYNC_CTRL_REG) */
115    memw
116    bnone a4, a5, _wait_writeback_done
117
118    /* REG_CLR_BIT(EXTMEM_DCACHE_FREEZE_REG, EXTMEM_DCACHE_FREEZE_ENA); */
119    l32i a4, a2, 0  /* a4 = *(EXTMEM_DCACHE_FREEZE_REG) */
120    movi a5, ~(EXTMEM_DCACHE_FREEZE_ENA_M)
121    and a4, a4, a5
122    s32i a4, a2, 0  /* *(EXTMEM_DCACHE_FREEZE_REG) = a4 */
123
124    /* while (REG_GET_BIT(EXTMEM_DCACHE_FREEZE_REG, EXTMEM_DCACHE_FREEZE_DONE)); */
125    movi a5, EXTMEM_DCACHE_FREEZE_DONE_M
126_wait_unfreeze_done:
127    l32i a4, a2, 0  /* a4 = *(EXTMEM_DCACHE_FREEZE_REG) */
128    memw
129    bany a4, a5, _wait_unfreeze_done
130
131    retw
132    .size   cache_writeback_items_freeze, . - cache_writeback_items_freeze
133