1 /*
2  * Copyright (c) 2024 Raspberry Pi Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_XIP_CACHE_H
8 #define _HARDWARE_XIP_CACHE_H
9 
10 #include "pico.h"
11 #include "hardware/regs/addressmap.h"
12 
13 /** \file xip_cache.h
14  *  \defgroup hardware_xip_cache hardware_xip_cache
15  *
16  * \brief Low-level cache maintenance operations for the XIP cache
17  *
18  * These functions apply some maintenance operation to either the entire cache contents, or a range
19  * of offsets within the downstream address space. Offsets start from 0 (indicating the first byte
20  * of flash), so pointers should have XIP_BASE subtracted before passing into one of these
21  * functions.
22  *
23  * \if rp2040-specific
24  * The only valid cache maintenance operation on RP2040 is "invalidate", which tells the cache to
25  * forget everything it knows about some address. This is necessary after a programming operation,
26  * because the cache does not automatically know about any serial programming operations performed
27  * on the external flash device, and could return stale data.
28  * \endif
29  *
30  * \if rp2350-specific
31  * On RP2350, the three types of operation are:
32  *
33  * * Invalidate: tell the cache to forget everything it knows about some address. The next access to
34  *   that address will fetch from downstream memory.
35  *
36  * * Clean: if the addressed cache line contains data not yet written to external memory, then write
37  *   that data out now, and mark the line as "clean" (i.e. not containing uncommitted write data)
38  *
39  * * Pin: mark an address as always being resident in the cache. This persists until the line is
40  *   invalidated, and can be used to allocate part of the cache for cache-as-SRAM use.
41  *
42  * When using both external flash and external RAM (e.g. PSRAM), a simple way to maintain coherence
43  * over flash programming operations is to:
44  *
45  * 1. Clean the entire cache (e.g. using xip_cache_clean_all())
46  *
47  * 2. Erase + program the flash using serial SPI commands
48  *
49  * 3. Invalidate ("flush") the entire cache (e.g. using xip_cache_invalidate_all())
50  *
51  * The invalidate ensures the programming is visible to subsequent reads. The clean ensures that the
52  * invalidate does not discard any cached PSRAM write data.
53  *
54  * \endif
55  *
56  */
57 
58 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_XIP_CACHE, Enable/disable assertions in the hardware_xip_cache module, type=bool, default=0, group=hardware_xip_cache
59 #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_XIP_CACHE
60 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_XIP_CACHE 0
61 #endif
62 
63 #define XIP_CACHE_LINE_SIZE _u(8)
64 
65 #define XIP_CACHE_SIZE (_u(16) * _u(1024))
66 
67 #if PICO_RP2040
68 #define XIP_CACHE_ADDRESS_SPACE_SIZE (_u(16) * _u(1024) * _u(1024))
69 #else
70 #define XIP_CACHE_ADDRESS_SPACE_SIZE (XIP_END - XIP_BASE)
71 #endif
72 
73 // A read-only cache never requires cleaning (you can still call the functions, they are just no-ops)
74 #if PICO_RP2040
75 #define XIP_CACHE_IS_READ_ONLY 1
76 #else
77 #define XIP_CACHE_IS_READ_ONLY 0
78 #endif
79 
80 #ifndef __ASSEMBLER__
81 
82 #ifdef __cplusplus
83 extern "C" {
84 #endif
85 
86 /*! \brief Invalidate the cache for the entire XIP address space
87  *  \ingroup hardware_xip_cache
88  *
89  * Invalidation ensures that subsequent reads will fetch data from the downstream memory, rather
90  * than using (potentially stale) cached data.
91  *
92  * This function is faster than calling xip_cache_invalidate_range() for the entire address space,
93  * because it iterates over cachelines instead of addresses.
94  *
95  * @note Any pending write data held in the cache is lost: you can force the cache to commit these
96  *  writes first, by calling xip_cache_clean_all()
97  *
98  * @note Unlike flash_flush_cache(), this function affects *only* the cache line state.
99  *  flash_flush_cache() calls a ROM API which can have other effects on some platforms, like
100  *  cleaning up the bootrom's QSPI GPIO setup on RP2040. Prefer this function for general cache
101  *  maintenance use, and prefer flash_flush_cache in sequences of ROM flash API calls.
102  */
103 void xip_cache_invalidate_all(void);
104 
105 /*! \brief Invalidate a range of offsets within the XIP address space
106  *  \ingroup hardware_xip_cache
107  *
108  * \param start_offset The first offset to be invalidated. Offset 0 means the first byte of XIP
109  *  memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function.
110  *  Must be 4-byte-aligned on RP2040. Must be a aligned to the start of a cache line
111  *  (XIP_CACHE_LINE_SIZE) on other platforms.
112  *
113  * \param size_bytes The number of bytes to invalidate. Must be a multiple of 4 bytes on RP2040.
114  *  Must be a multiple of XIP_CACHE_LINE_SIZE on other platforms.
115  *
116  * Invalidation ensures that subsequent reads will fetch data from the downstream memory, rather
117  * than using (potentially stale) cached data.
118 
119  * @note Any pending write data held in the cache is lost: you can force the cache to commit these
120  *  writes first, by calling xip_cache_clean_range() with the same parameters. Generally this is
121  *  not necessary because invalidation is used with flash (write-behind via programming), and
122  *  cleaning is used with PSRAM (writing through the cache).
123  *
124  */
125 void xip_cache_invalidate_range(uintptr_t start_offset, uintptr_t size_bytes);
126 
127 #if !XIP_CACHE_IS_READ_ONLY
128 
129 /*! \brief Clean the cache for the entire XIP address space
130  *  \ingroup hardware_xip_cache
131  *
132  * This causes the cache to write out all pending write data to the downstream memory. For example,
133  * when suspending the system with state retained in external PSRAM, this ensures all data has made
134  * it out to external PSRAM before powering down.
135  *
136  * This function is faster than calling xip_cache_clean_range() for the entire address space,
137  * because it iterates over cachelines instead of addresses.
138  *
139  * \if rp2040-specific
140  * On RP2040 this is a no-op, as the XIP cache is read-only. This is indicated by the
141  * XIP_CACHE_IS_READ_ONLY macro.
142  * \endif
143  *
144  * \if rp2350-specific
145  * On RP2350, due to the workaround applied for RP2350-E11, this function also effectively
146  * invalidates all cache lines after cleaning them. The next access to each line will miss. Avoid
147  * this by calling xip_cache_clean_range() which does not suffer this issue.
148  * \endif
149  *
150  */
151 void xip_cache_clean_all(void);
152 
153 /*! \brief Clean a range of offsets within the XIP address space
154  *  \ingroup hardware_xip_cache
155  *
156  * This causes the cache to write out pending write data at these offsets to the downstream memory.
157  *
158  * \if rp2040-specific
159  * On RP2040 this is a no-op, as the XIP cache is read-only. This is indicated by the
160  * XIP_CACHE_IS_READ_ONLY macro.
161  * \endif
162  *
163  * \param start_offset The first offset to be invalidated. Offset 0 means the first byte of XIP
164  *  memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function.
165  *  Must be aligned to the start of a cache line (XIP_CACHE_LINE_SIZE).
166  *
167  * \param size_bytes The number of bytes to clean. Must be a multiple of XIP_CACHE_LINE_SIZE.
168  */
169 void xip_cache_clean_range(uintptr_t start_offset, uintptr_t size_bytes);
170 
171 #else
172 // Stub these out inline to avoid generating a call to an empty function when they are no-ops
xip_cache_clean_all(void)173 static inline void xip_cache_clean_all(void) {}
xip_cache_clean_range(uintptr_t start_offset,uintptr_t size_bytes)174 static inline void xip_cache_clean_range(uintptr_t start_offset, uintptr_t size_bytes) {
175     (void)start_offset;
176     (void)size_bytes;
177 }
178 #endif
179 
180 #if !PICO_RP2040
181 
182 /*! \brief Pin a range of offsets within the XIP address space
183  *  \ingroup hardware_xip_cache
184  *
185  * Pinning a line at an address allocates the line exclusively for use at that address. This means
186  * that all subsequent accesses to that address will hit the cache, and will not go to downstream
187  * memory. This persists until one of two things happens:
188  *
189  * * The line is invalidated, e.g. via xip_cache_invalidate_all()
190  *
191  * * The same line is pinned at a different address (note lines are selected by address modulo
192  *   XIP_CACHE_SIZE)
193  *
194  * \param start_offset The first offset to be pinnned. Offset 0 means the first byte of XIP
195  *  memory (e.g. flash). Pointers must have XIP_BASE subtracted before passing into this function.
196  *  Must be aligned to the start of a cache line (XIP_CACHE_LINE_SIZE).
197  *
198  * \param size_bytes The number of bytes to pin. Must be a multiple of XIP_CACHE_LINE_SIZE.
199  *
200  */
201 void xip_cache_pin_range(uintptr_t start_offset, uintptr_t size_bytes);
202 #endif
203 
204 #ifdef __cplusplus
205 }
206 #endif
207 
208 #endif // !__ASSEMBLER__
209 
210 #endif // !_HARDWARE_XIP_CACHE_H
211