Flash access library for GR-Boards.
FlashAccess.cpp
- Committer:
- dkato
- Date:
- 2017-11-28
- Revision:
- 1:652a093cf264
- Parent:
- 0:5a74eeaefb5d
File content as of revision 1:652a093cf264:
/*******************************************************************************
* DISCLAIMER
* This software is supplied by Renesas Electronics Corporation and is only
* intended for use with Renesas products. No other uses are authorized. This
* software is owned by Renesas Electronics Corporation and is protected under
* all applicable laws, including copyright laws.
* THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
* THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
* LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
* TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
* ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
* FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
* ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* Renesas reserves the right, without notice, to make changes to this software
* and to discontinue the availability of this software. By using this software,
* you agree to the additional terms and conditions found by accessing the
* following link:
* http://www.renesas.com/disclaimer
*
* Copyright (C) 2017 Renesas Electronics Corporation. All rights reserved.
*******************************************************************************/
#include "mbed.h"
#include "FlashAccess.h"
/* ---- serial flash command ---- */
#define SFLASHCMD_SECTOR_ERASE (0x20u) /* SE 3-byte address(1bit) */
#define SFLASHCMD_PAGE_PROGRAM (0x02u) /* PP 3-byte address(1bit), data(1bit) */
#define SFLASHCMD_READ (0x03u) /* READ 3-byte address(1bit), data(1bit) */
#define SFLASHCMD_READ_STATUS_REG (0x05u) /* RDSR data(1bit) */
#define SFLASHCMD_WRITE_ENABLE (0x06u) /* WREN */
/* ---- serial flash register definitions ---- */
#define STREG_BUSY_BIT (0x01u) /* SR.[0]BUSY Erase/Write In Progress (RO) */
/* Definition of the base address for the MMU translation table */
#if defined(__CC_ARM) || defined(__GNUC__)
extern uint32_t Image$$TTB$$ZI$$Base;
#define TTB ((uint32_t)&Image$$TTB$$ZI$$Base) /* using linker symbol */
#elif defined(__ICCARM__)
#pragma section="TTB"
#define TTB ((uint32_t)__section_begin("TTB"))
#endif
/** public **/
FlashAccess::FlashAccess() : SPIBSC(&SPIBSC0) {
}
bool FlashAccess::SectorErase(uint32_t addr) {
bool ret;
#if defined (__ICCARM__)
int was_masked = __disable_irq_iar();
#else
int was_masked = __disable_irq();
#endif
spi_mode();
ret = _SectorErase(addr);
ex_mode();
if (0 == was_masked) {
__enable_irq();
}
return ret;
}
bool FlashAccess::PageProgram(uint32_t addr, uint8_t * buf, int32_t size) {
bool ret;
#if defined (__ICCARM__)
int was_masked = __disable_irq_iar();
#else
int was_masked = __disable_irq();
#endif
spi_mode();
ret = _PageProgram(addr, buf, size);
ex_mode();
if (0 == was_masked) {
__enable_irq();
}
return ret;
}
bool FlashAccess::Read(uint32_t addr, uint8_t * buf, int32_t size) {
bool ret;
#if defined (__ICCARM__)
int was_masked = __disable_irq_iar();
#else
int was_masked = __disable_irq();
#endif
spi_mode();
ret = _Read(addr, buf, size);
ex_mode();
if (0 == was_masked) {
__enable_irq();
}
return ret;
}
/** protected **/
bool FlashAccess::_SectorErase(uint32_t addr) {
bool ret;
/* ---- Write enable ---- */
ret = _WriteEnable(); /* WREN Command */
if (ret == false) {
return ret;
}
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- command ---- */
spimd_reg.cde = SPIBSC_OUTPUT_ENABLE;
spimd_reg.cdb = SPIBSC_1BIT;
spimd_reg.cmd = SFLASHCMD_SECTOR_ERASE;
/* ---- address ---- */
spimd_reg.ade = SPIBSC_OUTPUT_ADDR_24;
spimd_reg.addre = SPIBSC_SDR_TRANS; /* SDR */
spimd_reg.adb = SPIBSC_1BIT;
spimd_reg.addr = addr;
ret = spibsc_transfer(&spimd_reg);
if (ret == false) {
return ret;
}
ret = _busy_wait();
return ret;
}
bool FlashAccess::_PageProgram(uint32_t addr, uint8_t * buf, int32_t size) {
bool ret;
/* ---- Write enable ---- */
ret = _WriteEnable(); /* WREN Command */
if (ret == false) {
return ret;
}
/* ----------- 1. Command, Address ---------------*/
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- command ---- */
spimd_reg.cde = SPIBSC_OUTPUT_ENABLE;
spimd_reg.cdb = SPIBSC_1BIT;
spimd_reg.cmd = SFLASHCMD_PAGE_PROGRAM;
/* ---- address ---- */
spimd_reg.ade = SPIBSC_OUTPUT_ADDR_24;
spimd_reg.addre = SPIBSC_SDR_TRANS; /* SDR */
spimd_reg.adb = SPIBSC_1BIT;
spimd_reg.addr = addr;
/* ---- Others ---- */
spimd_reg.sslkp = SPIBSC_SPISSL_KEEP; /* SPBSSL level */
ret = spibsc_transfer(&spimd_reg); /* Command,Address */
if (ret == false) {
return ret;
}
/* ----------- 2. Data ---------------*/
ret = data_send(SPIBSC_1BIT, SPIBSC_SPISSL_NEGATE, buf, size);
if (ret == false) {
return ret;
}
ret = _busy_wait();
return ret;
}
bool FlashAccess::_Read(uint32_t addr, uint8_t * buf, int32_t size) {
bool ret;
/* ----------- 1. Command, Address ---------------*/
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- command ---- */
spimd_reg.cde = SPIBSC_OUTPUT_ENABLE;
spimd_reg.cdb = SPIBSC_1BIT;
spimd_reg.cmd = SFLASHCMD_READ;
/* ---- address ---- */
spimd_reg.ade = SPIBSC_OUTPUT_ADDR_24;
spimd_reg.addre = SPIBSC_SDR_TRANS; /* SDR */
spimd_reg.adb = SPIBSC_1BIT;
spimd_reg.addr = addr;
/* ---- Others ---- */
spimd_reg.sslkp = SPIBSC_SPISSL_KEEP; /* SPBSSL level */
ret = spibsc_transfer(&spimd_reg); /* Command,Address */
if (ret == false) {
return ret;
}
/* ----------- 2. Data ---------------*/
ret = data_recv(SPIBSC_1BIT, SPIBSC_SPISSL_NEGATE, buf, size);
return ret;
}
bool FlashAccess::_WriteEnable(void) {
bool ret;
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- command ---- */
spimd_reg.cde = SPIBSC_OUTPUT_ENABLE;
spimd_reg.cdb = SPIBSC_1BIT;
spimd_reg.cmd = SFLASHCMD_WRITE_ENABLE;
ret = spibsc_transfer(&spimd_reg);
return ret;
}
bool FlashAccess::_busy_wait(void) {
bool ret;
uint8_t st_reg;
while (1) {
ret = _read_register(SFLASHCMD_READ_STATUS_REG, &st_reg);
if (ret == false) {
break;
}
if ((st_reg & STREG_BUSY_BIT) == 0) {
break;
}
}
return ret;
}
bool FlashAccess::_read_register(uint8_t cmd, uint8_t * status) {
bool ret;
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- command ---- */
spimd_reg.cde = SPIBSC_OUTPUT_ENABLE;
spimd_reg.cdb = SPIBSC_1BIT;
spimd_reg.cmd = cmd;
/* ---- Others ---- */
spimd_reg.sslkp = SPIBSC_SPISSL_NEGATE; /* SPBSSL level */
spimd_reg.spire = SPIBSC_SPIDATA_ENABLE; /* read enable/disable */
spimd_reg.spiwe = SPIBSC_SPIDATA_ENABLE; /* write enable/disable */
/* ---- data ---- */
spimd_reg.spide = SPIBSC_OUTPUT_SPID_8; /* Enable(8bit) */
spimd_reg.spidre = SPIBSC_SDR_TRANS; /* SDR */
spimd_reg.spidb = SPIBSC_1BIT;
spimd_reg.smwdr[0] = 0x00; /* Output 0 in read status */
spimd_reg.smwdr[1] = 0x00; /* Output 0 in read status */
ret = spibsc_transfer(&spimd_reg);
if (ret != false) {
*status = (uint8_t)(spimd_reg.smrdr[0]); /* Data[7:0] */
}
return ret;
}
bool FlashAccess::data_send(uint32_t bit_width, uint32_t spbssl_level, uint8_t * buf, int32_t size) {
bool ret = true;
int32_t unit;
uint8_t *buf_b;
uint16_t *buf_s;
uint32_t *buf_l;
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- Others ---- */
spimd_reg.sslkp = SPIBSC_SPISSL_KEEP; /* SPBSSL level */
spimd_reg.spiwe = SPIBSC_SPIDATA_ENABLE; /* write enable/disable */
/* ---- data ---- */
spimd_reg.spidb = bit_width;
spimd_reg.spidre= SPIBSC_SDR_TRANS; /* SDR */
if (((uint32_t)size & 0x3) == 0) {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_32; /* Enable(32bit) */
unit = 4;
} else if (((uint32_t)size & 0x1) == 0) {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_16; /* Enable(16bit) */
unit = 2;
} else {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_8; /* Enable(8bit) */
unit = 1;
}
while (size > 0) {
if (unit == 1) {
buf_b = (uint8_t *)buf;
spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)*buf_b) & 0x000000FF);
} else if (unit == 2) {
buf_s = (uint16_t *)buf;
spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)*buf_s) & 0x0000FFFF);
} else if (unit == 4) {
buf_l = (uint32_t *)buf;
spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)(*buf_l)) & 0xfffffffful);
} else {
/* Do Nothing */
}
buf += unit;
size -= unit;
if (size <= 0) {
spimd_reg.sslkp = spbssl_level;
}
ret = spibsc_transfer(&spimd_reg); /* Data */
if (ret == false) {
return ret;
}
}
return ret;
}
bool FlashAccess::data_recv(uint32_t bit_width, uint32_t spbssl_level, uint8_t * buf, int32_t size) {
bool ret = true;
int32_t unit;
uint8_t *buf_b;
uint16_t *buf_s;
uint32_t *buf_l;
/* ---- spimd_reg init ---- */
clear_spimd_reg(&spimd_reg);
/* ---- Others ---- */
spimd_reg.sslkp = SPIBSC_SPISSL_KEEP; /* SPBSSL level */
spimd_reg.spire = SPIBSC_SPIDATA_ENABLE; /* read enable/disable */
/* ---- data ---- */
spimd_reg.spidb = bit_width;
spimd_reg.spidre = SPIBSC_SDR_TRANS; /* SDR */
if (((uint32_t)size & 0x3) == 0) {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_32; /* Enable(32bit) */
unit = 4;
} else if (((uint32_t)size & 0x1) == 0) {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_16; /* Enable(16bit) */
unit = 2;
} else {
spimd_reg.spide = SPIBSC_OUTPUT_SPID_8; /* Enable(8bit) */
unit = 1;
}
while (size > 0) {
if (unit >= size) {
spimd_reg.sslkp = spbssl_level;
}
ret = spibsc_transfer(&spimd_reg); /* Data */
if (ret == false) {
return ret;
}
if (unit == 1) {
buf_b = (uint8_t *)buf;
*buf_b = (uint8_t)((spimd_reg.smrdr[0]) & 0x000000fful);
} else if (unit == 2) {
buf_s = (uint16_t *)buf;
*buf_s = (uint16_t)((spimd_reg.smrdr[0]) & 0x0000fffful);
} else if (unit == 4) {
buf_l = (uint32_t *)buf;
*buf_l = (uint32_t)((spimd_reg.smrdr[0]) & 0xfffffffful);
} else {
/* Do Nothing */
}
buf += unit;
size -= unit;
}
return ret;
}
void FlashAccess::spi_mode(void) {
volatile uint32_t dummy_read_32;
if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_SPI) {
/* ==== Change the MMU translation table SPI Multi-I/O bus space settings
for use in SPI operating mode ==== */
change_mmu_ttbl_spibsc(0);
/* ==== Cleaning and invalidation of cache ==== */
cache_control();
/* ==== Switch to SPI operating mode ==== */
spibsc_stop();
dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
/* SPI Mode */
RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SPI, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
}
(void)dummy_read_32;
}
void FlashAccess::ex_mode(void) {
volatile uint32_t dummy_read_32;
if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_EXTRD) {
/* ==== Switch to external address space read mode and clear SPIBSC read cache ==== */
spibsc_stop();
/* Flush SPIBSC's read cache */
RegWwrite_32(&SPIBSC->DRCR, SPIBSC_DRCR_RCF_EXE, SPIBSC_DRCR_RCF_SHIFT, SPIBSC_DRCR_RCF);
dummy_read_32 = SPIBSC->DRCR; /* dummy read */
/* External address space read mode */
RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_EXTRD, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
/* ==== Change the MMU translation table SPI Multi-I/O bus space settings
for use in external address space read mode ==== */
change_mmu_ttbl_spibsc(1);
/* ==== Cleaning and invalidation of cache ==== */
cache_control();
}
(void)dummy_read_32;
}
void FlashAccess::clear_spimd_reg(st_spibsc_spimd_reg_t * regset) {
/* ---- command ---- */
regset->cde = SPIBSC_OUTPUT_DISABLE;
regset->cdb = SPIBSC_1BIT;
regset->cmd = 0x00;
/* ---- optional command ---- */
regset->ocde = SPIBSC_OUTPUT_DISABLE;
regset->ocdb = SPIBSC_1BIT;
regset->ocmd = 0x00;
/* ---- address ---- */
regset->ade = SPIBSC_OUTPUT_DISABLE;
regset->addre = SPIBSC_SDR_TRANS; /* SDR */
regset->adb = SPIBSC_1BIT;
regset->addr = 0x00000000;
/* ---- option data ---- */
regset->opde = SPIBSC_OUTPUT_DISABLE;
regset->opdre = SPIBSC_SDR_TRANS; /* SDR */
regset->opdb = SPIBSC_1BIT;
regset->opd[0] = 0x00; /* OPD3 */
regset->opd[1] = 0x00; /* OPD2 */
regset->opd[2] = 0x00; /* OPD1 */
regset->opd[3] = 0x00; /* OPD0 */
/* ---- dummy cycle ---- */
regset->dme = SPIBSC_DUMMY_CYC_DISABLE;
regset->dmdb = SPIBSC_1BIT;
regset->dmcyc = SPIBSC_DUMMY_1CYC;
/* ---- data ---- */
regset->spide = SPIBSC_OUTPUT_DISABLE;
regset->spidre = SPIBSC_SDR_TRANS; /* SDR */
regset->spidb = SPIBSC_1BIT;
/* ---- Others ---- */
regset->sslkp = SPIBSC_SPISSL_NEGATE; /* SPBSSL level */
regset->spire = SPIBSC_SPIDATA_DISABLE; /* read enable/disable */
regset->spiwe = SPIBSC_SPIDATA_DISABLE; /* write enable/disable */
}
bool FlashAccess::spibsc_transfer(st_spibsc_spimd_reg_t * regset) {
if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_SPI) {
if (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_SSLF_SHIFT, SPIBSC_CMNSR_SSLF) != SPIBSC_SSL_NEGATE) {
return false;
}
/* SPI Mode */
RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SPI, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
}
if (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
return false;
}
/* ---- Command ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->cde, SPIBSC_SMENR_CDE_SHIFT, SPIBSC_SMENR_CDE);
if (regset->cde != SPIBSC_OUTPUT_DISABLE) {
/* Command */
RegWwrite_32(&SPIBSC->SMCMR, regset->cmd, SPIBSC_SMCMR_CMD_SHIFT, SPIBSC_SMCMR_CMD);
/* Single/Dual/Quad */
RegWwrite_32(&SPIBSC->SMENR, regset->cdb, SPIBSC_SMENR_CDB_SHIFT, SPIBSC_SMENR_CDB);
}
/* ---- Option Command ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->ocde, SPIBSC_SMENR_OCDE_SHIFT, SPIBSC_SMENR_OCDE);
if (regset->ocde != SPIBSC_OUTPUT_DISABLE) {
/* Option Command */
RegWwrite_32(&SPIBSC->SMCMR, regset->ocmd, SPIBSC_SMCMR_OCMD_SHIFT, SPIBSC_SMCMR_OCMD);
/* Single/Dual/Quad */
RegWwrite_32(&SPIBSC->SMENR, regset->ocdb, SPIBSC_SMENR_OCDB_SHIFT, SPIBSC_SMENR_OCDB);
}
/* ---- Address ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->ade, SPIBSC_SMENR_ADE_SHIFT, SPIBSC_SMENR_ADE);
if (regset->ade != SPIBSC_OUTPUT_DISABLE) {
/* Address */
RegWwrite_32(&SPIBSC->SMADR, regset->addr, SPIBSC_SMADR_ADR_SHIFT, SPIBSC_SMADR_ADR);
/* Single/Dual/Quad */
RegWwrite_32(&SPIBSC->SMENR, regset->adb, SPIBSC_SMENR_ADB_SHIFT, SPIBSC_SMENR_ADB);
}
/* ---- Option Data ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->opde, SPIBSC_SMENR_OPDE_SHIFT, SPIBSC_SMENR_OPDE);
if (regset->opde != SPIBSC_OUTPUT_DISABLE) {
/* Option Data */
RegWwrite_32(&SPIBSC->SMOPR, regset->opd[0], SPIBSC_SMOPR_OPD3_SHIFT, SPIBSC_SMOPR_OPD3);
RegWwrite_32(&SPIBSC->SMOPR, regset->opd[1], SPIBSC_SMOPR_OPD2_SHIFT, SPIBSC_SMOPR_OPD2);
RegWwrite_32(&SPIBSC->SMOPR, regset->opd[2], SPIBSC_SMOPR_OPD1_SHIFT, SPIBSC_SMOPR_OPD1);
RegWwrite_32(&SPIBSC->SMOPR, regset->opd[3], SPIBSC_SMOPR_OPD0_SHIFT, SPIBSC_SMOPR_OPD0);
/* Single/Dual/Quad */
RegWwrite_32(&SPIBSC->SMENR, regset->opdb, SPIBSC_SMENR_OPDB_SHIFT, SPIBSC_SMENR_OPDB);
}
/* ---- Dummy ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->dme, SPIBSC_SMENR_DME_SHIFT, SPIBSC_SMENR_DME);
if (regset->dme != SPIBSC_DUMMY_CYC_DISABLE) {
RegWwrite_32(&SPIBSC->SMDMCR, regset->dmdb, SPIBSC_SMDMCR_DMDB_SHIFT, SPIBSC_SMDMCR_DMDB);
/* Dummy Cycle */
RegWwrite_32(&SPIBSC->SMDMCR, regset->dmcyc, SPIBSC_SMDMCR_DMCYC_SHIFT, SPIBSC_SMDMCR_DMCYC);
}
/* ---- Data ---- */
/* Enable/Disable */
RegWwrite_32(&SPIBSC->SMENR, regset->spide, SPIBSC_SMENR_SPIDE_SHIFT, SPIBSC_SMENR_SPIDE);
if (regset->spide != SPIBSC_OUTPUT_DISABLE) {
if (SPIBSC_OUTPUT_SPID_8 == regset->spide) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
SPIBSC->SMWDR0.UINT8[0] = (uint8_t)(regset->smwdr[0]);
} else {
SPIBSC->SMWDR0.UINT16[0] = (uint16_t)(regset->smwdr[0]);
}
} else if (regset->spide == SPIBSC_OUTPUT_SPID_16) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
SPIBSC->SMWDR0.UINT16[0] = (uint16_t)(regset->smwdr[0]);
} else {
SPIBSC->SMWDR0.UINT32 = regset->smwdr[0];
}
} else if (regset->spide == SPIBSC_OUTPUT_SPID_32) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
SPIBSC->SMWDR0.UINT32 = (uint32_t)(regset->smwdr[0]);
} else {
SPIBSC->SMWDR0.UINT32 = (uint32_t)(regset->smwdr[0]);
SPIBSC->SMWDR1.UINT32 = (uint32_t)(regset->smwdr[1]); /* valid in two serial-flash */
}
} else {
/* none */
}
/* Single/Dual/Quad */
RegWwrite_32(&SPIBSC->SMENR, regset->spidb, SPIBSC_SMENR_SPIDB_SHIFT, SPIBSC_SMENR_SPIDB);
}
RegWwrite_32(&SPIBSC->SMCR, regset->sslkp, SPIBSC_SMCR_SSLKP_SHIFT, SPIBSC_SMCR_SSLKP);
if ((regset->spidb != SPIBSC_1BIT) && (regset->spide != SPIBSC_OUTPUT_DISABLE)) {
if ((regset->spire == SPIBSC_SPIDATA_ENABLE) && (regset->spiwe == SPIBSC_SPIDATA_ENABLE)) {
/* not set in same time */
return false;
}
}
RegWwrite_32(&SPIBSC->SMCR, regset->spire, SPIBSC_SMCR_SPIRE_SHIFT, SPIBSC_SMCR_SPIRE);
RegWwrite_32(&SPIBSC->SMCR, regset->spiwe, SPIBSC_SMCR_SPIWE_SHIFT, SPIBSC_SMCR_SPIWE);
/* SDR Transmission/DDR Transmission Setting */
RegWwrite_32(&SPIBSC->SMDRENR, regset->addre, SPIBSC_SMDRENR_ADDRE_SHIFT, SPIBSC_SMDRENR_ADDRE);
RegWwrite_32(&SPIBSC->SMDRENR, regset->opdre, SPIBSC_SMDRENR_OPDRE_SHIFT, SPIBSC_SMDRENR_OPDRE);
RegWwrite_32(&SPIBSC->SMDRENR, regset->spidre, SPIBSC_SMDRENR_SPIDRE_SHIFT, SPIBSC_SMDRENR_SPIDRE);
/* execute after setting SPNDL bit */
RegWwrite_32(&SPIBSC->SMCR, SPIBSC_SPI_ENABLE, SPIBSC_SMCR_SPIE_SHIFT, SPIBSC_SMCR_SPIE);
/* wait for transfer-start */
while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
/* wait for transfer-end */
}
if (SPIBSC_OUTPUT_SPID_8 == regset->spide) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT8[0];
} else {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT16[0]; /* valid in two serial-flash */
}
} else if (regset->spide == SPIBSC_OUTPUT_SPID_16) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT16[0];
} else {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT32; /* valid in two serial-flash */
}
} else if (regset->spide == SPIBSC_OUTPUT_SPID_32) {
if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT32;
} else {
regset->smrdr[0] = SPIBSC->SMRDR0.UINT32; /* valid in two serial-flash */
regset->smrdr[1] = SPIBSC->SMRDR1.UINT32;
}
} else {
/* none */
}
return true;
}
uint32_t FlashAccess::RegRead_32(volatile uint32_t * ioreg, uint32_t shift, uint32_t mask) {
uint32_t reg_value;
reg_value = *ioreg; /* Read from register */
reg_value = (reg_value & mask) >> shift; /* Clear other bit and Bit shift */
return reg_value;
}
void FlashAccess::RegWwrite_32(volatile uint32_t * ioreg, uint32_t write_value, uint32_t shift, uint32_t mask) {
uint32_t reg_value;
reg_value = *ioreg; /* Read from register */
reg_value = (reg_value & (~mask)) | (write_value << shift); /* Modify value */
*ioreg = reg_value; /* Write to register */
}
/** private **/
void FlashAccess::change_mmu_ttbl_spibsc(uint32_t type) {
uint32_t index; /* Loop variable: table index */
mmu_ttbl_desc_section_t desc; /* Loop variable: descriptor */
mmu_ttbl_desc_section_t * table = (mmu_ttbl_desc_section_t *)TTB;
/* ==== Modify SPI Multi-I/O bus space settings in the MMU translation table ==== */
for (index = (SPIBSC_ADDR_START >> 20); index <= (SPIBSC_ADDR_END >> 20); index++) {
/* Modify memory attribute descriptor */
if (type == 0) { /* Spi */
desc = table[index];
desc_tbl[index - (SPIBSC_ADDR_START >> 20)] = desc;
desc.AP1_0 = 0x0u; /* AP[2:0] = b'000 (No access) */
desc.AP2 = 0x0u;
desc.XN = 0x1u; /* XN = 1 (Execute never) */
} else { /* Xip */
desc = desc_tbl[index - (SPIBSC_ADDR_START >> 20)];
}
/* Write descriptor back to translation table */
table[index] = desc;
}
}
void FlashAccess::spibsc_stop(void) {
if (((SPIBSC->DRCR & SPIBSC_DRCR_RBE) != 0) &&
((SPIBSC->DRCR & SPIBSC_DRCR_SSLE) != 0)) {
RegWwrite_32(&SPIBSC->DRCR, 1, SPIBSC_DRCR_SSLN_SHIFT, SPIBSC_DRCR_SSLN);
}
while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_SSLF_SHIFT, SPIBSC_CMNSR_SSLF) != SPIBSC_SSL_NEGATE) {
;
}
while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
;
}
}
#ifndef __STATIC_FORCEINLINE
#if defined ( __CC_ARM )
#define __STATIC_FORCEINLINE static __forceinline
#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline
#elif defined ( __GNUC__ )
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline
#elif defined ( __ICCARM__ )
#define __STATIC_FORCEINLINE _Pragma("inline=forced") static inline
#endif
#endif
#if defined ( __CC_ARM )
__STATIC_FORCEINLINE __ASM void L1C_CleanInvalidateCache_sforce(uint32_t op) {
ARM
PUSH {R4-R11}
MRC p15, 1, R6, c0, c0, 1 // Read CLIDR
ANDS R3, R6, #0x07000000 // Extract coherency level
MOV R3, R3, LSR #23 // Total cache levels << 1
BEQ Finished // If 0, no need to clean
MOV R10, #0 // R10 holds current cache level << 1
Loop1 ADD R2, R10, R10, LSR #1 // R2 holds cache "Set" position
MOV R1, R6, LSR R2 // Bottom 3 bits are the Cache-type for this level
AND R1, R1, #7 // Isolate those lower 3 bits
CMP R1, #2
BLT Skip // No cache or only instruction cache at this level
MCR p15, 2, R10, c0, c0, 0 // Write the Cache Size selection register
ISB // ISB to sync the change to the CacheSizeID reg
MRC p15, 1, R1, c0, c0, 0 // Reads current Cache Size ID register
AND R2, R1, #7 // Extract the line length field
ADD R2, R2, #4 // Add 4 for the line length offset (log2 16 bytes)
LDR R4, =0x3FF
ANDS R4, R4, R1, LSR #3 // R4 is the max number on the way size (right aligned)
CLZ R5, R4 // R5 is the bit position of the way size increment
LDR R7, =0x7FFF
ANDS R7, R7, R1, LSR #13 // R7 is the max number of the index size (right aligned)
Loop2 MOV R9, R4 // R9 working copy of the max way size (right aligned)
Loop3 ORR R11, R10, R9, LSL R5 // Factor in the Way number and cache number into R11
ORR R11, R11, R7, LSL R2 // Factor in the Set number
CMP R0, #0
BNE Dccsw
MCR p15, 0, R11, c7, c6, 2 // DCISW. Invalidate by Set/Way
B cont
Dccsw CMP R0, #1
BNE Dccisw
MCR p15, 0, R11, c7, c10, 2 // DCCSW. Clean by Set/Way
B cont
Dccisw MCR p15, 0, R11, c7, c14, 2 // DCCISW. Clean and Invalidate by Set/Way
cont SUBS R9, R9, #1 // Decrement the Way number
BGE Loop3
SUBS R7, R7, #1 // Decrement the Set number
BGE Loop2
Skip ADD R10, R10, #2 // Increment the cache number
CMP R3, R10
BGT Loop1
Finished
DSB
POP {R4-R11}
BX lr
}
#elif (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) || defined ( __GNUC__ )
__STATIC_FORCEINLINE void L1C_CleanInvalidateCache_sforce(uint32_t op) {
__ASM volatile(
" PUSH {R4-R11} \n"
" MRC p15, 1, R6, c0, c0, 1 \n" // Read CLIDR
" ANDS R3, R6, #0x07000000 \n" // Extract coherency level
" MOV R3, R3, LSR #23 \n" // Total cache levels << 1
" BEQ Finished \n" // If 0, no need to clean
" MOV R10, #0 \n" // R10 holds current cache level << 1
"Loop1: ADD R2, R10, R10, LSR #1 \n" // R2 holds cache "Set" position
" MOV R1, R6, LSR R2 \n" // Bottom 3 bits are the Cache-type for this level
" AND R1, R1, #7 \n" // Isolate those lower 3 bits
" CMP R1, #2 \n"
" BLT Skip \n" // No cache or only instruction cache at this level
" MCR p15, 2, R10, c0, c0, 0 \n" // Write the Cache Size selection register
" ISB \n" // ISB to sync the change to the CacheSizeID reg
" MRC p15, 1, R1, c0, c0, 0 \n" // Reads current Cache Size ID register
" AND R2, R1, #7 \n" // Extract the line length field
" ADD R2, R2, #4 \n" // Add 4 for the line length offset (log2 16 bytes)
" LDR R4, =0x3FF \n"
" ANDS R4, R4, R1, LSR #3 \n" // R4 is the max number on the way size (right aligned)
" CLZ R5, R4 \n" // R5 is the bit position of the way size increment
" LDR R7, =0x7FFF \n"
" ANDS R7, R7, R1, LSR #13 \n" // R7 is the max number of the index size (right aligned)
"Loop2: MOV R9, R4 \n" // R9 working copy of the max way size (right aligned)
"Loop3: ORR R11, R10, R9, LSL R5 \n" // Factor in the Way number and cache number into R11
" ORR R11, R11, R7, LSL R2 \n" // Factor in the Set number
" CMP R0, #0 \n"
" BNE Dccsw \n"
" MCR p15, 0, R11, c7, c6, 2 \n" // DCISW. Invalidate by Set/Way
" B cont \n"
"Dccsw: CMP R0, #1 \n"
" BNE Dccisw \n"
" MCR p15, 0, R11, c7, c10, 2 \n" // DCCSW. Clean by Set/Way
" B cont \n"
"Dccisw: MCR p15, 0, R11, c7, c14, 2 \n" // DCCISW. Clean and Invalidate by Set/Way
"cont: SUBS R9, R9, #1 \n" // Decrement the Way number
" BGE Loop3 \n"
" SUBS R7, R7, #1 \n" // Decrement the Set number
" BGE Loop2 \n"
"Skip: ADD R10, R10, #2 \n" // Increment the cache number
" CMP R3, R10 \n"
" BGT Loop1 \n"
"Finished: \n"
" DSB \n"
" POP {R4-R11} "
);
}
#else
__STATIC_FORCEINLINE void __L1C_MaintainDCacheSetWay_sforce(uint32_t level, uint32_t maint) {
register volatile uint32_t Dummy;
register volatile uint32_t ccsidr;
uint32_t num_sets;
uint32_t num_ways;
uint32_t shift_way;
uint32_t log2_linesize;
uint32_t log2_num_ways;
Dummy = level << 1;
/* set csselr, select ccsidr register */
__set_CCSIDR(Dummy);
/* get current ccsidr register */
ccsidr = __get_CCSIDR();
num_sets = ((ccsidr & 0x0FFFE000) >> 13) + 1;
num_ways = ((ccsidr & 0x00001FF8) >> 3) + 1;
log2_linesize = (ccsidr & 0x00000007) + 2 + 2;
log2_num_ways = log2_up(num_ways);
shift_way = 32 - log2_num_ways;
for (int way = num_ways-1; way >= 0; way--) {
for (int set = num_sets-1; set >= 0; set--) {
Dummy = (level << 1) | (set << log2_linesize) | (way << shift_way);
switch (maint) {
case 0:
// DCISW. Invalidate by Set/Way
__ASM volatile("MCR p15, 0, %0, c7, c6, 2" : : "r"(Dummy) : "memory");
break;
case 1:
// DCCSW. Clean by Set/Way
__ASM volatile("MCR p15, 0, %0, c7, c10, 2" : : "r"(Dummy) : "memory");
break;
default:
// DCCISW. Clean and Invalidate by Set/Way
__ASM volatile("MCR p15, 0, %0, c7, c14, 2" : : "r"(Dummy) : "memory");
break;
}
}
}
__DMB();
}
__STATIC_FORCEINLINE void L1C_CleanInvalidateCache_sforce(uint32_t op) {
register volatile uint32_t clidr;
uint32_t cache_type;
clidr = __get_CLIDR();
for (uint32_t i = 0; i<7; i++) {
cache_type = (clidr >> i*3) & 0x7UL;
if ((cache_type >= 2) && (cache_type <= 4)) {
__L1C_MaintainDCacheSetWay_sforce(i, op);
}
}
}
#endif
#ifdef MBED_VERSION
void FlashAccess::cache_control(void) {
unsigned int assoc;
/* ==== Cleaning and invalidation of the L1 data cache ==== */
L1C_CleanInvalidateCache_sforce(2);
__DSB();
/* ==== Cleaning and invalidation of the L2 cache ==== */
if (PL310->AUX_CNT & (1<<16)) {
assoc = 16;
} else {
assoc = 8;
}
PL310->INV_WAY = (1 << assoc) - 1;
while(PL310->INV_WAY & ((1 << assoc) - 1)); // poll invalidate
PL310->CACHE_SYNC = 0x0;
/* ==== Invalidate all TLB entries ==== */
__ca9u_inv_tlb_all();
/* ==== Invalidate the L1 instruction cache ==== */
__v7_inv_icache_all();
__DSB();
__ISB();
}
#else // mbed-os 5.6.4
void FlashAccess::cache_control(void) {
unsigned int assoc;
/* ==== Cleaning and invalidation of the L1 data cache ==== */
L1C_CleanInvalidateCache_sforce(2);
__DSB();
/* ==== Cleaning and invalidation of the L2 cache ==== */
if (L2C_310->AUX_CNT & (1U << 16U)) {
assoc = 16U;
} else {
assoc = 8U;
}
L2C_310->CLEAN_INV_WAY = (1U << assoc) - 1U;
while (L2C_310->CLEAN_INV_WAY & ((1U << assoc) - 1U)); // poll invalidate
L2C_310->CACHE_SYNC = 0x0;
/* ==== Invalidate all TLB entries ==== */
__set_TLBIALL(0);
__DSB(); // ensure completion of the invalidation
__ISB(); // ensure instruction fetch path sees new state
/* ==== Invalidate the L1 instruction cache ==== */
__set_ICIALLU(0);
__DSB(); // ensure completion of the invalidation
__ISB(); // ensure instruction fetch path sees new I cache state
}
#endif