Add support for 4-byte QSPI flash addressing (#295)

* Add support for 4-byte QSPI flash addressing

* Avoid code duplication
This commit is contained in:
Ricardo Barbedo 2023-01-23 15:18:46 +01:00 committed by GitHub
parent 0ac85d1c9f
commit 43e6c0c867
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 99 additions and 32 deletions

View File

@ -3,6 +3,7 @@
* Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com> * Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*/ */
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -24,11 +25,19 @@
# define FLASH_RDSR_WEL (0x02) # define FLASH_RDSR_WEL (0x02)
/* flash program */ /* flash program */
#define FLASH_PP 0x02 #define FLASH_PP 0x02
/* flash program with 4-byte address */
#define FLASH_4PP 0x12
/* read memory */
#define FLASH_READ 0x03
/* read memory with 4-byte address */
#define FLASH_4READ 0x13
/* write [en|dis]able : 0B addr + 0 dummy */ /* write [en|dis]able : 0B addr + 0 dummy */
#define FLASH_WRDIS 0x04 #define FLASH_WRDIS 0x04
#define FLASH_WREN 0x06 #define FLASH_WREN 0x06
/* sector (4Kb) erase */ /* sector (4Kb) erase */
#define FLASH_SE 0x20 #define FLASH_SE 0x20
/* sector (4k) erase with 4-byte address*/
#define FLASH_4SE 0x21
/* read configuration register */ /* read configuration register */
#define FLASH_RDCR 0x35 #define FLASH_RDCR 0x35
/* write function register (at least ISSI) */ /* write function register (at least ISSI) */
@ -39,6 +48,8 @@
#define FLASH_ROTP 0x4B #define FLASH_ROTP 0x4B
/* block (32Kb) erase */ /* block (32Kb) erase */
#define FLASH_BE32 0x52 #define FLASH_BE32 0x52
/* block (32Kb) erase with 4-byte address */
#define FLASH_4BE32 0x5C
#define FLASH_POWER_UP 0xAB #define FLASH_POWER_UP 0xAB
#define FLASH_POWER_DOWN 0xB9 #define FLASH_POWER_DOWN 0xB9
/* read/write non volatile register: 0B addr + 0 dummy */ /* read/write non volatile register: 0B addr + 0 dummy */
@ -49,8 +60,10 @@
#define FLASH_WRVCR 0x81 #define FLASH_WRVCR 0x81
/* bulk erase */ /* bulk erase */
#define FLASH_CE 0xC7 #define FLASH_CE 0xC7
/* block (64kb) erase */ /* block (64Kb) erase */
#define FLASH_BE64 0xD8 #define FLASH_BE64 0xD8
/* block (64Kb) erase with 4-byte address */
#define FLASH_4BE64 0xDC
/* read/write lock register : 3B addr + 0 dummy */ /* read/write lock register : 3B addr + 0 dummy */
#define FLASH_WRLR 0xE5 #define FLASH_WRLR 0xE5
#define FLASH_RDLR 0xE8 #define FLASH_RDLR 0xE8
@ -107,35 +120,59 @@ int SPIFlash::bulk_erase()
/* sector -> subsector for micron */ /* sector -> subsector for micron */
int SPIFlash::sector_erase(int addr) int SPIFlash::sector_erase(int addr)
{ {
uint8_t tx[4]; uint8_t tx[5];
tx[0] = (uint8_t)(FLASH_SE ); uint32_t len = 0;
tx[1] = (uint8_t)(0xff & (addr >> 16));
tx[2] = (uint8_t)(0xff & (addr >> 8)); uint8_t cmd = (addr <= 0xffffff) ? FLASH_SE : FLASH_4SE;
tx[3] = (uint8_t)(0xff & (addr ));
_spi->spi_put(tx, NULL, 4); tx[len++] = cmd;
if (cmd == FLASH_4SE)
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 24));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 16));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 8));
tx[len++] = static_cast<uint8_t>(0xff & (addr ));
_spi->spi_put(tx, NULL, len);
return 0; return 0;
} }
int SPIFlash::block32_erase(int addr) int SPIFlash::block32_erase(int addr)
{ {
uint8_t tx[4] = { uint8_t tx[5];
static_cast<uint8_t>(FLASH_BE32 ), uint32_t len = 0;
static_cast<uint8_t>(0xff & (addr >> 16)),
static_cast<uint8_t>(0xff & (addr >> 8)), uint8_t cmd = (addr <= 0xffffff) ? FLASH_BE32 : FLASH_4BE32;
static_cast<uint8_t>(0xff & (addr ))};
_spi->spi_put(tx, NULL, 4); tx[len++] = cmd;
if (cmd == FLASH_4BE32)
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 24));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 16));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 8));
tx[len++] = static_cast<uint8_t>(0xff & (addr ));
_spi->spi_put(tx, NULL, len);
return 0; return 0;
} }
/* block64 -> sector for micron */ /* block64 -> sector for micron */
int SPIFlash::block64_erase(int addr) int SPIFlash::block64_erase(int addr)
{ {
uint8_t tx[4] = { uint8_t tx[5];
static_cast<uint8_t>(FLASH_BE64 ), uint32_t len = 0;
static_cast<uint8_t>(0xff & (addr >> 16)),
static_cast<uint8_t>(0xff & (addr >> 8)), uint8_t cmd = (addr <= 0xffffff) ? FLASH_BE64 : FLASH_4BE64;
static_cast<uint8_t>(0xff & (addr ))};
_spi->spi_put(tx, NULL, 4); tx[len++] = cmd;
if (cmd == FLASH_4BE64)
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 24));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 16));
tx[len++] = static_cast<uint8_t>(0xff & (addr >> 8));
tx[len++] = static_cast<uint8_t>(0xff & (addr ));
_spi->spi_put(tx, NULL, len);
return 0; return 0;
} }
@ -195,31 +232,61 @@ int SPIFlash::sectors_erase(int base_addr, int size)
int SPIFlash::write_page(int addr, uint8_t *data, int len) int SPIFlash::write_page(int addr, uint8_t *data, int len)
{ {
uint8_t tx[len+3]; uint32_t addr_len;
tx[0] = (uint8_t)(0xff & (addr >> 16)); uint8_t write_cmd;
tx[1] = (uint8_t)(0xff & (addr >> 8)); uint32_t i = 0;
tx[2] = (uint8_t)(0xff & (addr ));
memcpy(tx+3, data, len); if (addr <= 0xffffff) {
addr_len = 3;
write_cmd = FLASH_PP;
} else {
addr_len = 4;
write_cmd = FLASH_4PP;
}
uint8_t tx[len+addr_len];
if (write_cmd == FLASH_4PP)
tx[i++] = (uint8_t)(0xff & (addr >> 24));
tx[i++] = (uint8_t)(0xff & (addr >> 16));
tx[i++] = (uint8_t)(0xff & (addr >> 8));
tx[i++] = (uint8_t)(0xff & (addr ));
memcpy(tx+addr_len, data, len);
if (write_enable() == -1) if (write_enable() == -1)
return -1; return -1;
_spi->spi_put(FLASH_PP, tx, NULL, len+3); _spi->spi_put(write_cmd, tx, NULL, len+addr_len);
return _spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WIP, 0x00, 1000); return _spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WIP, 0x00, 1000);
} }
int SPIFlash::read(int base_addr, uint8_t *data, int len) int SPIFlash::read(int base_addr, uint8_t *data, int len)
{ {
uint8_t tx[len+3]; uint32_t addr_len;
uint8_t rx[len+3]; uint8_t read_cmd;
tx[0] = (uint8_t)(0xff & (base_addr >> 16)); uint32_t i = 0;
tx[1] = (uint8_t)(0xff & (base_addr >> 8));
tx[2] = (uint8_t)(0xff & (base_addr ));
int ret = _spi->spi_put(0x03, tx, rx, len+3); if (base_addr <= 0xffffff) {
addr_len = 3;
read_cmd = FLASH_READ;
} else {
addr_len = 4;
read_cmd = FLASH_4READ;
}
uint8_t tx[len+addr_len];
uint8_t rx[len+addr_len];
if (read_cmd == FLASH_4READ)
tx[i++] = (uint8_t)(0xff & (base_addr >> 24));
tx[i++] = (uint8_t)(0xff & (base_addr >> 16));
tx[i++] = (uint8_t)(0xff & (base_addr >> 8));
tx[i++] = (uint8_t)(0xff & (base_addr ));
int ret = _spi->spi_put(read_cmd, tx, rx, len+addr_len);
if (ret == 0) if (ret == 0)
memcpy(data, rx+3, len); memcpy(data, rx+addr_len, len);
else else
printf("error\n"); printf("error\n");
return ret; return ret;