1 /*
2  * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT espressif_esp32_flash_controller
8 #define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
9 
10 #define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size)
11 #define FLASH_ERASE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, erase_block_size)
12 
13 /*
14  * HAL includes go first to
15  * avoid BIT macro redefinition
16  */
17 #include <esp_flash.h>
18 #include <spi_flash_mmap.h>
19 #include <soc/spi_struct.h>
20 #include <esp_flash_encrypt.h>
21 #include <esp_flash_internal.h>
22 #include <bootloader_flash_priv.h>
23 
24 #include <zephyr/kernel.h>
25 #include <zephyr/device.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <zephyr/drivers/flash.h>
30 #include <soc.h>
31 
32 #include <zephyr/logging/log.h>
33 LOG_MODULE_REGISTER(flash_esp32, CONFIG_FLASH_LOG_LEVEL);
34 
35 #define FLASH_SEM_TIMEOUT (k_is_in_isr() ? K_NO_WAIT : K_FOREVER)
36 
37 struct flash_esp32_dev_config {
38 	spi_dev_t *controller;
39 };
40 
41 struct flash_esp32_dev_data {
42 #ifdef CONFIG_MULTITHREADING
43 	struct k_sem sem;
44 #endif
45 };
46 
47 static const struct flash_parameters flash_esp32_parameters = {
48 	.write_block_size = FLASH_WRITE_BLK_SZ,
49 	.erase_value = 0xff,
50 };
51 
52 #ifdef CONFIG_MULTITHREADING
flash_esp32_sem_take(const struct device * dev)53 static inline void flash_esp32_sem_take(const struct device *dev)
54 {
55 	struct flash_esp32_dev_data *data = dev->data;
56 
57 	k_sem_take(&data->sem, FLASH_SEM_TIMEOUT);
58 }
59 
flash_esp32_sem_give(const struct device * dev)60 static inline void flash_esp32_sem_give(const struct device *dev)
61 {
62 	struct flash_esp32_dev_data *data = dev->data;
63 
64 	k_sem_give(&data->sem);
65 }
66 #else
67 
68 #define flash_esp32_sem_take(dev) do {} while (0)
69 #define flash_esp32_sem_give(dev) do {} while (0)
70 
71 #endif /* CONFIG_MULTITHREADING */
72 
73 #include <zephyr/kernel.h>
74 #include <zephyr/logging/log.h>
75 #include <zephyr/sys/util.h>
76 #include <stdint.h>
77 #include <string.h>
78 
79 #ifdef CONFIG_MCUBOOT
80 #define READ_BUFFER_SIZE 32
flash_esp32_is_aligned(off_t address,void * buffer,size_t length)81 static bool flash_esp32_is_aligned(off_t address, void *buffer, size_t length)
82 {
83 	/* check if address, buffer pointer, and length are 4-byte aligned */
84 	return ((address & 3) == 0) && (((uintptr_t)buffer & 3) == 0) && ((length & 3) == 0);
85 }
86 #endif
87 
flash_esp32_read(const struct device * dev,off_t address,void * buffer,size_t length)88 static int flash_esp32_read(const struct device *dev, off_t address, void *buffer, size_t length)
89 {
90 	int ret = 0;
91 
92 #ifdef CONFIG_MCUBOOT
93 	uint8_t *dest_ptr = (uint8_t *)buffer;
94 	size_t remaining = length;
95 	size_t copy_size = 0;
96 	size_t aligned_size = 0;
97 	bool allow_decrypt = esp_flash_encryption_enabled();
98 
99 	if (flash_esp32_is_aligned(address, buffer, length)) {
100 		ret = esp_rom_flash_read(address, buffer, length, allow_decrypt);
101 		return (ret == ESP_OK) ? 0 : -EIO;
102 	}
103 
104 	/* handle unaligned reading */
105 	uint8_t __aligned(4) temp_buf[READ_BUFFER_SIZE + 8];
106 	while (remaining > 0) {
107 		size_t addr_offset = address & 3;
108 		size_t buf_offset = (uintptr_t)dest_ptr & 3;
109 
110 		copy_size = (remaining > READ_BUFFER_SIZE) ? READ_BUFFER_SIZE : remaining;
111 
112 		if (addr_offset == 0 && buf_offset == 0 && copy_size >= 4) {
113 			aligned_size = copy_size & ~3;
114 			ret = esp_rom_flash_read(address, dest_ptr, aligned_size, allow_decrypt);
115 			if (ret != ESP_OK) {
116 				return -EIO;
117 			}
118 
119 			address += aligned_size;
120 			dest_ptr += aligned_size;
121 			remaining -= aligned_size;
122 		} else {
123 			size_t start_addr = address - addr_offset;
124 
125 			aligned_size = (copy_size + addr_offset + 3) & ~3;
126 
127 			ret = esp_rom_flash_read(start_addr, temp_buf, aligned_size, allow_decrypt);
128 			if (ret != ESP_OK) {
129 				return -EIO;
130 			}
131 
132 			memcpy(dest_ptr, temp_buf + addr_offset, copy_size);
133 
134 			address += copy_size;
135 			dest_ptr += copy_size;
136 			remaining -= copy_size;
137 		}
138 	}
139 #else
140 	flash_esp32_sem_take(dev);
141 
142 	if (esp_flash_encryption_enabled()) {
143 		ret = esp_flash_read_encrypted(NULL, address, buffer, length);
144 	} else {
145 		ret = esp_flash_read(NULL, buffer, address, length);
146 	}
147 
148 	flash_esp32_sem_give(dev);
149 #endif
150 
151 	if (ret != 0) {
152 		LOG_ERR("Flash read error: %d", ret);
153 		return -EIO;
154 	}
155 
156 	return 0;
157 }
158 
flash_esp32_write(const struct device * dev,off_t address,const void * buffer,size_t length)159 static int flash_esp32_write(const struct device *dev,
160 			     off_t address,
161 			     const void *buffer,
162 			     size_t length)
163 {
164 	int ret = 0;
165 
166 #ifdef CONFIG_MCUBOOT
167 	if (!flash_esp32_is_aligned(address, (void *)buffer, length)) {
168 		LOG_ERR("Unaligned flash write is not supported");
169 		return -EINVAL;
170 	}
171 
172 	bool encrypt = esp_flash_encryption_enabled();
173 
174 	ret = esp_rom_flash_write(address, (void *)buffer, length, encrypt);
175 #else
176 	flash_esp32_sem_take(dev);
177 
178 	if (esp_flash_encryption_enabled()) {
179 		ret = esp_flash_write_encrypted(NULL, address, buffer, length);
180 	} else {
181 		ret = esp_flash_write(NULL, buffer, address, length);
182 	}
183 
184 	flash_esp32_sem_give(dev);
185 #endif
186 
187 	if (ret != 0) {
188 		LOG_ERR("Flash write error: %d", ret);
189 		return -EIO;
190 	}
191 
192 	return 0;
193 }
194 
flash_esp32_erase(const struct device * dev,off_t start,size_t len)195 static int flash_esp32_erase(const struct device *dev, off_t start, size_t len)
196 {
197 	int ret = 0;
198 
199 #ifdef CONFIG_MCUBOOT
200 	ret = esp_rom_flash_erase_range(start, len);
201 #else
202 	flash_esp32_sem_take(dev);
203 	ret = esp_flash_erase_region(NULL, start, len);
204 	flash_esp32_sem_give(dev);
205 #endif
206 	if (ret != 0) {
207 		LOG_ERR("Flash erase error: %d", ret);
208 		return -EIO;
209 	}
210 	return 0;
211 }
212 
213 #if CONFIG_FLASH_PAGE_LAYOUT
214 static const struct flash_pages_layout flash_esp32_pages_layout = {
215 	.pages_count = DT_REG_SIZE(SOC_NV_FLASH_NODE) / FLASH_ERASE_BLK_SZ,
216 	.pages_size = DT_PROP(SOC_NV_FLASH_NODE, erase_block_size),
217 };
218 
flash_esp32_page_layout(const struct device * dev,const struct flash_pages_layout ** layout,size_t * layout_size)219 void flash_esp32_page_layout(const struct device *dev,
220 			     const struct flash_pages_layout **layout,
221 			     size_t *layout_size)
222 {
223 	*layout = &flash_esp32_pages_layout;
224 	*layout_size = 1;
225 }
226 #endif /* CONFIG_FLASH_PAGE_LAYOUT */
227 
228 static const struct flash_parameters *
flash_esp32_get_parameters(const struct device * dev)229 flash_esp32_get_parameters(const struct device *dev)
230 {
231 	ARG_UNUSED(dev);
232 
233 	return &flash_esp32_parameters;
234 }
235 
flash_esp32_init(const struct device * dev)236 static int flash_esp32_init(const struct device *dev)
237 {
238 #ifdef CONFIG_MULTITHREADING
239 	struct flash_esp32_dev_data *const dev_data = dev->data;
240 
241 	k_sem_init(&dev_data->sem, 1, 1);
242 #endif /* CONFIG_MULTITHREADING */
243 
244 	return 0;
245 }
246 
247 static DEVICE_API(flash, flash_esp32_driver_api) = {
248 	.read = flash_esp32_read,
249 	.write = flash_esp32_write,
250 	.erase = flash_esp32_erase,
251 	.get_parameters = flash_esp32_get_parameters,
252 #ifdef CONFIG_FLASH_PAGE_LAYOUT
253 	.page_layout = flash_esp32_page_layout,
254 #endif
255 };
256 
257 static struct flash_esp32_dev_data flash_esp32_data;
258 
259 static const struct flash_esp32_dev_config flash_esp32_config = {
260 	.controller = (spi_dev_t *) DT_INST_REG_ADDR(0),
261 };
262 
263 DEVICE_DT_INST_DEFINE(0, flash_esp32_init,
264 		      NULL,
265 		      &flash_esp32_data, &flash_esp32_config,
266 		      POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
267 		      &flash_esp32_driver_api);
268