Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / drivers / flash_w25q128fv.c
blobd005f8e8eeb5d21c7553be9b6479672ee3da19c0
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
20 * Author: Dominic Clifton - Initial implementation and testing.
23 #include <stdbool.h>
24 #include <stdint.h>
26 #include "platform.h"
28 #if defined(USE_FLASH_W25Q128FV) && defined(USE_QUADSPI)
30 #define USE_FLASH_WRITES_USING_4LINES
31 #define USE_FLASH_READS_USING_4LINES
33 #include "build/debug.h"
34 #include "common/utils.h"
36 #include "drivers/flash.h"
37 #include "drivers/flash_impl.h"
38 #include "drivers/flash_w25q128fv.h"
39 #include "drivers/bus_quadspi.h"
41 // JEDEC ID
42 #define JEDEC_ID_WINBOND_W25Q128FV_SPI 0xEF4018
43 #define JEDEC_ID_WINBOND_W25Q128FV_QUADSPI 0xEF6018
44 #define JEDEC_ID_WINBOND_W25Q128JV_QUADSPI 0xEF7018
46 // Device size parameters
47 #define W25Q128FV_PAGE_SIZE 2048
48 #define W25Q128FV_PAGES_PER_BLOCK 64
49 #define W25Q128FV_BLOCKS_PER_DIE 1024
50 #define W25Q128FV_BLOCK_SIZE (W25Q128FV_PAGES_PER_BLOCK * W25Q128FV_PAGE_SIZE)
52 // Sizes
53 #define W25Q128FV_STATUS_REGISTER_BITS 8
54 #define W25Q128FV_ADDRESS_BITS 24
57 // Instructions
58 #define W25Q128FV_INSTRUCTION_RDID 0x9F
60 #define W25Q128FV_INSTRUCTION_ENABLE_RESET 0x66
61 #define W25Q128FV_INSTRUCTION_RESET_DEVICE 0x99
63 #define W25Q128FV_INSTRUCTION_READ_STATUS1_REG 0x05
64 #define W25Q128FV_INSTRUCTION_READ_STATUS2_REG 0x35
65 #define W25Q128FV_INSTRUCTION_READ_STATUS3_REG 0x15
67 #define W25Q128FV_INSTRUCTION_WRITE_STATUS1_REG 0x01
68 #define W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG 0x31
69 #define W25Q128FV_INSTRUCTION_WRITE_STATUS3_REG 0x11
71 #define W25Q128FV_INSTRUCTION_WRITE_ENABLE 0x06
72 #define W25Q128FV_INSTRUCTION_VOLATILE_WRITE_ENABLE 0x50
73 #define W25Q128FV_INSTRUCTION_BLOCK_ERASE_64KB 0xD8
74 #define W25Q128FV_INSTRUCTION_CHIP_ERASE 0xC7
76 #define W25Q128FV_INSTRUCTION_ENTER_QPI_MODE 0x38
78 #define W25Q128FV_INSTRUCTION_FAST_READ 0x0B
79 #define W25Q128FV_INSTRUCTION_FAST_READ_QUAD_OUTPUT 0x6B
81 #define W25Q128FV_INSTRUCTION_PAGE_PROGRAM 0x02
82 #define W25Q128FV_INSTRUCTION_QUAD_PAGE_PROGRAM 0x32
84 #define W25Q128FV_SR1_BIT_WRITE_IN_PROGRESS (1 << 0)
85 #define W25Q128FV_SR1_BIT_WRITE_ENABLED (1 << 1)
87 #define W25Q128FV_SR2_BIT_QUAD_ENABLE (1 << 1)
90 //#define W25Q128FV_INSTRUCTION_WRITE_DISABLE 0x04
91 //#define W25Q128FV_INSTRUCTION_PAGE_PROGRAM 0x02
93 // Timings (2ms minimum to avoid 1 tick advance in consecutive calls to HAL_GetTick).
94 #define W25Q128FV_TIMEOUT_PAGE_READ_MS 4
95 #define W25Q128FV_TIMEOUT_RESET_MS 2 // tRST = 30us
96 #define W25Q128FV_TIMEOUT_BLOCK_ERASE_64KB_MS 2000 // tBE2max = 2000ms, tBE2typ = 150ms
97 #define W25Q128FV_TIMEOUT_CHIP_ERASE_MS (200 * 1000) // tCEmax 200s, tCEtyp = 40s
99 #define W25Q128FV_TIMEOUT_PAGE_PROGRAM_MS 2 // tPPmax = 700us, tPPtyp = 250us
100 #define W25Q128FV_TIMEOUT_WRITE_ENABLE_MS 2
103 typedef enum {
104 INITIAL_MODE_SPI = 0,
105 INITIAL_MODE_QUADSPI,
106 } w25q128fv_initialMode_e;
108 typedef struct w25q128fvState_s {
109 w25q128fv_initialMode_e initialMode;
110 uint32_t currentWriteAddress;
111 } w25q128fvState_t;
113 w25q128fvState_t w25q128fvState = { 0 };
115 static bool w25q128fv_waitForReady(flashDevice_t *fdevice);
116 static void w25q128fv_waitForTimeout(flashDevice_t *fdevice);
118 static void w25q128fv_setTimeout(flashDevice_t *fdevice, uint32_t timeoutMillis)
120 uint32_t now = HAL_GetTick();
121 fdevice->timeoutAt = now + timeoutMillis;
124 static void w25q128fv_performOneByteCommand(flashDeviceIO_t *io, uint8_t command)
126 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
127 quadSpiTransmit1LINE(quadSpi, command, 0, NULL, 0);
130 static void w25q128fv_performCommandWithAddress(flashDeviceIO_t *io, uint8_t command, uint32_t address)
132 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
134 quadSpiInstructionWithAddress1LINE(quadSpi, command, 0, address & 0xffffff, W25Q128FV_ADDRESS_BITS);
137 static void w25q128fv_writeEnable(flashDevice_t *fdevice)
139 w25q128fv_performOneByteCommand(&fdevice->io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
142 static uint8_t w25q128fv_readRegister(flashDeviceIO_t *io, uint8_t command)
144 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
146 uint8_t in[1];
147 quadSpiReceive1LINE(quadSpi, command, 0, in, W25Q128FV_STATUS_REGISTER_BITS / 8);
149 return in[0];
152 static void w25q128fv_writeRegister(flashDeviceIO_t *io, uint8_t command, uint8_t data)
154 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
156 quadSpiTransmit1LINE(quadSpi, command, 0, &data, W25Q128FV_STATUS_REGISTER_BITS / 8);
159 static void w25q128fv_deviceReset(flashDevice_t *fdevice)
161 flashDeviceIO_t *io = &fdevice->io;
163 w25q128fv_waitForReady(fdevice);
164 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_ENABLE_RESET);
165 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_RESET_DEVICE);
167 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_RESET_MS);
168 w25q128fv_waitForTimeout(fdevice);
170 w25q128fv_waitForReady(fdevice);
172 #ifdef DISABLE_NONVOLATILE_QE_MODE // Use this if you encounter a chip with it's QE bit enabled when it shouldn't be.
173 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
174 w25q128fv_writeRegister(io, W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG, 0x00);
175 #endif
178 #if defined(USE_FLASH_WRITES_USING_4LINES) || defined(USE_FLASH_READS_USING_4LINES)
179 uint8_t registerValue = w25q128fv_readRegister(io, W25Q128FV_INSTRUCTION_READ_STATUS2_REG);
182 // WARNING: DO NOT ENABLE QE bit if IO2/IO3 are connected to GND or VCC.
184 // See datasheet https://www.winbond.com/resource-files/w25q128fv%20rev.m%2005132016%20kms.pdf
185 // W25Q128FV - Revision M - 7.1.10 Quad Enable
187 // There is no such warning for the W25Q128JV in the same documentation section
188 // See datasheet https://www.winbond.com/resource-files/w25q128jv%20revg%2004082019%20plus.pdf
189 // W25Q128JV - Revision G - 7.1.4 Quad Enable
192 if ((registerValue & W25Q128FV_SR2_BIT_QUAD_ENABLE) == 0) {
193 // Enable QUADSPI mode.
194 registerValue = w25q128fv_readRegister(io, W25Q128FV_INSTRUCTION_READ_STATUS2_REG);
196 uint8_t newValue = registerValue;
197 newValue |= W25Q128FV_SR2_BIT_QUAD_ENABLE;
199 //w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
200 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_VOLATILE_WRITE_ENABLE);
201 w25q128fv_writeRegister(io, W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG, newValue);
203 #endif
206 bool w25q128fv_isReady(flashDevice_t *fdevice)
208 uint8_t status = w25q128fv_readRegister(&fdevice->io, W25Q128FV_INSTRUCTION_READ_STATUS1_REG);
210 bool busy = (status & W25Q128FV_SR1_BIT_WRITE_IN_PROGRESS);
212 return !busy;
215 static bool w25q128fv_isWritable(flashDevice_t *fdevice)
217 uint8_t status = w25q128fv_readRegister(&fdevice->io, W25Q128FV_INSTRUCTION_READ_STATUS1_REG);
219 bool writable = (status & W25Q128FV_SR1_BIT_WRITE_ENABLED);
221 return writable;
224 bool w25q128fv_hasTimedOut(flashDevice_t *fdevice)
226 uint32_t now = HAL_GetTick();
227 if (cmp32(now, fdevice->timeoutAt) >= 0) {
228 return true;
230 return false;
233 void w25q128fv_waitForTimeout(flashDevice_t *fdevice)
235 while (!w25q128fv_hasTimedOut(fdevice)) { }
237 fdevice->timeoutAt = 0;
240 bool w25q128fv_waitForReady(flashDevice_t *fdevice)
242 bool ready = true;
243 while (!w25q128fv_isReady(fdevice)) {
244 if (w25q128fv_hasTimedOut(fdevice)) {
245 ready = false;
246 break;
249 fdevice->timeoutAt = 0;
251 return ready;
254 const flashVTable_t w25q128fv_vTable;
256 static void w25q128fv_deviceInit(flashDevice_t *flashdev);
258 bool w25q128fv_detect(flashDevice_t *fdevice, uint32_t chipID)
260 switch (chipID) {
261 case JEDEC_ID_WINBOND_W25Q128FV_SPI:
262 case JEDEC_ID_WINBOND_W25Q128FV_QUADSPI:
263 case JEDEC_ID_WINBOND_W25Q128JV_QUADSPI:
264 fdevice->geometry.sectors = 256;
265 fdevice->geometry.pagesPerSector = 256;
266 fdevice->geometry.pageSize = 256;
267 break;
269 default:
270 // Unsupported chip
271 fdevice->geometry.sectors = 0;
272 fdevice->geometry.pagesPerSector = 0;
273 fdevice->geometry.sectorSize = 0;
274 fdevice->geometry.totalSize = 0;
275 return false;
278 // use the chip id to determine the initial interface mode on cold-boot.
279 switch (chipID) {
280 case JEDEC_ID_WINBOND_W25Q128FV_SPI:
281 w25q128fvState.initialMode = INITIAL_MODE_SPI;
282 break;
284 case JEDEC_ID_WINBOND_W25Q128JV_QUADSPI:
285 case JEDEC_ID_WINBOND_W25Q128FV_QUADSPI:
286 w25q128fvState.initialMode = INITIAL_MODE_QUADSPI;
287 break;
289 default:
290 break;
293 fdevice->geometry.flashType = FLASH_TYPE_NOR;
294 fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
295 fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
297 w25q128fv_deviceReset(fdevice);
299 w25q128fv_deviceInit(fdevice);
301 fdevice->vTable = &w25q128fv_vTable;
303 return true;
306 static void w25q128fv_eraseSector(flashDevice_t *fdevice, uint32_t address)
309 w25q128fv_waitForReady(fdevice);
311 w25q128fv_writeEnable(fdevice);
313 w25q128fv_performCommandWithAddress(&fdevice->io, W25Q128FV_INSTRUCTION_BLOCK_ERASE_64KB, address);
315 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_BLOCK_ERASE_64KB_MS);
318 static void w25q128fv_eraseCompletely(flashDevice_t *fdevice)
320 w25q128fv_waitForReady(fdevice);
322 w25q128fv_writeEnable(fdevice);
324 w25q128fv_performOneByteCommand(&fdevice->io, W25Q128FV_INSTRUCTION_CHIP_ERASE);
326 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_CHIP_ERASE_MS);
330 static void w25q128fv_loadProgramData(flashDevice_t *fdevice, const uint8_t *data, int length)
332 w25q128fv_waitForReady(fdevice);
334 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
336 #ifdef USE_FLASH_WRITES_USING_4LINES
337 quadSpiTransmitWithAddress4LINES(quadSpi, W25Q128FV_INSTRUCTION_QUAD_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
338 #else
339 quadSpiTransmitWithAddress1LINE(quadSpi, W25Q128FV_INSTRUCTION_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
340 #endif
342 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_PAGE_PROGRAM_MS);
344 w25q128fvState.currentWriteAddress += length;
347 static void w25q128fv_pageProgramBegin(flashDevice_t *fdevice, uint32_t address, void (*callback)(uint32_t length))
349 fdevice->callback = callback;
350 w25q128fvState.currentWriteAddress = address;
353 static uint32_t w25q128fv_pageProgramContinue(flashDevice_t *fdevice, uint8_t const **buffers, uint32_t *bufferSizes, uint32_t bufferCount)
355 for (uint32_t i = 0; i < bufferCount; i++) {
356 w25q128fv_waitForReady(fdevice);
358 w25q128fv_writeEnable(fdevice);
360 // verify write enable is set.
361 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_WRITE_ENABLE_MS);
362 bool writable = false;
363 do {
364 writable = w25q128fv_isWritable(fdevice);
365 } while (!writable && w25q128fv_hasTimedOut(fdevice));
367 if (!writable) {
368 return 0; // TODO report failure somehow.
371 w25q128fv_loadProgramData(fdevice, buffers[i], bufferSizes[i]);
374 return fdevice->callbackArg;
377 static void w25q128fv_pageProgramFinish(flashDevice_t *fdevice)
379 UNUSED(fdevice);
382 static void w25q128fv_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, uint32_t length, void (*callback)(uint32_t length))
384 w25q128fv_pageProgramBegin(fdevice, address, callback);
385 w25q128fv_pageProgramContinue(fdevice, &data, &length, 1);
386 w25q128fv_pageProgramFinish(fdevice);
389 void w25q128fv_flush(flashDevice_t *fdevice)
391 UNUSED(fdevice);
394 static int w25q128fv_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, uint32_t length)
396 if (!w25q128fv_waitForReady(fdevice)) {
397 return 0;
400 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
401 #ifdef USE_FLASH_READS_USING_4LINES
402 bool status = quadSpiReceiveWithAddress4LINES(quadSpi, W25Q128FV_INSTRUCTION_FAST_READ_QUAD_OUTPUT, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
403 #else
404 bool status = quadSpiReceiveWithAddress1LINE(quadSpi, W25Q128FV_INSTRUCTION_FAST_READ, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
405 #endif
406 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_PAGE_READ_MS);
408 if (!status) {
409 return 0;
412 return length;
417 const flashGeometry_t* w25q128fv_getGeometry(flashDevice_t *fdevice)
419 return &fdevice->geometry;
422 const flashVTable_t w25q128fv_vTable = {
423 .isReady = w25q128fv_isReady,
424 .waitForReady = w25q128fv_waitForReady,
425 .eraseSector = w25q128fv_eraseSector,
426 .eraseCompletely = w25q128fv_eraseCompletely,
427 .pageProgramBegin = w25q128fv_pageProgramBegin,
428 .pageProgramContinue = w25q128fv_pageProgramContinue,
429 .pageProgramFinish = w25q128fv_pageProgramFinish,
430 .pageProgram = w25q128fv_pageProgram,
431 .flush = w25q128fv_flush,
432 .readBytes = w25q128fv_readBytes,
433 .getGeometry = w25q128fv_getGeometry,
436 static void w25q128fv_deviceInit(flashDevice_t *flashdev)
438 UNUSED(flashdev);
441 #endif