/******************************************************************************
* FileName: SpiFlash.c
* Description: SPI FLASH funcs in ROM-BIOS
* Alternate SDK ver 0.0.0 (b0)
* Author: PV`
* (c) PV` 2015
*******************************************************************************/
#include "c_types.h"
#include "bios/spiflash.h"
#include "esp8266.h"
#include "driver/spi_register.h"
// ROM:4000448C
SpiFlashOpResult Wait_SPI_Idle(SpiFlashChip *sflashchip)
{
uint32_t status;
While(HWREG(INTC_BASE, 0x0C) & BIT9);
return SPI_read_status(sflashchip, &status);
}
// ROM:4000443C
SpiFlashOpResult SPI_write_enable(SpiFlashChip *sflashchip)
{
uint32_t status = 0;
Wait_SPI_Idle();
IOREG(SPI_CMD(0)) = SPI_WREN;
while(IOREG(SPI_CMD(0)));
while((status & BIT1) == 0) SPI_read_status(sflashchip,&status);
return SPI_FLASH_RESULT_OK;
}
// ROM:40004400
SpiFlashOpResult SPI_write_status(SpiFlashChip *sflashchip, uint32_t sta)
{
Wait_SPI_Idle(sflashchip);
IOREG(SPI_RD_STATUS(0)) = sta;
IOREG(SPI_CMD(0)) = SPI_WREN;
while(IOREG(SPI_CMD(0)));
return SPI_FLASH_RESULT_OK;
}
SpiFlashOpResult SPI_read_status(SpiFlashChip *sflashchip, uint32_t *sta)
{
uint32_t status;
do {
IOREG(SPI_RD_STATUS(0)) = sta;
IOREG(SPI_CMD(0)) = SPI_READ;
while(IOREG(SPI_CMD(0)));
status = IOREG(SPI_RD_STATUS(0)) & sflashchip->status_mask;
} while(status & BIT0);
*sta = status;
return SPI_FLASH_RESULT_OK;
}
// ROM:40004644
SpiFlashOpResult spi_flash_attach(void){
SelectSpiFunction();
SPIFlashCnfig(5,4);
return SPIReadModeCnfig(5);
}
// ROM:40004B44
// ВНИМАНИЕ! имеет внутренную ошибку. Не используйте SPIEraseArea() функцию ROM-BIOS!
SpiFlashOpResult SPIEraseArea (uint32 start_addr, uint32 lenght)
{
uint32 num_sec_in_block; // *(a1 + 0xC) = SP + 0xC
uint32 var_st_1; // *(a1 + 4) = SP + 0x4
uint32 num_sec_erase; // *(a1 + 0) = SP + 0x0
uint32 var_r_13; // a13
uint32 first_sec_erase; // a12
uint32 var_r_3; // a3
uint32 var_r_0; // a0
SPIReadModeCnfig (5);
if (flashchip.chip_size >= (start_addr + lenght))
{
if ((start_addr % flashchip.sector_size) == 0)
{
if (SPIUnlock (flashchip) == 0)
{
first_sec_erase = start_addr / flashchip.sector_size; // First sector to erase
num_sec_in_block = flashchip.block_size / flashchip.sector_size; // Number of sectors in block
num_sec_erase = lenght / flashchip.sector_size; // Number of sectors to erase
// Округляем количество секторов для стирания в большую сторону.
if ((lenght % flashchip.sector_size) != 0) num_sec_erase ++; //
var_r_13 = num_sec_erase; // 9
// Стираем посекторно до адреса кратного блочному стиранию.
var_r_0 = num_sec_in_block - (first_sec_erase % num_sec_in_block); // кол-во секторов до адреса кратного блочному стиранию.
if (var_r_0 < num_sec_erase) var_r_13 = var_r_0; // запомнить кол-во секторов до стирания
for ( ; var_r_13 != 0; first_sec_erase++, var_r_13--)
if (SPIEraseSector (first_sec_erase) != 0) return 1;
// Если оставшеестя количество секторов для стирания помещается в n-блоков,
// то стираем n-блоков.
var_r_13 = num_sec_erase - var_r_13; // var_r_13 = num_sec_erase - 0
for ( ; num_sec_in_block < var_r_13; first_sec_erase += num_sec_in_block, var_r_13 -= num_sec_in_block)
if (SPIEraseBlock(first_sec_erase / num_sec_in_block) != 0) return 1;
// Стираем оставшиеся сектора в конце.
for ( ; var_r_13 != 0; first_sec_erase ++, var_r_13 --)
if (SPIEraseSector (first_sec_erase) != 0) return 1;
return SPI_FLASH_RESULT_OK;
}
}
}
return SPI_FLASH_RESULT_ERR;
}
// ROM:40004C2C
SpiFlashOpResult SPIParamCfg(uint32_t deviceId, uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, uint32_t status_mask)
{
flashchip->deviceId = deviceId;
flashchip->chip_size = chip_size;
flashchip->block_size = block_size;
flashchip->sector_size = sector_size;
flashchip->page_size = page_size;
flashchip->status_mask = status_mask;
return SPI_FLASH_RESULT_OK;
}
// ROM:400048A8
SpiFlashOpResult SPILock(void)
{
if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
return SPI_write_status(flashchip, 0x1C);
}
// ROM:40004878
SpiFlashOpResult SPIUnlock(void)
{
if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
return SPI_write_status(flashchip, 0);
}
// ROM:40004120
SpiFlashOpResult spi_erase_block(SpiFlashChip *fchip, uint32_t addr)
{
Wait_SPI_Idle(fchip);
IOREG(SPI_ADDR(0)) = addr & 0xFFFFFF;
IOREG(SPI_CMD(0)) = SPI_BE;
while(IOREG(SPI_CMD(0)));
Wait_SPI_Idle(fchip);
return SPI_FLASH_RESULT_OK;
}
// ROM:400049B4
SpiFlashOpResult SPIEraseBlock(uint32_t blocknum)
{
SpiFlashChip *fchip = flashchip;
if(blocknum > fchip->chip_size / fchip->block_size) return SPI_FLASH_RESULT_ERR;
if(SPI_write_enable(fchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
if(spi_erase_block(fchip, fchip->block_size * blocknum) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
return SPI_FLASH_RESULT_OK;
}
// ROM:400040C0
SpiFlashOpResult spi_erase_sector(SpiFlashChip *fchip, uint32_t addr)
{
if(addr*0xFFF) return SPI_FLASH_RESULT_ERR;
Wait_SPI_Idle(fchip);
IOREG(SPI_ADDR(0)) = addr & 0xFFFFFF;
IOREG(SPI_CMD(0)) = SPI_SE;
while(IOREG(SPI_CMD(0)));
Wait_SPI_Idle(fchip);
return SPI_FLASH_RESULT_OK;
}
// ROM:40004A00
SpiFlashOpResult SPIEraseSector(uint32_t sectornum)
{
SpiFlashChip *fchip = flashchip;
if(sectornum > fchip->chip_size / fchip->sector_size) return SPI_FLASH_RESULT_ERR;
if(SPI_write_enable(fchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
if(spi_erase_sector(fchip, fchip->sector_size * sectornum) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
return SPI_FLASH_RESULT_OK;
}
// ROM:40004080
SpiFlashOpResult spi_erase_chip(SpiFlashChip *fchip)
{
Wait_SPI_Idle(fchip);
IOREG(SPI_CMD(0)) = SPI_CE;
while(IOREG(SPI_CMD(0)));
Wait_SPI_Idle(fchip);
return SPI_FLASH_RESULT_OK;
}
// ROM:40004984
SpiFlashOpResult SPIEraseChip(void)
{
if(SPI_write_enable(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
if(spi_erase_chip(flashchip) != SPI_FLASH_RESULT_OK) return SPI_FLASH_RESULT_ERR;
return SPI_FLASH_RESULT_OK;
}
// ROM:40004568
void SPIFlashCnfig(uint32_t spi_interface, uint32_t spi_freg)
{
// Flash QIO80:
// SPI_CTRL = 0x16ab000 - QIO_MODE | TWO_BYTE_STATUS_EN | WP_REG | SHARE_BUS | ENABLE_AHB | RESANDRES | FASTRD_MODE | BIT12
// IOMUX_BASE = 0x305
// Flash QIO40:
// SPI_CTRL = 0x16aa101
// IOMUX_BASE = 0x205
uint32 a6 = 0; // spi_interface > 4
uint32 a2;
HWREG(SPI0_BASE,0x1C) |= 4;
if(spi_interface == 0) a6 = 1<<24; // SPI_QIO_MODE
else if(spi_interface == 1) a6 = 1<<20; // SPI_QOUT_MODE
else if(spi_interface == 2) a6 = 1<<23; // SPI_DIO_MODE
else if(spi_interface == 3) a6 = 1<<14; // SPI_DOUT_MODE
else if(spi_interface == 4) a6 = 1<<13; // SPI_FASTRD_MODE
if(spi_freg < 2) {
a2 = 0x100;
HWREG(SPI0_BASE,0x08) |= 0x1000; // ???
HWREG(IOMUX_BASE,0) |= a2;
}
else {
a2 = (((spi_freg - 1) << 8) + spi_freg + (((spi_freg >> 1) - 1) << 4) - 1);
HWREG(SPI0_BASE,0x08) &= 0xFFFFEFFF;
HWREG(IOMUX_BASE,0) &= 0xEFF;
}
a2 |= a6;
a2 |= 0x288000; // SPI_RESANDRES | SPI_SHARE_BUS | SPI_WP_REG
HWREG(SPI0_BASE,0x08) |= a2;
HWREG(SPI0_BASE,0) = 0x100000;
while(HWREG(SPI0_BASE,0) != 0);
// [0x60000208] = 0x016aa101;
// 0x00288000
// 0x00411000 // BIT12 BIT16 BIT22
}
// ROM:400042AC
SpiFlashOpResult spi_flash_read(SpiFlashChip *fchip, uint32_t faddr, uint32_t *dst, size_t size)
{
if(faddr + size > fchip->chip_size) return SPI_FLASH_RESULT_ERR;
Wait_SPI_Idle(fchip);
while(size >= 1) {
if(size < 32) {
IOREG(SPI_ADDR(0)) = faddr | (size << 24);
IOREG(SPI_CMD(0)) = SPI_READ;
while(IOREG(SPI_CMD(0)));
}
else {
IOREG(SPI_ADDR(0)) = faddr | BIT29; // 0x20000000 = 32 << 24
IOREG(SPI_CMD(0)) = SPI_READ;
while(IOREG(SPI_CMD(0)));
}
// move dst, SPI0_W0+...
// size -= read
}
return SPI_FLASH_RESULT_OK;
}
// ROM:40004B1C
SpiFlashOpResult SPIRead(uint32_t faddr, uint32_t *dst, size_t size)
{
return spi_flash_read(flashchip, faddr, dst, size);
}