1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 * Copyright (c) 2022 Yonatan Schachter
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <errno.h>
9 #include <stdint.h>
10 #include <stddef.h>
11
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/flash.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/irq.h>
16 #include <zephyr/toolchain.h>
17
18 #include <hardware/flash.h>
19 #include <hardware/regs/io_qspi.h>
20 #include <hardware/regs/pads_qspi.h>
21 #include <hardware/structs/ssi.h>
22 #include <hardware/structs/xip_ctrl.h>
23 #include <hardware/resets.h>
24 #include <pico/bootrom.h>
25
26 LOG_MODULE_REGISTER(flash_rpi_pico, CONFIG_FLASH_LOG_LEVEL);
27
28 #define DT_DRV_COMPAT raspberrypi_pico_flash_controller
29
30 #define PAGE_SIZE 256
31 #define SECTOR_SIZE DT_PROP(DT_CHOSEN(zephyr_flash), erase_block_size)
32 #define ERASE_VALUE 0xff
33 #define FLASH_SIZE KB(CONFIG_FLASH_SIZE)
34 #define FLASH_BASE CONFIG_FLASH_BASE_ADDRESS
35 #define SSI_BASE_ADDRESS DT_REG_ADDR(DT_CHOSEN(zephyr_flash_controller))
36
37 static const struct flash_parameters flash_rpi_parameters = {
38 .write_block_size = 1,
39 .erase_value = ERASE_VALUE,
40 };
41
42 /**
43 * Low level flash functions are based on:
44 * github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
45 * and
46 * github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c
47 */
48
49 #define FLASHCMD_PAGE_PROGRAM 0x02
50 #define FLASHCMD_READ_STATUS 0x05
51 #define FLASHCMD_WRITE_ENABLE 0x06
52 #define BOOT2_SIZE_WORDS 64
53
54 enum outover {
55 OUTOVER_NORMAL = 0,
56 OUTOVER_INVERT,
57 OUTOVER_LOW,
58 OUTOVER_HIGH
59 };
60
61 static ssi_hw_t *const ssi = (ssi_hw_t *)SSI_BASE_ADDRESS;
62 static uint32_t boot2_copyout[BOOT2_SIZE_WORDS];
63 static bool boot2_copyout_valid;
64
__no_inline_not_in_flash_func(flash_init_boot2_copyout)65 static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void)
66 {
67 if (boot2_copyout_valid)
68 return;
69 for (int i = 0; i < BOOT2_SIZE_WORDS; ++i)
70 boot2_copyout[i] = ((uint32_t *)FLASH_BASE)[i];
71 __compiler_memory_barrier();
72 boot2_copyout_valid = true;
73 }
74
__no_inline_not_in_flash_func(flash_enable_xip_via_boot2)75 static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void)
76 {
77 ((void (*)(void))((uint32_t)boot2_copyout+1))();
78 }
79
__no_inline_not_in_flash_func(flash_cs_force)80 void __no_inline_not_in_flash_func(flash_cs_force)(enum outover over)
81 {
82 io_rw_32 *reg = (io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SS_CTRL_OFFSET);
83 *reg = (*reg & ~IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS)
84 | (over << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB);
85 (void) *reg;
86 }
87
__no_inline_not_in_flash_func(flash_was_aborted)88 int __no_inline_not_in_flash_func(flash_was_aborted)()
89 {
90 return *(io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET)
91 & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS;
92 }
93
__no_inline_not_in_flash_func(flash_put_get)94 void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count,
95 size_t rx_skip)
96 {
97 const uint max_in_flight = 16 - 2;
98 size_t tx_count = count;
99 size_t rx_count = count;
100 bool did_something;
101 uint32_t tx_level;
102 uint32_t rx_level;
103 uint8_t rxbyte;
104
105 while (tx_count || rx_skip || rx_count) {
106 tx_level = ssi_hw->txflr;
107 rx_level = ssi_hw->rxflr;
108 did_something = false;
109 if (tx_count && tx_level + rx_level < max_in_flight) {
110 ssi->dr0 = (uint32_t) (tx ? *tx++ : 0);
111 --tx_count;
112 did_something = true;
113 }
114 if (rx_level) {
115 rxbyte = ssi->dr0;
116 did_something = true;
117 if (rx_skip) {
118 --rx_skip;
119 } else {
120 if (rx)
121 *rx++ = rxbyte;
122 --rx_count;
123 }
124 }
125
126 if (!did_something && __builtin_expect(flash_was_aborted(), 0))
127 break;
128 }
129 flash_cs_force(OUTOVER_HIGH);
130 }
131
__no_inline_not_in_flash_func(flash_put_get_wrapper)132 void __no_inline_not_in_flash_func(flash_put_get_wrapper)(uint8_t cmd, const uint8_t *tx,
133 uint8_t *rx, size_t count)
134 {
135 flash_cs_force(OUTOVER_LOW);
136 ssi->dr0 = cmd;
137 flash_put_get(tx, rx, count, 1);
138 }
139
flash_put_cmd_addr(uint8_t cmd,uint32_t addr)140 static ALWAYS_INLINE void flash_put_cmd_addr(uint8_t cmd, uint32_t addr)
141 {
142 flash_cs_force(OUTOVER_LOW);
143 addr |= cmd << 24;
144 for (int i = 0; i < 4; ++i) {
145 ssi->dr0 = addr >> 24;
146 addr <<= 8;
147 }
148 }
149
__no_inline_not_in_flash_func(flash_write_partial_internal)150 void __no_inline_not_in_flash_func(flash_write_partial_internal)(uint32_t addr, const uint8_t *data,
151 size_t size)
152 {
153 uint8_t status_reg;
154
155 flash_put_get_wrapper(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
156 flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, addr);
157 flash_put_get(data, NULL, size, 4);
158
159 do {
160 flash_put_get_wrapper(FLASHCMD_READ_STATUS, NULL, &status_reg, 1);
161 } while (status_reg & 0x1 && !flash_was_aborted());
162 }
163
__no_inline_not_in_flash_func(flash_write_partial)164 void __no_inline_not_in_flash_func(flash_write_partial)(uint32_t flash_offs, const uint8_t *data,
165 size_t count)
166 {
167 rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)
168 rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
169 rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)
170 rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
171 rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)
172 rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
173
174 flash_init_boot2_copyout();
175
176 __compiler_memory_barrier();
177
178 connect_internal_flash();
179 flash_exit_xip();
180 flash_write_partial_internal(flash_offs, data, count);
181 flash_flush_cache();
182 flash_enable_xip_via_boot2();
183 }
184
is_valid_range(off_t offset,uint32_t size)185 static bool is_valid_range(off_t offset, uint32_t size)
186 {
187 return (offset >= 0) && ((offset + size) <= FLASH_SIZE);
188 }
189
flash_rpi_read(const struct device * dev,off_t offset,void * data,size_t size)190 static int flash_rpi_read(const struct device *dev, off_t offset, void *data, size_t size)
191 {
192 if (size == 0) {
193 return 0;
194 }
195
196 if (!is_valid_range(offset, size)) {
197 LOG_ERR("Read range exceeds the flash boundaries");
198 return -EINVAL;
199 }
200
201 memcpy(data, (uint8_t *)(CONFIG_FLASH_BASE_ADDRESS + offset), size);
202
203 return 0;
204 }
205
flash_rpi_write(const struct device * dev,off_t offset,const void * data,size_t size)206 static int flash_rpi_write(const struct device *dev, off_t offset, const void *data, size_t size)
207 {
208 uint32_t key;
209 size_t bytes_to_write;
210 uint8_t *data_pointer = (uint8_t *)data;
211
212 if (size == 0) {
213 return 0;
214 }
215
216 if (!is_valid_range(offset, size)) {
217 LOG_ERR("Write range exceeds the flash boundaries. Offset=%#lx, Size=%u",
218 offset, size);
219 return -EINVAL;
220 }
221
222 key = irq_lock();
223
224 if ((offset & (PAGE_SIZE - 1)) > 0) {
225 bytes_to_write = MIN(PAGE_SIZE - (offset & (PAGE_SIZE - 1)), size);
226 flash_write_partial(offset, data_pointer, bytes_to_write);
227 data_pointer += bytes_to_write;
228 size -= bytes_to_write;
229 offset += bytes_to_write;
230 }
231
232 if (size >= PAGE_SIZE) {
233 bytes_to_write = size & ~(PAGE_SIZE - 1);
234 flash_range_program(offset, data_pointer, bytes_to_write);
235 data_pointer += bytes_to_write;
236 size -= bytes_to_write;
237 offset += bytes_to_write;
238 }
239
240 if (size > 0) {
241 flash_write_partial(offset, data_pointer, size);
242 }
243
244 irq_unlock(key);
245
246 return 0;
247 }
248
flash_rpi_erase(const struct device * dev,off_t offset,size_t size)249 static int flash_rpi_erase(const struct device *dev, off_t offset, size_t size)
250 {
251 uint32_t key;
252
253 if (size == 0) {
254 return 0;
255 }
256
257 if (!is_valid_range(offset, size)) {
258 LOG_ERR("Erase range exceeds the flash boundaries. Offset=%#lx, Size=%u",
259 offset, size);
260 return -EINVAL;
261 }
262
263 if ((offset % SECTOR_SIZE) || (size % SECTOR_SIZE)) {
264 LOG_ERR("Erase range is not a multiple of the sector size. Offset=%#lx, Size=%u",
265 offset, size);
266 return -EINVAL;
267 }
268
269 key = irq_lock();
270
271 flash_range_erase(offset, size);
272
273 irq_unlock(key);
274
275 return 0;
276 }
277
flash_rpi_get_parameters(const struct device * dev)278 static const struct flash_parameters *flash_rpi_get_parameters(const struct device *dev)
279 {
280 ARG_UNUSED(dev);
281
282 return &flash_rpi_parameters;
283 }
284
285 #if CONFIG_FLASH_PAGE_LAYOUT
286
287 static const struct flash_pages_layout flash_rpi_pages_layout = {
288 .pages_count = FLASH_SIZE / SECTOR_SIZE,
289 .pages_size = SECTOR_SIZE,
290 };
291
flash_rpi_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)292 void flash_rpi_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
293 size_t *layout_size)
294 {
295 *layout = &flash_rpi_pages_layout;
296 *layout_size = 1;
297 }
298
299 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
300
301 static const struct flash_driver_api flash_rpi_driver_api = {
302 .read = flash_rpi_read,
303 .write = flash_rpi_write,
304 .erase = flash_rpi_erase,
305 .get_parameters = flash_rpi_get_parameters,
306 #ifdef CONFIG_FLASH_PAGE_LAYOUT
307 .page_layout = flash_rpi_page_layout,
308 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
309 };
310
311 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL,
312 CONFIG_FLASH_INIT_PRIORITY, &flash_rpi_driver_api);
313