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 static uint8_t flash_ram_buffer[PAGE_SIZE];
65 
__no_inline_not_in_flash_func(flash_init_boot2_copyout)66 static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void)
67 {
68 	if (boot2_copyout_valid) {
69 		return;
70 	}
71 	for (int i = 0; i < BOOT2_SIZE_WORDS; ++i) {
72 		boot2_copyout[i] = ((uint32_t *)FLASH_BASE)[i];
73 	}
74 	__compiler_memory_barrier();
75 	boot2_copyout_valid = true;
76 }
77 
__no_inline_not_in_flash_func(flash_enable_xip_via_boot2)78 static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void)
79 {
80 	((void (*)(void))((uint32_t)boot2_copyout+1))();
81 }
82 
__no_inline_not_in_flash_func(flash_cs_force)83 void __no_inline_not_in_flash_func(flash_cs_force)(enum outover over)
84 {
85 	io_rw_32 *reg = (io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SS_CTRL_OFFSET);
86 	*reg = (*reg & ~IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS)
87 		| (over << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB);
88 	(void) *reg;
89 }
90 
__no_inline_not_in_flash_func(flash_was_aborted)91 int __no_inline_not_in_flash_func(flash_was_aborted)()
92 {
93 	return *(io_rw_32 *) (IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET)
94 		   & IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS;
95 }
96 
__no_inline_not_in_flash_func(flash_put_get)97 void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx, uint8_t *rx, size_t count,
98 						size_t rx_skip)
99 {
100 	const uint max_in_flight = 16 - 2;
101 	size_t tx_count = count;
102 	size_t rx_count = count;
103 	bool did_something;
104 	uint32_t tx_level;
105 	uint32_t rx_level;
106 	uint8_t rxbyte;
107 
108 	while (tx_count || rx_skip || rx_count) {
109 		tx_level = ssi_hw->txflr;
110 		rx_level = ssi_hw->rxflr;
111 		did_something = false;
112 		if (tx_count && tx_level + rx_level < max_in_flight) {
113 			ssi->dr0 = (uint32_t) (tx ? *tx++ : 0);
114 			--tx_count;
115 			did_something = true;
116 		}
117 		if (rx_level) {
118 			rxbyte = ssi->dr0;
119 			did_something = true;
120 			if (rx_skip) {
121 				--rx_skip;
122 			} else {
123 				if (rx) {
124 					*rx++ = rxbyte;
125 				}
126 				--rx_count;
127 			}
128 		}
129 
130 		if (!did_something && __builtin_expect(flash_was_aborted(), 0)) {
131 			break;
132 		}
133 	}
134 	flash_cs_force(OUTOVER_HIGH);
135 }
136 
__no_inline_not_in_flash_func(flash_put_get_wrapper)137 void __no_inline_not_in_flash_func(flash_put_get_wrapper)(uint8_t cmd, const uint8_t *tx,
138 					uint8_t *rx, size_t count)
139 {
140 	flash_cs_force(OUTOVER_LOW);
141 	ssi->dr0 = cmd;
142 	flash_put_get(tx, rx, count, 1);
143 }
144 
flash_put_cmd_addr(uint8_t cmd,uint32_t addr)145 static ALWAYS_INLINE void flash_put_cmd_addr(uint8_t cmd, uint32_t addr)
146 {
147 	flash_cs_force(OUTOVER_LOW);
148 	addr |= cmd << 24;
149 	for (int i = 0; i < 4; ++i) {
150 		ssi->dr0 = addr >> 24;
151 		addr <<= 8;
152 	}
153 }
154 
__no_inline_not_in_flash_func(flash_write_partial_internal)155 void __no_inline_not_in_flash_func(flash_write_partial_internal)(uint32_t addr, const uint8_t *data,
156 					size_t size)
157 {
158 	uint8_t status_reg;
159 
160 	flash_put_get_wrapper(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
161 	flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, addr);
162 	flash_put_get(data, NULL, size, 4);
163 
164 	do {
165 		flash_put_get_wrapper(FLASHCMD_READ_STATUS, NULL, &status_reg, 1);
166 	} while (status_reg & 0x1 && !flash_was_aborted());
167 }
168 
__no_inline_not_in_flash_func(flash_write_partial)169 void __no_inline_not_in_flash_func(flash_write_partial)(uint32_t flash_offs, const uint8_t *data,
170 							size_t count)
171 {
172 	rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)
173 					rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
174 	rom_flash_exit_xip_fn exit_xip = (rom_flash_exit_xip_fn)
175 						rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
176 	rom_flash_flush_cache_fn flush_cache = (rom_flash_flush_cache_fn)
177 						rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
178 
179 	flash_init_boot2_copyout();
180 
181 	__compiler_memory_barrier();
182 
183 	connect_internal_flash();
184 	exit_xip();
185 	flash_write_partial_internal(flash_offs, data, count);
186 	flush_cache();
187 	flash_enable_xip_via_boot2();
188 }
189 
is_valid_range(off_t offset,uint32_t size)190 static bool is_valid_range(off_t offset, uint32_t size)
191 {
192 	return (offset >= 0) && ((offset + size) <= FLASH_SIZE);
193 }
194 
flash_rpi_read(const struct device * dev,off_t offset,void * data,size_t size)195 static int flash_rpi_read(const struct device *dev, off_t offset, void *data, size_t size)
196 {
197 	if (size == 0) {
198 		return 0;
199 	}
200 
201 	if (!is_valid_range(offset, size)) {
202 		LOG_ERR("Read range exceeds the flash boundaries");
203 		return -EINVAL;
204 	}
205 
206 	memcpy(data, (uint8_t *)(CONFIG_FLASH_BASE_ADDRESS + offset), size);
207 
208 	return 0;
209 }
210 
flash_rpi_write(const struct device * dev,off_t offset,const void * data,size_t size)211 static int flash_rpi_write(const struct device *dev, off_t offset, const void *data, size_t size)
212 {
213 	uint32_t key;
214 	size_t bytes_to_write;
215 	uint8_t *data_pointer = (uint8_t *)data;
216 
217 	if (size == 0) {
218 		return 0;
219 	}
220 
221 	if (!is_valid_range(offset, size)) {
222 		LOG_ERR("Write range exceeds the flash boundaries. Offset=%#lx, Size=%u",
223 				offset, size);
224 		return -EINVAL;
225 	}
226 
227 	key = irq_lock();
228 
229 	if ((offset & (PAGE_SIZE - 1)) > 0) {
230 		bytes_to_write = MIN(PAGE_SIZE - (offset & (PAGE_SIZE - 1)), size);
231 		memcpy(flash_ram_buffer, data_pointer, bytes_to_write);
232 		flash_write_partial(offset, flash_ram_buffer, bytes_to_write);
233 		data_pointer += bytes_to_write;
234 		size -= bytes_to_write;
235 		offset += bytes_to_write;
236 	}
237 
238 	while (size >= PAGE_SIZE) {
239 		bytes_to_write = PAGE_SIZE;
240 		memcpy(flash_ram_buffer, data_pointer, bytes_to_write);
241 		flash_range_program(offset, flash_ram_buffer, bytes_to_write);
242 		data_pointer += bytes_to_write;
243 		size -= bytes_to_write;
244 		offset += bytes_to_write;
245 	}
246 
247 	if (size > 0) {
248 		memcpy(flash_ram_buffer, data_pointer, size);
249 		flash_write_partial(offset, flash_ram_buffer, size);
250 	}
251 
252 	irq_unlock(key);
253 
254 	return 0;
255 }
256 
flash_rpi_erase(const struct device * dev,off_t offset,size_t size)257 static int flash_rpi_erase(const struct device *dev, off_t offset, size_t size)
258 {
259 	uint32_t key;
260 
261 	if (size == 0) {
262 		return 0;
263 	}
264 
265 	if (!is_valid_range(offset, size)) {
266 		LOG_ERR("Erase range exceeds the flash boundaries. Offset=%#lx, Size=%u",
267 				offset, size);
268 		return -EINVAL;
269 	}
270 
271 	if ((offset % SECTOR_SIZE) || (size % SECTOR_SIZE)) {
272 		LOG_ERR("Erase range is not a multiple of the sector size. Offset=%#lx, Size=%u",
273 				offset, size);
274 		return -EINVAL;
275 	}
276 
277 	key = irq_lock();
278 
279 	flash_range_erase(offset, size);
280 
281 	irq_unlock(key);
282 
283 	return 0;
284 }
285 
flash_rpi_get_parameters(const struct device * dev)286 static const struct flash_parameters *flash_rpi_get_parameters(const struct device *dev)
287 {
288 	ARG_UNUSED(dev);
289 
290 	return &flash_rpi_parameters;
291 }
292 
293 #if CONFIG_FLASH_PAGE_LAYOUT
294 
295 static const struct flash_pages_layout flash_rpi_pages_layout = {
296 	.pages_count = FLASH_SIZE / SECTOR_SIZE,
297 	.pages_size = SECTOR_SIZE,
298 };
299 
flash_rpi_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)300 void flash_rpi_page_layout(const struct device *dev, const struct flash_pages_layout **layout,
301 				size_t *layout_size)
302 {
303 	*layout = &flash_rpi_pages_layout;
304 	*layout_size = 1;
305 }
306 
307 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
308 
309 static DEVICE_API(flash, flash_rpi_driver_api) = {
310 	.read = flash_rpi_read,
311 	.write = flash_rpi_write,
312 	.erase = flash_rpi_erase,
313 	.get_parameters = flash_rpi_get_parameters,
314 #ifdef CONFIG_FLASH_PAGE_LAYOUT
315 	.page_layout = flash_rpi_page_layout,
316 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
317 };
318 
319 DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL,
320 		      CONFIG_FLASH_INIT_PRIORITY, &flash_rpi_driver_api);
321