1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9 #include <rtthread.h>
10 #include <rtdevice.h>
11
12 #include "spi_flash.h"
13 #include "spi_flash_w25qxx_mtd.h"
14
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19
20 #define FLASH_DEBUG
21
22 #ifdef FLASH_DEBUG
23 #define FLASH_TRACE printf
24 #else
25 #define FLASH_TRACE(...)
26 #endif /* #ifdef FLASH_DEBUG */
27
28 /* JEDEC Manufacturer’s ID */
29 #define MF_ID (0xEF)
30 /* JEDEC Device ID: Memory type and Capacity */
31 #define MTC_W25Q80_BV (0x4014) /* W25Q80BV */
32 #define MTC_W25Q16_BV_CL_CV (0x4015) /* W25Q16BV W25Q16CL W25Q16CV */
33 #define MTC_W25Q16_DW (0x6015) /* W25Q16DW */
34 #define MTC_W25Q32_BV (0x4016) /* W25Q32BV */
35 #define MTC_W25Q32_DW (0x6016) /* W25Q32DW */
36 #define MTC_W25Q64_BV_CV (0x4017) /* W25Q64BV W25Q64CV */
37 #define MTC_W25Q64_DW (0x4017) /* W25Q64DW */
38 #define MTC_W25Q128_BV (0x4018) /* W25Q128BV */
39 #define MTC_W25Q256_FV (TBD) /* W25Q256FV */
40
41 #define MTC_W25X80 (0x3014)
42
43 /* command list */
44 #define CMD_WRSR (0x01) /* Write Status Register */
45 #define CMD_PP (0x02) /* Page Program */
46 #define CMD_READ (0x03) /* Read Data */
47 #define CMD_WRDI (0x04) /* Write Disable */
48 #define CMD_RDSR1 (0x05) /* Read Status Register-1 */
49 #define CMD_WREN (0x06) /* Write Enable */
50 #define CMD_FAST_READ (0x0B) /* Fast Read */
51 #define CMD_ERASE_4K (0x20) /* Sector Erase:4K */
52 #define CMD_RDSR2 (0x35) /* Read Status Register-2 */
53 #define CMD_ERASE_32K (0x52) /* 32KB Block Erase */
54 #define CMD_JEDEC_ID (0x9F) /* Read JEDEC ID */
55 #define CMD_ERASE_full (0xC7) /* Chip Erase */
56 #define CMD_ERASE_64K (0xD8) /* 64KB Block Erase */
57 #define CMD_MANU_ID (0x90)
58
59 #define DUMMY (0xFF)
60
61 #define FLASH_ERASE_CMD CMD_ERASE_4K
62 #define FLASH_BLOCK_SIZE 4096
63 #define FLASH_PAGE_SIZE 256
64
w25qxx_lock(struct rt_mtd_nor_device * device)65 static void w25qxx_lock(struct rt_mtd_nor_device *device)
66 {
67 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
68 rt_mutex_take(&mtd->lock, RT_WAITING_FOREVER);
69 }
70
w25qxx_unlock(struct rt_mtd_nor_device * device)71 static void w25qxx_unlock(struct rt_mtd_nor_device *device)
72 {
73 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
74 rt_mutex_release(&mtd->lock);
75 }
76
w25qxx_read_status(struct rt_mtd_nor_device * device)77 static rt_uint8_t w25qxx_read_status(struct rt_mtd_nor_device *device)
78 {
79 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
80 return rt_spi_sendrecv8(mtd->rt_spi_device, CMD_RDSR1);
81 }
82
w25qxx_wait_busy(struct rt_mtd_nor_device * device)83 static void w25qxx_wait_busy(struct rt_mtd_nor_device *device)
84 {
85 while( w25qxx_read_status(device) & (0x01));
86 }
87
w25qxx_read_id(struct rt_mtd_nor_device * device)88 static rt_err_t w25qxx_read_id(struct rt_mtd_nor_device *device)
89 {
90 rt_uint8_t cmd;
91 rt_uint8_t id_recv[3];
92
93 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
94
95 w25qxx_lock(device);
96
97 cmd = 0xFF; /* reset SPI FLASH, cancel all cmd in processing. */
98 rt_spi_send(mtd->rt_spi_device, &cmd, 1);
99
100 cmd = CMD_WRDI;
101 rt_spi_send(mtd->rt_spi_device, &cmd, 1);
102
103 /* read flash id */
104 cmd = CMD_JEDEC_ID;
105 rt_spi_send_then_recv(mtd->rt_spi_device, &cmd, 1, id_recv, 3);
106
107 w25qxx_unlock(device);
108
109 return (rt_uint32_t)(id_recv[0] << 16) | (id_recv[1] << 8) | id_recv[2];
110 }
111
w25qxx_read(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint8_t * buffer,rt_size_t length)112 static rt_size_t w25qxx_read(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint8_t *buffer, rt_size_t length)
113 {
114 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
115 rt_uint8_t send_buffer[4];
116
117 if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
118 return 0;
119
120
121 w25qxx_lock(device);
122
123 send_buffer[0] = CMD_WRDI;
124 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
125
126 send_buffer[0] = CMD_READ;
127 send_buffer[1] = (rt_uint8_t)(offset>>16);
128 send_buffer[2] = (rt_uint8_t)(offset>>8);
129 send_buffer[3] = (rt_uint8_t)(offset);
130 rt_spi_send_then_recv(mtd->rt_spi_device,
131 send_buffer, 4,
132 buffer, length);
133
134 w25qxx_unlock(device);
135 return length;
136 }
137
w25qxx_write(struct rt_mtd_nor_device * device,rt_off_t offset,const rt_uint8_t * buffer,rt_size_t length)138 static rt_size_t w25qxx_write(struct rt_mtd_nor_device *device, rt_off_t offset, const rt_uint8_t *buffer, rt_size_t length)
139 {
140 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
141 rt_uint8_t send_buffer[4];
142 rt_uint8_t *write_ptr ;
143 rt_size_t write_size,write_total;
144
145 if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
146 return 0;
147
148 w25qxx_lock(device);
149
150 send_buffer[0] = CMD_WREN;
151 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
152 w25qxx_wait_busy(device); // wait erase done.
153
154 write_size = 0;
155 write_total = 0;
156 write_ptr = (rt_uint8_t *)buffer;
157 while(write_total < length)
158 {
159 send_buffer[0] = CMD_WREN;
160 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
161
162 //write first page...
163 send_buffer[0] = CMD_PP;
164 send_buffer[1] = (rt_uint8_t)(offset >> 16);
165 send_buffer[2] = (rt_uint8_t)(offset >> 8);
166 send_buffer[3] = (rt_uint8_t)(offset);
167
168 //address % FLASH_PAGE_SIZE + length
169 if(((offset & (FLASH_PAGE_SIZE - 1)) + (length - write_total)) > FLASH_PAGE_SIZE)
170 {
171 write_size = FLASH_PAGE_SIZE - (offset & (FLASH_PAGE_SIZE - 1));
172 }
173 else
174 {
175 write_size = (length - write_total);
176 }
177
178 rt_spi_send_then_send(mtd->rt_spi_device,
179 send_buffer, 4,
180 write_ptr + write_total, write_size);
181 w25qxx_wait_busy(device);
182
183
184 offset += write_size;
185 write_total += write_size;
186 }
187
188 send_buffer[0] = CMD_WRDI;
189 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
190
191 w25qxx_unlock(device);
192
193 return length;
194 }
195
w25qxx_erase_block(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint32_t length)196 static rt_err_t w25qxx_erase_block(struct rt_mtd_nor_device *device, rt_off_t offset, rt_uint32_t length)
197 {
198 struct spi_flash_mtd *mtd = (struct spi_flash_mtd *)device;
199 rt_uint8_t send_buffer[4];
200 rt_uint32_t erase_size = 0;
201
202 //offset must be ALIGN_DOWN to BLOCKSIZE
203 if(offset != RT_ALIGN_DOWN(offset,FLASH_BLOCK_SIZE))
204 return 0;
205
206 if((offset + length) > device->block_end * FLASH_BLOCK_SIZE)
207 return 0;
208
209 /* check length must align to block size */
210 if(length % device->block_size != 0)
211 {
212 rt_kprintf("param length = %d ,error\n",length);
213 return 0;
214 }
215
216 w25qxx_lock(device);
217
218 send_buffer[0] = CMD_WREN;
219 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
220 w25qxx_wait_busy(device); // wait erase done.
221 while (erase_size < length)
222 {
223 send_buffer[0] = CMD_ERASE_4K;
224 send_buffer[1] = (rt_uint8_t) (offset >> 16);
225 send_buffer[2] = (rt_uint8_t) (offset >> 8);
226 send_buffer[3] = (rt_uint8_t) (offset);
227 rt_spi_send(mtd->rt_spi_device, send_buffer, 4);
228 w25qxx_wait_busy(device); // wait erase done.
229
230 erase_size += 4096;
231 offset += 4096;
232 }
233 send_buffer[0] = CMD_WRDI;
234 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
235
236 w25qxx_unlock(device);
237 return RT_EOK;
238 }
239
240 const static struct rt_mtd_nor_driver_ops w25qxx_mtd_ops =
241 {
242 w25qxx_read_id,
243 w25qxx_read,
244 w25qxx_write,
245 w25qxx_erase_block,
246 };
247
w25qxx_mtd_init(const char * mtd_name,const char * spi_device_name)248 rt_err_t w25qxx_mtd_init(const char *mtd_name,const char * spi_device_name)
249 {
250 rt_err_t result = RT_EOK;
251 rt_uint32_t id;
252 rt_uint8_t send_buffer[3];
253
254 struct rt_spi_device* rt_spi_device;
255 struct spi_flash_mtd* mtd = (struct spi_flash_mtd *)rt_malloc(sizeof(struct spi_flash_mtd));
256
257 RT_ASSERT(mtd != RT_NULL);
258
259 /* initialize mutex */
260 if (rt_mutex_init(&mtd->lock, mtd_name, RT_IPC_FLAG_FIFO) != RT_EOK)
261 {
262 FLASH_TRACE("init mtd lock mutex failed\n");
263 result = -RT_ENOSYS;
264
265 goto _error_exit;
266 }
267
268 rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
269 if(rt_spi_device == RT_NULL)
270 {
271 FLASH_TRACE("spi device %s not found!\r\n", spi_device_name);
272 result = -RT_ENOSYS;
273
274 goto _error_exit;
275 }
276 mtd->rt_spi_device = rt_spi_device;
277 /* config spi */
278 {
279 struct rt_spi_configuration cfg;
280 cfg.data_width = 8;
281 cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
282 cfg.max_hz = 20 * 1000 * 1000; /* 20 */
283 rt_spi_configure(rt_spi_device, &cfg);
284 }
285
286 /* Init Flash device */
287 {
288 w25qxx_lock(&mtd->mtd_device);
289
290 send_buffer[0] = CMD_WREN;
291 rt_spi_send(mtd->rt_spi_device, send_buffer, 1);
292 w25qxx_wait_busy(&mtd->mtd_device);
293
294 send_buffer[0] = CMD_WRSR;
295 send_buffer[1] = 0;
296 send_buffer[2] = 0;
297 rt_spi_send(mtd->rt_spi_device, send_buffer, 3);
298 w25qxx_wait_busy(&mtd->mtd_device);
299
300 w25qxx_unlock(&mtd->mtd_device);
301 }
302
303 id = w25qxx_read_id(&mtd->mtd_device);
304
305 mtd->mtd_device.block_size = 4096;
306 mtd->mtd_device.block_start = 0;
307 switch(id & 0xFFFF)
308 {
309 case MTC_W25Q80_BV: /* W25Q80BV */
310 mtd->mtd_device.block_end = 256;
311 break;
312 case MTC_W25Q16_BV_CL_CV: /* W25Q16BV W25Q16CL W25Q16CV */
313 case MTC_W25Q16_DW: /* W25Q16DW */
314 mtd->mtd_device.block_end = 512;
315 break;
316 case MTC_W25Q32_BV: /* W25Q32BV */
317 case MTC_W25Q32_DW: /* W25Q32DW */
318 mtd->mtd_device.block_end = 1024;
319 break;
320 case MTC_W25Q64_BV_CV: /* W25Q64BV W25Q64CV */
321 mtd->mtd_device.block_end = 2048;
322 break;
323 case MTC_W25Q128_BV: /* W25Q128BV */
324 mtd->mtd_device.block_end = 4086;
325 break;
326 }
327 mtd->mtd_device.ops = &w25qxx_mtd_ops;
328 rt_mtd_nor_register_device(mtd_name,&mtd->mtd_device);
329
330 return RT_EOK;
331
332 _error_exit:
333 if(mtd != RT_NULL)
334 rt_free(mtd);
335 return result;
336 }
337