2021-06-26 15:24:07 +02:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2019-10-05 19:00:10 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2020-08-23 17:14:21 +02:00
|
|
|
#include <string.h>
|
2019-10-05 19:00:10 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
2021-10-10 18:26:04 +02:00
|
|
|
#include <cmath>
|
2019-10-05 19:00:10 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
#include "progressBar.hpp"
|
2021-07-11 11:32:10 +02:00
|
|
|
#include "display.hpp"
|
2019-10-05 19:00:10 +02:00
|
|
|
#include "spiFlash.hpp"
|
2021-10-10 18:26:04 +02:00
|
|
|
#include "spiFlashdb.hpp"
|
2020-04-21 09:00:57 +02:00
|
|
|
#include "spiInterface.hpp"
|
2019-10-05 19:00:10 +02:00
|
|
|
|
|
|
|
|
/* read/write status register : 0B addr + 0 dummy */
|
2020-04-21 09:00:57 +02:00
|
|
|
#define FLASH_WRSR 0x01
|
|
|
|
|
#define FLASH_RDSR 0x05
|
2019-10-05 19:00:10 +02:00
|
|
|
# define FLASH_RDSR_WIP (0x01)
|
|
|
|
|
# define FLASH_RDSR_WEL (0x02)
|
|
|
|
|
/* flash program */
|
|
|
|
|
#define FLASH_PP 0x02
|
|
|
|
|
/* write [en|dis]able : 0B addr + 0 dummy */
|
2020-04-21 09:00:57 +02:00
|
|
|
#define FLASH_WRDIS 0x04
|
|
|
|
|
#define FLASH_WREN 0x06
|
2019-10-05 19:00:10 +02:00
|
|
|
/* Read OTP : 3 B addr + 8 clk cycle*/
|
2020-04-21 09:00:57 +02:00
|
|
|
#define FLASH_ROTP 0x4B
|
|
|
|
|
#define FLASH_POWER_UP 0xAB
|
|
|
|
|
#define FLASH_POWER_DOWN 0xB9
|
2019-10-05 19:00:10 +02:00
|
|
|
/* read/write non volatile register: 0B addr + 0 dummy */
|
|
|
|
|
#define FLASH_RDNVCR 0xB5
|
2020-08-23 17:14:21 +02:00
|
|
|
#define FLASH_WRNVCR 0xB1
|
|
|
|
|
/* read/write volatile register */
|
|
|
|
|
#define FLASH_RDVCR 0x85
|
|
|
|
|
#define FLASH_WRVCR 0x81
|
2019-10-05 19:00:10 +02:00
|
|
|
/* bulk erase */
|
|
|
|
|
#define FLASH_BE 0xC7
|
|
|
|
|
/* sector (64kb) erase */
|
|
|
|
|
#define FLASH_SE 0xD8
|
|
|
|
|
/* read/write lock register : 3B addr + 0 dummy */
|
|
|
|
|
#define FLASH_WRLR 0xE5
|
|
|
|
|
#define FLASH_RDLR 0xE8
|
|
|
|
|
/* read/clear flag status register : 0B addr + 0 dummy */
|
|
|
|
|
#define FLASH_CLFSR 0x50
|
|
|
|
|
#define FLASH_RFSR 0x70
|
|
|
|
|
/* */
|
|
|
|
|
#define FLASH_WRVECR 0x61
|
|
|
|
|
#define FLASH_RDVECR 0x65
|
|
|
|
|
|
2021-05-05 06:59:02 +02:00
|
|
|
/* microchip SST26VF032B / SST26VF032BA */
|
|
|
|
|
/* Read Block Protection Register */
|
|
|
|
|
#define FLASH_RBPR 0x72
|
|
|
|
|
/* Global Block Protection unlock */
|
|
|
|
|
#define FLASH_ULBPR 0x98
|
|
|
|
|
|
2021-10-10 18:26:04 +02:00
|
|
|
SPIFlash::SPIFlash(SPIInterface *spi, int8_t verbose):_spi(spi),
|
|
|
|
|
_verbose(verbose), _jedec_id(0), _flash_model(NULL)
|
2019-10-05 19:00:10 +02:00
|
|
|
{
|
2021-10-10 18:26:04 +02:00
|
|
|
read_id();
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SPIFlash::bulk_erase()
|
|
|
|
|
{
|
|
|
|
|
if (write_enable() == -1)
|
|
|
|
|
return -1;
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_BE, NULL, NULL, 0);
|
|
|
|
|
return _spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WIP, 0x00, 100000, true);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SPIFlash::sector_erase(int addr)
|
|
|
|
|
{
|
2020-08-23 17:14:21 +02:00
|
|
|
uint8_t tx[4];
|
|
|
|
|
tx[0] = (uint8_t)(FLASH_SE );
|
|
|
|
|
tx[1] = (uint8_t)(0xff & (addr >> 16));
|
|
|
|
|
tx[2] = (uint8_t)(0xff & (addr >> 8));
|
|
|
|
|
tx[3] = (uint8_t)(0xff & (addr ));
|
|
|
|
|
_spi->spi_put(tx, NULL, 4);
|
2019-10-05 19:00:10 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SPIFlash::sectors_erase(int base_addr, int size)
|
|
|
|
|
{
|
2021-01-30 07:57:49 +01:00
|
|
|
int ret = 0;
|
2019-10-05 19:00:10 +02:00
|
|
|
int start_addr = base_addr;
|
2020-08-23 17:14:21 +02:00
|
|
|
int end_addr = (base_addr + size + 0xffff) & ~0xffff;
|
2021-01-30 07:57:49 +01:00
|
|
|
ProgressBar progress("Erasing", end_addr, 50, _verbose < 0);
|
|
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
for (int addr = start_addr; addr < end_addr; addr += 0x10000) {
|
2021-01-30 07:57:49 +01:00
|
|
|
if (write_enable() == -1) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (sector_erase(addr) == -1) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (_spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WIP, 0x00, 100000, false) == -1) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-10-05 19:00:10 +02:00
|
|
|
progress.display(addr);
|
|
|
|
|
}
|
2021-01-30 07:57:49 +01:00
|
|
|
if (ret == 0)
|
|
|
|
|
progress.done();
|
|
|
|
|
else
|
|
|
|
|
progress.fail();
|
|
|
|
|
|
|
|
|
|
return ret;
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-15 08:22:29 +01:00
|
|
|
int SPIFlash::write_page(int addr, uint8_t *data, int len)
|
2019-10-05 19:00:10 +02:00
|
|
|
{
|
2020-03-15 08:22:29 +01:00
|
|
|
uint8_t tx[len+3];
|
|
|
|
|
tx[0] = (uint8_t)(0xff & (addr >> 16));
|
2020-08-23 17:14:21 +02:00
|
|
|
tx[1] = (uint8_t)(0xff & (addr >> 8));
|
|
|
|
|
tx[2] = (uint8_t)(0xff & (addr ));
|
|
|
|
|
|
|
|
|
|
memcpy(tx+3, data, len);
|
|
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
if (write_enable() == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_PP, tx, NULL, len+3);
|
|
|
|
|
return _spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WIP, 0x00, 1000);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-08-23 17:14:21 +02:00
|
|
|
int SPIFlash::read(int base_addr, uint8_t *data, int len)
|
|
|
|
|
{
|
|
|
|
|
uint8_t tx[len+3];
|
|
|
|
|
uint8_t rx[len+3];
|
|
|
|
|
tx[0] = (uint8_t)(0xff & (base_addr >> 16));
|
|
|
|
|
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 (ret == 0)
|
|
|
|
|
memcpy(data, rx+3, len);
|
|
|
|
|
else
|
|
|
|
|
printf("error\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 11:32:10 +02:00
|
|
|
bool SPIFlash::dump(const std::string &filename, const int &base_addr,
|
|
|
|
|
const int &len, int rd_burst)
|
|
|
|
|
{
|
|
|
|
|
if (rd_burst == 0)
|
|
|
|
|
rd_burst = len;
|
|
|
|
|
|
2021-10-02 19:25:04 +02:00
|
|
|
/* segfault with buffer > 1M */
|
|
|
|
|
if (rd_burst > 0x100000)
|
|
|
|
|
rd_burst = 0x100000;
|
|
|
|
|
|
2021-07-11 11:32:10 +02:00
|
|
|
std::string data;
|
|
|
|
|
data.resize(rd_burst);
|
|
|
|
|
|
|
|
|
|
printInfo("dump flash (May take time)");
|
|
|
|
|
|
|
|
|
|
printInfo("Open dump file ", false);
|
|
|
|
|
FILE *fd = fopen(filename.c_str(), "wb");
|
|
|
|
|
if (!fd) {
|
|
|
|
|
printError("FAIL");
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProgressBar progress("Read flash ", len, 50, false);
|
|
|
|
|
for (int i = 0; i < len; i += rd_burst) {
|
|
|
|
|
if (rd_burst + i > len)
|
|
|
|
|
rd_burst = len - i;
|
|
|
|
|
if (0 != read(base_addr + i, (uint8_t*)&data[0], rd_burst)) {
|
|
|
|
|
progress.fail();
|
|
|
|
|
printError("Failed to read flash");
|
|
|
|
|
fclose(fd);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
fwrite(data.c_str(), sizeof(uint8_t), rd_burst, fd);
|
|
|
|
|
progress.display(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progress.done();
|
|
|
|
|
|
|
|
|
|
fclose(fd);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
int SPIFlash::erase_and_prog(int base_addr, uint8_t *data, int len)
|
|
|
|
|
{
|
2021-05-05 06:59:02 +02:00
|
|
|
if (_jedec_id == 0)
|
|
|
|
|
read_id();
|
|
|
|
|
|
2020-04-21 19:25:35 +02:00
|
|
|
/* check Block Protect Bits */
|
2021-05-05 06:59:02 +02:00
|
|
|
if (_jedec_id == 0xbf2642bf) { // microchip SST26VF032B
|
|
|
|
|
if (!global_unlock())
|
2020-04-21 19:25:35 +02:00
|
|
|
return -1;
|
2021-05-05 06:59:02 +02:00
|
|
|
} else {
|
|
|
|
|
uint8_t status = read_status_reg();
|
|
|
|
|
if ((status & 0x1c) !=0) {
|
|
|
|
|
if (write_enable() != 0)
|
|
|
|
|
return -1;
|
|
|
|
|
if (disable_protection() != 0)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2020-04-21 19:25:35 +02:00
|
|
|
}
|
2021-05-05 06:59:02 +02:00
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
ProgressBar progress("Writing", len, 50, _verbose < 0);
|
2020-08-23 17:14:21 +02:00
|
|
|
if (sectors_erase(base_addr, len) == -1)
|
2019-10-05 19:00:10 +02:00
|
|
|
return -1;
|
2020-04-21 09:00:57 +02:00
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
uint8_t *ptr = data;
|
|
|
|
|
int size = 0;
|
2020-08-23 17:14:21 +02:00
|
|
|
for (int addr = 0; addr < len; addr += size, ptr+=size) {
|
2019-10-05 19:00:10 +02:00
|
|
|
size = (addr + 256 > len)?(len-addr) : 256;
|
2020-08-23 17:14:21 +02:00
|
|
|
if (write_page(base_addr + addr, ptr, size) == -1)
|
2019-10-05 19:00:10 +02:00
|
|
|
return -1;
|
|
|
|
|
progress.display(addr);
|
|
|
|
|
}
|
|
|
|
|
progress.done();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 11:32:10 +02:00
|
|
|
bool SPIFlash::verify(const int &base_addr, const uint8_t *data,
|
|
|
|
|
const int &len, int rd_burst)
|
|
|
|
|
{
|
|
|
|
|
if (rd_burst == 0)
|
|
|
|
|
rd_burst = len;
|
|
|
|
|
|
|
|
|
|
printInfo("Verifying write (May take time)");
|
|
|
|
|
|
|
|
|
|
std::string verify_data;
|
|
|
|
|
verify_data.resize(rd_burst);
|
|
|
|
|
|
|
|
|
|
ProgressBar progress("Read flash ", len, 50, false);
|
|
|
|
|
for (int i = 0; i < len; i += rd_burst) {
|
|
|
|
|
if (rd_burst + i > len)
|
|
|
|
|
rd_burst = len - i;
|
|
|
|
|
if (0 != read(base_addr + i, (uint8_t*)&verify_data[0], rd_burst)) {
|
|
|
|
|
progress.fail();
|
|
|
|
|
printError("Failed to read flash");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int ii = 0; ii < rd_burst; ii++) {
|
|
|
|
|
if ((uint8_t)verify_data[ii] != data[i+ii]) {
|
|
|
|
|
progress.fail();
|
|
|
|
|
printError("Verification failed at " +
|
|
|
|
|
std::to_string(base_addr + i + ii));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
progress.display(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
progress.done();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
void SPIFlash::reset()
|
|
|
|
|
{
|
2020-08-23 17:14:21 +02:00
|
|
|
uint8_t data[8];
|
|
|
|
|
memset(data, 0xff, 8);
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(0xff, data, NULL, 8);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SPIFlash::read_id()
|
|
|
|
|
{
|
|
|
|
|
int len = 4;
|
|
|
|
|
uint8_t rx[512];
|
2020-04-21 09:02:48 +02:00
|
|
|
bool has_edid = false;
|
2019-10-05 19:00:10 +02:00
|
|
|
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(0x9F, NULL, rx, 4);
|
2021-05-05 06:25:00 +02:00
|
|
|
_jedec_id = 0;
|
2019-10-05 19:00:10 +02:00
|
|
|
for (int i=0; i < 4; i++) {
|
2021-05-05 06:25:00 +02:00
|
|
|
_jedec_id = _jedec_id << 8;
|
|
|
|
|
_jedec_id |= (0x00ff & (int)rx[i]);
|
2021-01-30 07:57:49 +01:00
|
|
|
if (_verbose > 0)
|
2019-11-21 09:19:48 +01:00
|
|
|
printf("%x ", rx[i]);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
if (_verbose > 0)
|
2021-05-05 06:25:00 +02:00
|
|
|
printf("read %x\n", _jedec_id);
|
2021-10-10 18:26:04 +02:00
|
|
|
auto t = flash_list.find(_jedec_id >> 8);
|
|
|
|
|
if (t != flash_list.end()) {
|
|
|
|
|
_flash_model = &(*t).second;
|
|
|
|
|
char content[256];
|
|
|
|
|
snprintf(content, 256, "Detected: %s %s %u sectors size: %uMb",
|
|
|
|
|
_flash_model->manufacturer.c_str(), _flash_model->model.c_str(),
|
|
|
|
|
_flash_model->nr_sector, _flash_model->nr_sector * 0x80000 / 1048576);
|
|
|
|
|
printInfo(content);
|
|
|
|
|
} else {
|
|
|
|
|
/* read extented */
|
|
|
|
|
if ((_jedec_id & 0xff) != 0) {
|
|
|
|
|
has_edid = true;
|
|
|
|
|
len += (_jedec_id & 0x0ff);
|
|
|
|
|
_spi->spi_put(0x9F, NULL, rx, len);
|
|
|
|
|
}
|
2019-10-05 19:00:10 +02:00
|
|
|
|
2021-10-10 18:26:04 +02:00
|
|
|
/* must be 0x20BA1810 ... */
|
|
|
|
|
|
|
|
|
|
printf("Detail: \n");
|
|
|
|
|
printf("Jedec ID : %02x\n", rx[0]);
|
|
|
|
|
printf("memory type : %02x\n", rx[1]);
|
|
|
|
|
printf("memory capacity : %02x\n", rx[2]);
|
|
|
|
|
if (has_edid) {
|
|
|
|
|
printf("EDID + CFD length : %02x\n", rx[3]);
|
|
|
|
|
printf("EDID : %02x%02x\n", rx[5], rx[4]);
|
|
|
|
|
printf("CFD : ");
|
|
|
|
|
if (_verbose > 0) {
|
|
|
|
|
for (int i = 6; i < len; i++)
|
|
|
|
|
printf("%02x ", rx[i]);
|
|
|
|
|
printf("\n");
|
|
|
|
|
} else {
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
2020-04-21 09:02:48 +02:00
|
|
|
}
|
2019-11-21 09:19:48 +01:00
|
|
|
}
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-21 09:19:48 +01:00
|
|
|
uint8_t SPIFlash::read_status_reg()
|
2019-10-05 19:00:10 +02:00
|
|
|
{
|
|
|
|
|
uint8_t rx;
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_RDSR, NULL, &rx, 1);
|
2021-01-30 07:57:49 +01:00
|
|
|
if (_verbose > 0) {
|
2019-10-05 19:00:10 +02:00
|
|
|
printf("RDSR : %02x\n", rx);
|
|
|
|
|
printf("WIP : %d\n", rx&0x01);
|
|
|
|
|
printf("WEL : %d\n", (rx>>1)&0x01);
|
|
|
|
|
printf("BP : %x\n", (((rx>>6)&0x01)<<3) | ((rx >> 2) & 0x07));
|
|
|
|
|
printf("TB : %d\n", (((rx>>5)&0x01)));
|
|
|
|
|
printf("SRWD : %d\n", (((rx>>7)&0x01)));
|
|
|
|
|
}
|
|
|
|
|
return rx;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-23 17:14:21 +02:00
|
|
|
uint16_t SPIFlash::readNonVolatileCfgReg()
|
|
|
|
|
{
|
|
|
|
|
uint8_t rx[2];
|
|
|
|
|
_spi->spi_put(FLASH_RDNVCR, NULL, rx, 2);
|
2021-01-30 07:57:49 +01:00
|
|
|
if (_verbose > 0)
|
2020-08-23 17:14:21 +02:00
|
|
|
printf("Non Volatile %x %x\n", rx[0], rx[1]);
|
|
|
|
|
return (rx[1] << 8) | rx[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t SPIFlash::readVolatileCfgReg()
|
|
|
|
|
{
|
|
|
|
|
uint8_t rx[2];
|
|
|
|
|
_spi->spi_put(FLASH_RDVCR, NULL, rx, 2);
|
2021-01-30 07:57:49 +01:00
|
|
|
if (_verbose > 0)
|
2020-08-23 17:14:21 +02:00
|
|
|
printf("Volatile %x %x\n", rx[0], rx[1]);
|
|
|
|
|
return (rx[1] << 8) | rx[0];
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-05 19:00:10 +02:00
|
|
|
void SPIFlash::power_up()
|
|
|
|
|
{
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_POWER_UP, NULL, NULL, 0);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SPIFlash::power_down()
|
|
|
|
|
{
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_POWER_DOWN, NULL, NULL, 0);
|
2019-10-05 19:00:10 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-21 09:19:48 +01:00
|
|
|
int SPIFlash::write_enable()
|
2019-10-05 19:00:10 +02:00
|
|
|
{
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_WREN, NULL, NULL, 0);
|
2019-10-05 19:00:10 +02:00
|
|
|
/* wait WEL */
|
2020-04-21 09:00:57 +02:00
|
|
|
if (_spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WEL, FLASH_RDSR_WEL, 1000)) {
|
2019-10-05 19:00:10 +02:00
|
|
|
printf("write en: Error\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SPIFlash::write_disable()
|
|
|
|
|
{
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_WRDIS, NULL, NULL, 0);
|
2019-10-05 19:00:10 +02:00
|
|
|
/* wait ! WEL */
|
2020-04-21 09:00:57 +02:00
|
|
|
int ret = _spi->spi_wait(FLASH_RDSR, FLASH_RDSR_WEL, 0x00, 1000);
|
2019-10-05 19:00:10 +02:00
|
|
|
if (ret == -1)
|
|
|
|
|
printf("write disable: Error\n");
|
2021-01-30 07:57:49 +01:00
|
|
|
else if (_verbose > 0)
|
2019-10-05 19:00:10 +02:00
|
|
|
printf("write disable: Success\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SPIFlash::disable_protection()
|
|
|
|
|
{
|
|
|
|
|
uint8_t data = 0x00;
|
2020-04-21 09:00:57 +02:00
|
|
|
_spi->spi_put(FLASH_WRSR, &data, NULL, 1);
|
|
|
|
|
if (_spi->spi_wait(FLASH_RDSR, 0xff, 0, 1000) < 0)
|
2019-10-05 19:00:10 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* read status */
|
|
|
|
|
if (read_status_reg() != 0) {
|
|
|
|
|
std::cout << "disable protection failed" << std::endl;
|
|
|
|
|
return -1;
|
|
|
|
|
} else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-05-05 06:59:02 +02:00
|
|
|
|
2021-10-10 18:26:04 +02:00
|
|
|
/* convert bp area (status register) to len in byte */
|
|
|
|
|
uint32_t SPIFlash::bp_to_len(uint8_t bp)
|
|
|
|
|
{
|
2021-10-10 18:27:41 +02:00
|
|
|
/* 0 -> no block protected */
|
2021-10-10 18:26:04 +02:00
|
|
|
if (bp == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* reconstruct code based on each BPx bit */
|
|
|
|
|
uint8_t tmp = 0;
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
|
if ((bp & _flash_model->bp_offset[i]))
|
|
|
|
|
tmp |= (1 << i);
|
2021-10-10 18:27:41 +02:00
|
|
|
/* bp code is 2^(bp-1) blocks */
|
2021-10-10 18:26:04 +02:00
|
|
|
uint16_t nr_sectors = (1 << (tmp-1));
|
|
|
|
|
|
|
|
|
|
return nr_sectors * 0x10000;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-10 18:27:41 +02:00
|
|
|
/* convert len (in byte) to bp (block protection) */
|
2021-10-10 18:26:04 +02:00
|
|
|
uint8_t SPIFlash::len_to_bp(uint32_t len)
|
|
|
|
|
{
|
2021-10-10 18:27:41 +02:00
|
|
|
/* 0 -> no block to protect */
|
2021-10-10 18:26:04 +02:00
|
|
|
if (len == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* round and divide by sector size */
|
|
|
|
|
len = ((len + 0xffff) & ~0xffff) / 0x10000;
|
|
|
|
|
|
|
|
|
|
/* convert size to basic BP code */
|
|
|
|
|
uint8_t bp = 1 + static_cast<int>(ceil(log2(len)));
|
|
|
|
|
/* reconstruct code based on each BPx bit */
|
|
|
|
|
uint8_t tmp = 0;
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
|
if (bp >> i)
|
|
|
|
|
tmp |= _flash_model->bp_offset[i];
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 06:59:02 +02:00
|
|
|
/* microchip SST26VF032B has a dedicated register
|
|
|
|
|
* to read sectors (un)lock status and another one to unlock
|
|
|
|
|
* sectors
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool SPIFlash::global_unlock()
|
|
|
|
|
{
|
|
|
|
|
if (write_enable() != 0)
|
|
|
|
|
return false;
|
|
|
|
|
_spi->spi_put(FLASH_ULBPR, NULL, NULL, 0);
|
|
|
|
|
|
|
|
|
|
if (_spi->spi_wait(FLASH_RDSR, 0xff, 0, 1000) < 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* check if all sectors are unlocked */
|
|
|
|
|
uint8_t rx2[10];
|
|
|
|
|
_spi->spi_put(FLASH_RBPR, NULL, rx2, 10);
|
|
|
|
|
printf("Non Volatile\n");
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
|
if (rx2[i] != 0)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|