Daiki Kato / FlashAccess
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FlashAccess.cpp Source File

FlashAccess.cpp

00001 /*******************************************************************************
00002 * DISCLAIMER
00003 * This software is supplied by Renesas Electronics Corporation and is only
00004 * intended for use with Renesas products. No other uses are authorized. This
00005 * software is owned by Renesas Electronics Corporation and is protected under
00006 * all applicable laws, including copyright laws.
00007 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
00008 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
00009 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00010 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
00011 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
00012 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
00013 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
00014 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
00015 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00016 * Renesas reserves the right, without notice, to make changes to this software
00017 * and to discontinue the availability of this software. By using this software,
00018 * you agree to the additional terms and conditions found by accessing the
00019 * following link:
00020 * http://www.renesas.com/disclaimer
00021 *
00022 * Copyright (C) 2017 Renesas Electronics Corporation. All rights reserved.
00023 *******************************************************************************/
00024 
00025 #include "mbed.h"
00026 #include "FlashAccess.h"
00027 
00028 /* ---- serial flash command ---- */
00029 #define SFLASHCMD_SECTOR_ERASE       (0x20u)    /* SE     3-byte address(1bit)             */
00030 #define SFLASHCMD_PAGE_PROGRAM       (0x02u)    /* PP     3-byte address(1bit), data(1bit) */
00031 #define SFLASHCMD_READ               (0x03u)    /* READ   3-byte address(1bit), data(1bit) */
00032 #define SFLASHCMD_READ_STATUS_REG    (0x05u)    /* RDSR                         data(1bit) */
00033 #define SFLASHCMD_WRITE_ENABLE       (0x06u)    /* WREN                                    */
00034 /* ---- serial flash register definitions ---- */
00035 #define STREG_BUSY_BIT               (0x01u)    /* SR.[0]BUSY Erase/Write In Progress (RO) */
00036 
00037 /* Definition of the base address for the MMU translation table */
00038 #if defined(__CC_ARM) || defined(__GNUC__)
00039 extern uint32_t Image$$TTB$$ZI$$Base;
00040 #define TTB         ((uint32_t)&Image$$TTB$$ZI$$Base)   /* using linker symbol */
00041 #elif defined(__ICCARM__)
00042 #pragma section="TTB"
00043 #define TTB         ((uint32_t)__section_begin("TTB"))
00044 #endif
00045 
00046 /** public **/
00047 
00048 FlashAccess::FlashAccess() : SPIBSC(&SPIBSC0) {
00049 }
00050 
00051 bool FlashAccess::SectorErase(uint32_t addr) {
00052     bool ret;
00053 #if defined (__ICCARM__)
00054     int was_masked = __disable_irq_iar();
00055 #else
00056     int was_masked = __disable_irq();
00057 #endif
00058     spi_mode();
00059     ret = _SectorErase(addr);
00060     ex_mode();
00061     if (0 == was_masked) {
00062         __enable_irq();
00063     }
00064     return ret;
00065 }
00066 
00067 bool FlashAccess::PageProgram(uint32_t addr, uint8_t * buf, int32_t size) {
00068     bool ret;
00069 #if defined (__ICCARM__)
00070     int was_masked = __disable_irq_iar();
00071 #else
00072     int was_masked = __disable_irq();
00073 #endif
00074     spi_mode();
00075     ret = _PageProgram(addr, buf, size);
00076     ex_mode();
00077     if (0 == was_masked) {
00078         __enable_irq();
00079     }
00080     return ret;
00081 }
00082 
00083 bool FlashAccess::Read(uint32_t addr, uint8_t * buf, int32_t size) {
00084     bool ret;
00085 #if defined (__ICCARM__)
00086     int was_masked = __disable_irq_iar();
00087 #else
00088     int was_masked = __disable_irq();
00089 #endif
00090     spi_mode();
00091     ret = _Read(addr, buf, size);
00092     ex_mode();
00093     if (0 == was_masked) {
00094         __enable_irq();
00095     }
00096     return ret;
00097 }
00098 
00099 /** protected **/
00100 
00101 bool FlashAccess::_SectorErase(uint32_t addr) {
00102     bool ret;
00103 
00104     /* ---- Write enable   ---- */
00105     ret = _WriteEnable();      /* WREN Command */
00106     if (ret == false) {
00107         return ret;
00108     }
00109 
00110     /* ---- spimd_reg init ---- */
00111     clear_spimd_reg(&spimd_reg);
00112 
00113     /* ---- command ---- */
00114     spimd_reg.cde    = SPIBSC_OUTPUT_ENABLE;
00115     spimd_reg.cdb    = SPIBSC_1BIT;
00116     spimd_reg.cmd    = SFLASHCMD_SECTOR_ERASE;
00117 
00118     /* ---- address ---- */
00119     spimd_reg.ade    = SPIBSC_OUTPUT_ADDR_24;
00120     spimd_reg.addre  = SPIBSC_SDR_TRANS;       /* SDR */
00121     spimd_reg.adb    = SPIBSC_1BIT;
00122     spimd_reg.addr   = addr;
00123 
00124     ret = spibsc_transfer(&spimd_reg);
00125     if (ret == false) {
00126         return ret;
00127     }
00128 
00129     ret = _busy_wait();
00130 
00131     return ret;
00132 }
00133 
00134 bool FlashAccess::_PageProgram(uint32_t addr, uint8_t * buf, int32_t size) {
00135     bool ret;
00136 
00137     /* ---- Write enable   ---- */
00138     ret = _WriteEnable();      /* WREN Command */
00139     if (ret == false) {
00140         return ret;
00141     }
00142 
00143     /* ----------- 1. Command, Address ---------------*/
00144     /* ---- spimd_reg init ---- */
00145     clear_spimd_reg(&spimd_reg);
00146 
00147     /* ---- command ---- */
00148     spimd_reg.cde    = SPIBSC_OUTPUT_ENABLE;
00149     spimd_reg.cdb    = SPIBSC_1BIT;
00150     spimd_reg.cmd    = SFLASHCMD_PAGE_PROGRAM;
00151 
00152     /* ---- address ---- */
00153     spimd_reg.ade    = SPIBSC_OUTPUT_ADDR_24;
00154     spimd_reg.addre  = SPIBSC_SDR_TRANS;       /* SDR */
00155     spimd_reg.adb    = SPIBSC_1BIT;
00156     spimd_reg.addr   = addr;
00157 
00158     /* ---- Others ---- */
00159     spimd_reg.sslkp  = SPIBSC_SPISSL_KEEP;     /* SPBSSL level */
00160 
00161     ret = spibsc_transfer(&spimd_reg);         /* Command,Address */
00162     if (ret == false) {
00163         return ret;
00164     }
00165 
00166     /* ----------- 2. Data ---------------*/
00167     ret = data_send(SPIBSC_1BIT, SPIBSC_SPISSL_NEGATE, buf, size);
00168     if (ret == false) {
00169         return ret;
00170     }
00171 
00172     ret = _busy_wait();
00173 
00174     return ret;
00175 }
00176 
00177 bool FlashAccess::_Read(uint32_t addr, uint8_t * buf, int32_t size) {
00178     bool ret;
00179 
00180     /* ----------- 1. Command, Address ---------------*/
00181     /* ---- spimd_reg init ---- */
00182     clear_spimd_reg(&spimd_reg);
00183 
00184     /* ---- command ---- */
00185     spimd_reg.cde    = SPIBSC_OUTPUT_ENABLE;
00186     spimd_reg.cdb    = SPIBSC_1BIT;
00187     spimd_reg.cmd    = SFLASHCMD_READ;
00188 
00189     /* ---- address ---- */
00190     spimd_reg.ade    = SPIBSC_OUTPUT_ADDR_24;
00191     spimd_reg.addre  = SPIBSC_SDR_TRANS;       /* SDR */
00192     spimd_reg.adb    = SPIBSC_1BIT;
00193     spimd_reg.addr   = addr;
00194 
00195     /* ---- Others ---- */
00196     spimd_reg.sslkp  = SPIBSC_SPISSL_KEEP;     /* SPBSSL level */
00197 
00198     ret = spibsc_transfer(&spimd_reg);         /* Command,Address */
00199     if (ret == false) {
00200         return ret;
00201     }
00202 
00203     /* ----------- 2. Data ---------------*/
00204     ret = data_recv(SPIBSC_1BIT, SPIBSC_SPISSL_NEGATE, buf, size);
00205 
00206     return ret;
00207 }
00208 
00209 bool FlashAccess::_WriteEnable(void) {
00210     bool ret;
00211 
00212     /* ---- spimd_reg init ---- */
00213     clear_spimd_reg(&spimd_reg);
00214 
00215     /* ---- command ---- */
00216     spimd_reg.cde    = SPIBSC_OUTPUT_ENABLE;
00217     spimd_reg.cdb    = SPIBSC_1BIT;
00218     spimd_reg.cmd    = SFLASHCMD_WRITE_ENABLE;
00219 
00220     ret = spibsc_transfer(&spimd_reg);
00221 
00222     return ret;
00223 }
00224 
00225 bool FlashAccess::_busy_wait(void) {
00226     bool ret;
00227     uint8_t st_reg;
00228 
00229     while (1) {
00230         ret = _read_register(SFLASHCMD_READ_STATUS_REG, &st_reg);
00231         if (ret == false) {
00232             break;
00233         }
00234         if ((st_reg & STREG_BUSY_BIT) == 0) {
00235             break;
00236         }
00237     }
00238 
00239     return ret;
00240 }
00241 
00242 bool FlashAccess::_read_register(uint8_t cmd, uint8_t * status) {
00243     bool ret;
00244 
00245     /* ---- spimd_reg init ---- */
00246     clear_spimd_reg(&spimd_reg);
00247 
00248     /* ---- command ---- */
00249     spimd_reg.cde    = SPIBSC_OUTPUT_ENABLE;
00250     spimd_reg.cdb    = SPIBSC_1BIT;
00251     spimd_reg.cmd    = cmd;
00252 
00253     /* ---- Others ---- */
00254     spimd_reg.sslkp  = SPIBSC_SPISSL_NEGATE;   /* SPBSSL level */
00255     spimd_reg.spire  = SPIBSC_SPIDATA_ENABLE;  /* read enable/disable */
00256     spimd_reg.spiwe  = SPIBSC_SPIDATA_ENABLE;  /* write enable/disable */
00257 
00258     /* ---- data ---- */
00259     spimd_reg.spide  = SPIBSC_OUTPUT_SPID_8;   /* Enable(8bit) */
00260     spimd_reg.spidre = SPIBSC_SDR_TRANS;       /* SDR */
00261     spimd_reg.spidb  = SPIBSC_1BIT;
00262     spimd_reg.smwdr[0] = 0x00;                 /* Output 0 in read status */
00263     spimd_reg.smwdr[1] = 0x00;                 /* Output 0 in read status */
00264 
00265     ret = spibsc_transfer(&spimd_reg);
00266     if (ret != false) {
00267         *status = (uint8_t)(spimd_reg.smrdr[0]);   /* Data[7:0]  */
00268     }
00269 
00270     return ret;
00271 }
00272 
00273 bool FlashAccess::data_send(uint32_t bit_width, uint32_t spbssl_level, uint8_t * buf, int32_t size) {
00274     bool ret = true;
00275     int32_t unit;
00276     uint8_t  *buf_b;
00277     uint16_t *buf_s;
00278     uint32_t *buf_l;
00279 
00280     /* ---- spimd_reg init ---- */
00281     clear_spimd_reg(&spimd_reg);
00282 
00283     /* ---- Others ---- */
00284     spimd_reg.sslkp  = SPIBSC_SPISSL_KEEP;     /* SPBSSL level */
00285     spimd_reg.spiwe  = SPIBSC_SPIDATA_ENABLE;  /* write enable/disable */
00286 
00287     /* ---- data ---- */
00288     spimd_reg.spidb = bit_width;
00289     spimd_reg.spidre= SPIBSC_SDR_TRANS;        /* SDR */
00290 
00291     if (((uint32_t)size & 0x3)  == 0) {
00292         spimd_reg.spide = SPIBSC_OUTPUT_SPID_32;  /* Enable(32bit) */
00293         unit = 4;
00294     } else if (((uint32_t)size & 0x1) == 0) {
00295         spimd_reg.spide = SPIBSC_OUTPUT_SPID_16;  /* Enable(16bit) */
00296         unit = 2;
00297     } else {
00298         spimd_reg.spide = SPIBSC_OUTPUT_SPID_8;   /* Enable(8bit) */
00299         unit = 1;
00300     }
00301 
00302     while (size > 0) {
00303         if (unit == 1) {
00304             buf_b = (uint8_t *)buf;
00305             spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)*buf_b) & 0x000000FF);
00306         } else if (unit == 2) {
00307             buf_s = (uint16_t *)buf;
00308             spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)*buf_s) & 0x0000FFFF);
00309         } else if (unit == 4) {
00310             buf_l = (uint32_t *)buf;
00311             spimd_reg.smwdr[0] = (uint32_t)(((uint32_t)(*buf_l)) & 0xfffffffful);
00312         } else {
00313             /* Do Nothing */
00314         }
00315 
00316         buf  += unit;
00317         size -= unit;
00318 
00319         if (size <= 0) {
00320             spimd_reg.sslkp = spbssl_level;
00321         }
00322 
00323         ret = spibsc_transfer(&spimd_reg);    /* Data */
00324         if (ret == false) {
00325             return ret;
00326         }
00327     }
00328 
00329     return ret;
00330 }
00331 
00332 bool FlashAccess::data_recv(uint32_t bit_width, uint32_t spbssl_level, uint8_t * buf, int32_t size) {
00333     bool ret = true;
00334     int32_t unit;
00335     uint8_t  *buf_b;
00336     uint16_t *buf_s;
00337     uint32_t *buf_l;
00338 
00339     /* ---- spimd_reg init ---- */
00340     clear_spimd_reg(&spimd_reg);
00341 
00342     /* ---- Others ---- */
00343     spimd_reg.sslkp  = SPIBSC_SPISSL_KEEP;     /* SPBSSL level */
00344     spimd_reg.spire  = SPIBSC_SPIDATA_ENABLE;  /* read enable/disable */
00345 
00346     /* ---- data ---- */
00347     spimd_reg.spidb  = bit_width;
00348     spimd_reg.spidre = SPIBSC_SDR_TRANS;       /* SDR */
00349 
00350     if (((uint32_t)size & 0x3) == 0) {
00351         spimd_reg.spide = SPIBSC_OUTPUT_SPID_32;  /* Enable(32bit) */
00352         unit = 4;
00353     } else if (((uint32_t)size & 0x1) == 0) {
00354         spimd_reg.spide = SPIBSC_OUTPUT_SPID_16;  /* Enable(16bit) */
00355         unit = 2;
00356     } else {
00357         spimd_reg.spide = SPIBSC_OUTPUT_SPID_8;   /* Enable(8bit) */
00358         unit = 1;
00359     }
00360 
00361     while (size > 0) {
00362         if (unit >= size) {
00363             spimd_reg.sslkp = spbssl_level;
00364         }
00365 
00366         ret = spibsc_transfer(&spimd_reg);     /* Data */
00367         if (ret == false) {
00368             return ret;
00369         }
00370 
00371         if (unit == 1) {
00372             buf_b = (uint8_t *)buf;
00373             *buf_b = (uint8_t)((spimd_reg.smrdr[0]) & 0x000000fful);
00374         } else if (unit ==  2) {
00375             buf_s = (uint16_t *)buf;
00376             *buf_s = (uint16_t)((spimd_reg.smrdr[0]) & 0x0000fffful);
00377         } else if (unit == 4) {
00378             buf_l = (uint32_t *)buf;
00379             *buf_l = (uint32_t)((spimd_reg.smrdr[0]) & 0xfffffffful);
00380         } else {
00381             /* Do Nothing */
00382         }
00383 
00384         buf  += unit;
00385         size -= unit;
00386     }
00387 
00388     return ret;
00389 }
00390 
00391 void FlashAccess::spi_mode(void) {
00392     volatile uint32_t dummy_read_32;
00393 
00394     if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_SPI) {
00395         /* ==== Change the MMU translation table SPI Multi-I/O bus space settings
00396                 for use in SPI operating mode ==== */
00397         change_mmu_ttbl_spibsc(0);
00398 
00399         /* ==== Cleaning and invalidation of cache ==== */
00400         cache_control();
00401 
00402         /* ==== Switch to SPI operating mode ==== */
00403         spibsc_stop();
00404 
00405         dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
00406         /* SPI Mode */
00407         RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SPI, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
00408         dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
00409 
00410     }
00411     (void)dummy_read_32;
00412 }
00413 
00414 void FlashAccess::ex_mode(void) {
00415     volatile uint32_t dummy_read_32;
00416 
00417     if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_EXTRD) {
00418         /* ==== Switch to external address space read mode and clear SPIBSC read cache ==== */
00419         spibsc_stop();
00420 
00421         /* Flush SPIBSC's read cache */
00422         RegWwrite_32(&SPIBSC->DRCR, SPIBSC_DRCR_RCF_EXE, SPIBSC_DRCR_RCF_SHIFT, SPIBSC_DRCR_RCF);
00423         dummy_read_32 = SPIBSC->DRCR;  /* dummy read */
00424 
00425         /* External address space read mode */
00426         RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_EXTRD, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
00427         dummy_read_32 = SPIBSC->CMNCR; /* dummy read */
00428 
00429         /* ==== Change the MMU translation table SPI Multi-I/O bus space settings
00430                 for use in external address space read mode ==== */
00431         change_mmu_ttbl_spibsc(1);
00432 
00433         /* ==== Cleaning and invalidation of cache ==== */
00434         cache_control();
00435     }
00436     (void)dummy_read_32;
00437 }
00438 
00439 void FlashAccess::clear_spimd_reg(st_spibsc_spimd_reg_t * regset) {
00440     /* ---- command ---- */
00441     regset->cde    = SPIBSC_OUTPUT_DISABLE;
00442     regset->cdb    = SPIBSC_1BIT;
00443     regset->cmd    = 0x00;
00444 
00445     /* ---- optional command ---- */
00446     regset->ocde   = SPIBSC_OUTPUT_DISABLE;
00447     regset->ocdb   = SPIBSC_1BIT;
00448     regset->ocmd   = 0x00;
00449 
00450     /* ---- address ---- */
00451     regset->ade    = SPIBSC_OUTPUT_DISABLE;
00452     regset->addre  = SPIBSC_SDR_TRANS;       /* SDR */
00453     regset->adb    = SPIBSC_1BIT;
00454     regset->addr   = 0x00000000;
00455 
00456     /* ---- option data ---- */
00457     regset->opde   = SPIBSC_OUTPUT_DISABLE;
00458     regset->opdre  = SPIBSC_SDR_TRANS;       /* SDR */
00459     regset->opdb   = SPIBSC_1BIT;
00460     regset->opd[0] = 0x00;    /* OPD3 */
00461     regset->opd[1] = 0x00;    /* OPD2 */
00462     regset->opd[2] = 0x00;    /* OPD1 */
00463     regset->opd[3] = 0x00;    /* OPD0 */
00464 
00465     /* ---- dummy cycle ---- */
00466     regset->dme    = SPIBSC_DUMMY_CYC_DISABLE;
00467     regset->dmdb   = SPIBSC_1BIT;
00468     regset->dmcyc  = SPIBSC_DUMMY_1CYC;
00469 
00470     /* ---- data ---- */
00471     regset->spide  = SPIBSC_OUTPUT_DISABLE;
00472     regset->spidre = SPIBSC_SDR_TRANS;       /* SDR */
00473     regset->spidb  = SPIBSC_1BIT;
00474 
00475     /* ---- Others ---- */
00476     regset->sslkp  = SPIBSC_SPISSL_NEGATE;   /* SPBSSL level */
00477     regset->spire  = SPIBSC_SPIDATA_DISABLE; /* read enable/disable */
00478     regset->spiwe  = SPIBSC_SPIDATA_DISABLE; /* write enable/disable */
00479 }
00480 
00481 bool FlashAccess::spibsc_transfer(st_spibsc_spimd_reg_t * regset) {
00482     if (RegRead_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD) != SPIBSC_CMNCR_MD_SPI) {
00483         if (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_SSLF_SHIFT, SPIBSC_CMNSR_SSLF) != SPIBSC_SSL_NEGATE) {
00484             return false;
00485         }
00486         /* SPI Mode */
00487         RegWwrite_32(&SPIBSC->CMNCR, SPIBSC_CMNCR_MD_SPI, SPIBSC_CMNCR_MD_SHIFT, SPIBSC_CMNCR_MD);
00488     }
00489 
00490     if (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
00491         return false;
00492     }
00493 
00494     /* ---- Command ---- */
00495     /* Enable/Disable */
00496     RegWwrite_32(&SPIBSC->SMENR, regset->cde, SPIBSC_SMENR_CDE_SHIFT, SPIBSC_SMENR_CDE);
00497     if (regset->cde != SPIBSC_OUTPUT_DISABLE) {
00498         /* Command */
00499         RegWwrite_32(&SPIBSC->SMCMR, regset->cmd, SPIBSC_SMCMR_CMD_SHIFT, SPIBSC_SMCMR_CMD);
00500         /* Single/Dual/Quad */
00501         RegWwrite_32(&SPIBSC->SMENR, regset->cdb, SPIBSC_SMENR_CDB_SHIFT, SPIBSC_SMENR_CDB);
00502     }
00503 
00504     /* ---- Option Command ---- */
00505     /* Enable/Disable */
00506     RegWwrite_32(&SPIBSC->SMENR, regset->ocde, SPIBSC_SMENR_OCDE_SHIFT, SPIBSC_SMENR_OCDE);
00507     if (regset->ocde != SPIBSC_OUTPUT_DISABLE) {
00508         /* Option Command */
00509         RegWwrite_32(&SPIBSC->SMCMR, regset->ocmd, SPIBSC_SMCMR_OCMD_SHIFT, SPIBSC_SMCMR_OCMD);
00510         /* Single/Dual/Quad */
00511         RegWwrite_32(&SPIBSC->SMENR, regset->ocdb, SPIBSC_SMENR_OCDB_SHIFT, SPIBSC_SMENR_OCDB);
00512     }
00513 
00514     /* ---- Address ---- */
00515     /* Enable/Disable */
00516     RegWwrite_32(&SPIBSC->SMENR, regset->ade, SPIBSC_SMENR_ADE_SHIFT, SPIBSC_SMENR_ADE);
00517     if (regset->ade != SPIBSC_OUTPUT_DISABLE) {
00518         /* Address */
00519         RegWwrite_32(&SPIBSC->SMADR, regset->addr, SPIBSC_SMADR_ADR_SHIFT, SPIBSC_SMADR_ADR);
00520         /* Single/Dual/Quad */
00521         RegWwrite_32(&SPIBSC->SMENR, regset->adb, SPIBSC_SMENR_ADB_SHIFT, SPIBSC_SMENR_ADB);
00522     }
00523 
00524     /* ---- Option Data ---- */
00525     /* Enable/Disable */
00526     RegWwrite_32(&SPIBSC->SMENR, regset->opde, SPIBSC_SMENR_OPDE_SHIFT, SPIBSC_SMENR_OPDE);
00527     if (regset->opde != SPIBSC_OUTPUT_DISABLE) {
00528         /* Option Data */
00529         RegWwrite_32(&SPIBSC->SMOPR, regset->opd[0], SPIBSC_SMOPR_OPD3_SHIFT, SPIBSC_SMOPR_OPD3);
00530         RegWwrite_32(&SPIBSC->SMOPR, regset->opd[1], SPIBSC_SMOPR_OPD2_SHIFT, SPIBSC_SMOPR_OPD2);
00531         RegWwrite_32(&SPIBSC->SMOPR, regset->opd[2], SPIBSC_SMOPR_OPD1_SHIFT, SPIBSC_SMOPR_OPD1);
00532         RegWwrite_32(&SPIBSC->SMOPR, regset->opd[3], SPIBSC_SMOPR_OPD0_SHIFT, SPIBSC_SMOPR_OPD0);
00533         /* Single/Dual/Quad */
00534         RegWwrite_32(&SPIBSC->SMENR, regset->opdb, SPIBSC_SMENR_OPDB_SHIFT, SPIBSC_SMENR_OPDB);
00535     }
00536 
00537     /* ---- Dummy ---- */
00538      /* Enable/Disable */
00539      RegWwrite_32(&SPIBSC->SMENR, regset->dme, SPIBSC_SMENR_DME_SHIFT, SPIBSC_SMENR_DME);
00540      if (regset->dme != SPIBSC_DUMMY_CYC_DISABLE) {
00541          RegWwrite_32(&SPIBSC->SMDMCR, regset->dmdb, SPIBSC_SMDMCR_DMDB_SHIFT, SPIBSC_SMDMCR_DMDB);
00542          /* Dummy Cycle */
00543          RegWwrite_32(&SPIBSC->SMDMCR, regset->dmcyc, SPIBSC_SMDMCR_DMCYC_SHIFT, SPIBSC_SMDMCR_DMCYC);
00544      }
00545 
00546     /* ---- Data ---- */
00547     /* Enable/Disable */
00548     RegWwrite_32(&SPIBSC->SMENR, regset->spide, SPIBSC_SMENR_SPIDE_SHIFT, SPIBSC_SMENR_SPIDE);
00549     if (regset->spide != SPIBSC_OUTPUT_DISABLE) {
00550         if (SPIBSC_OUTPUT_SPID_8 == regset->spide) {
00551             if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00552                 SPIBSC->SMWDR0.UINT8[0] = (uint8_t)(regset->smwdr[0]);
00553             } else {
00554                 SPIBSC->SMWDR0.UINT16[0] = (uint16_t)(regset->smwdr[0]);
00555             }
00556         } else if (regset->spide == SPIBSC_OUTPUT_SPID_16) {
00557             if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00558                 SPIBSC->SMWDR0.UINT16[0] = (uint16_t)(regset->smwdr[0]);
00559             } else {
00560                 SPIBSC->SMWDR0.UINT32 = regset->smwdr[0];
00561             }
00562         } else if (regset->spide == SPIBSC_OUTPUT_SPID_32) {
00563             if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00564                 SPIBSC->SMWDR0.UINT32 = (uint32_t)(regset->smwdr[0]);
00565             } else {
00566                 SPIBSC->SMWDR0.UINT32 = (uint32_t)(regset->smwdr[0]);
00567                 SPIBSC->SMWDR1.UINT32 = (uint32_t)(regset->smwdr[1]);  /* valid in two serial-flash */
00568             }
00569         } else {
00570             /* none */
00571         }
00572 
00573         /* Single/Dual/Quad */
00574         RegWwrite_32(&SPIBSC->SMENR, regset->spidb, SPIBSC_SMENR_SPIDB_SHIFT, SPIBSC_SMENR_SPIDB);
00575     }
00576 
00577     RegWwrite_32(&SPIBSC->SMCR, regset->sslkp, SPIBSC_SMCR_SSLKP_SHIFT, SPIBSC_SMCR_SSLKP);
00578 
00579     if ((regset->spidb != SPIBSC_1BIT) && (regset->spide != SPIBSC_OUTPUT_DISABLE)) {
00580         if ((regset->spire == SPIBSC_SPIDATA_ENABLE) && (regset->spiwe == SPIBSC_SPIDATA_ENABLE)) {
00581             /* not set in same time */
00582             return false;
00583         }
00584     }
00585 
00586     RegWwrite_32(&SPIBSC->SMCR, regset->spire, SPIBSC_SMCR_SPIRE_SHIFT, SPIBSC_SMCR_SPIRE);
00587     RegWwrite_32(&SPIBSC->SMCR, regset->spiwe, SPIBSC_SMCR_SPIWE_SHIFT, SPIBSC_SMCR_SPIWE);
00588 
00589     /* SDR Transmission/DDR Transmission Setting */
00590     RegWwrite_32(&SPIBSC->SMDRENR, regset->addre, SPIBSC_SMDRENR_ADDRE_SHIFT, SPIBSC_SMDRENR_ADDRE);
00591     RegWwrite_32(&SPIBSC->SMDRENR, regset->opdre, SPIBSC_SMDRENR_OPDRE_SHIFT, SPIBSC_SMDRENR_OPDRE);
00592     RegWwrite_32(&SPIBSC->SMDRENR, regset->spidre, SPIBSC_SMDRENR_SPIDRE_SHIFT, SPIBSC_SMDRENR_SPIDRE);
00593 
00594     /* execute after setting SPNDL bit */
00595     RegWwrite_32(&SPIBSC->SMCR, SPIBSC_SPI_ENABLE, SPIBSC_SMCR_SPIE_SHIFT, SPIBSC_SMCR_SPIE);
00596 
00597     /* wait for transfer-start */
00598     while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
00599         /* wait for transfer-end */
00600     }
00601 
00602     if (SPIBSC_OUTPUT_SPID_8 == regset->spide) {
00603         if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00604             regset->smrdr[0] = SPIBSC->SMRDR0.UINT8[0];
00605         } else {
00606             regset->smrdr[0] = SPIBSC->SMRDR0.UINT16[0];        /* valid in two serial-flash  */
00607         }
00608     } else if (regset->spide == SPIBSC_OUTPUT_SPID_16) {
00609         if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00610             regset->smrdr[0] = SPIBSC->SMRDR0.UINT16[0];
00611         } else {
00612             regset->smrdr[0] = SPIBSC->SMRDR0.UINT32;           /* valid in two serial-flash  */
00613         }
00614     } else if (regset->spide == SPIBSC_OUTPUT_SPID_32) {
00615         if (RegRead_32(&SPIBSC0.CMNCR, SPIBSC_CMNCR_BSZ_SHIFT, SPIBSC_CMNCR_BSZ) == SPIBSC_CMNCR_BSZ_SINGLE) {
00616             regset->smrdr[0] = SPIBSC->SMRDR0.UINT32;
00617         } else {
00618             regset->smrdr[0] = SPIBSC->SMRDR0.UINT32;           /* valid in two serial-flash  */
00619             regset->smrdr[1] = SPIBSC->SMRDR1.UINT32;
00620         }
00621     } else {
00622         /* none */
00623     }
00624 
00625     return true;
00626 }
00627 
00628 uint32_t FlashAccess::RegRead_32(volatile uint32_t * ioreg, uint32_t shift, uint32_t mask) {
00629     uint32_t reg_value;
00630 
00631     reg_value = *ioreg;                        /* Read from register            */
00632     reg_value = (reg_value & mask) >> shift;   /* Clear other bit and Bit shift */
00633 
00634     return reg_value;
00635 }
00636 
00637 void FlashAccess::RegWwrite_32(volatile uint32_t * ioreg, uint32_t write_value, uint32_t shift, uint32_t mask) {
00638     uint32_t reg_value;
00639 
00640     reg_value = *ioreg;                                         /* Read from register */
00641     reg_value = (reg_value & (~mask)) | (write_value << shift); /* Modify value       */
00642     *ioreg    = reg_value;                                      /* Write to register  */
00643 }
00644 
00645 /** private **/
00646 
00647 void FlashAccess::change_mmu_ttbl_spibsc(uint32_t type) {
00648     uint32_t index;               /* Loop variable: table index */
00649     mmu_ttbl_desc_section_t desc; /* Loop variable: descriptor */
00650     mmu_ttbl_desc_section_t * table = (mmu_ttbl_desc_section_t *)TTB;
00651 
00652     /* ==== Modify SPI Multi-I/O bus space settings in the MMU translation table ==== */
00653     for (index = (SPIBSC_ADDR_START >> 20); index <= (SPIBSC_ADDR_END >> 20); index++) {
00654         /* Modify memory attribute descriptor */
00655         if (type == 0) {         /* Spi */
00656             desc = table[index];
00657             desc_tbl[index - (SPIBSC_ADDR_START >> 20)] = desc;
00658             desc.AP1_0 = 0x0u;   /* AP[2:0] = b'000 (No access) */
00659             desc.AP2   = 0x0u;
00660             desc.XN    = 0x1u;   /* XN = 1 (Execute never) */
00661         } else {                 /* Xip */
00662             desc = desc_tbl[index - (SPIBSC_ADDR_START >> 20)];
00663         }
00664         /* Write descriptor back to translation table */
00665         table[index] = desc;
00666     }
00667 }
00668 
00669 void FlashAccess::spibsc_stop(void) {
00670     if (((SPIBSC->DRCR & SPIBSC_DRCR_RBE)  != 0) &&
00671         ((SPIBSC->DRCR & SPIBSC_DRCR_SSLE) != 0)) {
00672         RegWwrite_32(&SPIBSC->DRCR, 1, SPIBSC_DRCR_SSLN_SHIFT, SPIBSC_DRCR_SSLN);
00673     }
00674 
00675     while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_SSLF_SHIFT, SPIBSC_CMNSR_SSLF) != SPIBSC_SSL_NEGATE) {
00676         ;
00677     }
00678 
00679     while (RegRead_32(&SPIBSC->CMNSR, SPIBSC_CMNSR_TEND_SHIFT, SPIBSC_CMNSR_TEND) != SPIBSC_TRANS_END) {
00680         ;
00681     }
00682 }
00683 
00684 #ifndef __STATIC_FORCEINLINE
00685   #if   defined ( __CC_ARM )
00686     #define __STATIC_FORCEINLINE  static __forceinline
00687   #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
00688     #define __STATIC_FORCEINLINE  __attribute__((always_inline)) static __inline
00689   #elif defined ( __GNUC__ )
00690     #define __STATIC_FORCEINLINE  __attribute__((always_inline)) static __inline
00691   #elif defined ( __ICCARM__ )
00692     #define __STATIC_FORCEINLINE  _Pragma("inline=forced") static inline
00693   #endif
00694 #endif
00695 
00696 #if   defined ( __CC_ARM )
00697 __STATIC_FORCEINLINE __ASM void L1C_CleanInvalidateCache_sforce(uint32_t op) {
00698         ARM
00699 
00700         PUSH    {R4-R11}
00701 
00702         MRC     p15, 1, R6, c0, c0, 1      // Read CLIDR
00703         ANDS    R3, R6, #0x07000000        // Extract coherency level
00704         MOV     R3, R3, LSR #23            // Total cache levels << 1
00705         BEQ     Finished                   // If 0, no need to clean
00706 
00707         MOV     R10, #0                    // R10 holds current cache level << 1
00708 Loop1   ADD     R2, R10, R10, LSR #1       // R2 holds cache "Set" position
00709         MOV     R1, R6, LSR R2             // Bottom 3 bits are the Cache-type for this level
00710         AND     R1, R1, #7                 // Isolate those lower 3 bits
00711         CMP     R1, #2
00712         BLT     Skip                       // No cache or only instruction cache at this level
00713 
00714         MCR     p15, 2, R10, c0, c0, 0     // Write the Cache Size selection register
00715         ISB                                // ISB to sync the change to the CacheSizeID reg
00716         MRC     p15, 1, R1, c0, c0, 0      // Reads current Cache Size ID register
00717         AND     R2, R1, #7                 // Extract the line length field
00718         ADD     R2, R2, #4                 // Add 4 for the line length offset (log2 16 bytes)
00719         LDR     R4, =0x3FF
00720         ANDS    R4, R4, R1, LSR #3         // R4 is the max number on the way size (right aligned)
00721         CLZ     R5, R4                     // R5 is the bit position of the way size increment
00722         LDR     R7, =0x7FFF
00723         ANDS    R7, R7, R1, LSR #13        // R7 is the max number of the index size (right aligned)
00724 
00725 Loop2   MOV     R9, R4                     // R9 working copy of the max way size (right aligned)
00726 
00727 Loop3   ORR     R11, R10, R9, LSL R5       // Factor in the Way number and cache number into R11
00728         ORR     R11, R11, R7, LSL R2       // Factor in the Set number
00729         CMP     R0, #0
00730         BNE     Dccsw
00731         MCR     p15, 0, R11, c7, c6, 2     // DCISW. Invalidate by Set/Way
00732         B       cont
00733 Dccsw   CMP     R0, #1
00734         BNE     Dccisw
00735         MCR     p15, 0, R11, c7, c10, 2    // DCCSW. Clean by Set/Way
00736         B       cont
00737 Dccisw  MCR     p15, 0, R11, c7, c14, 2    // DCCISW. Clean and Invalidate by Set/Way
00738 cont    SUBS    R9, R9, #1                 // Decrement the Way number
00739         BGE     Loop3
00740         SUBS    R7, R7, #1                 // Decrement the Set number
00741         BGE     Loop2
00742 Skip    ADD     R10, R10, #2               // Increment the cache number
00743         CMP     R3, R10
00744         BGT     Loop1
00745 
00746 Finished
00747         DSB
00748         POP    {R4-R11}
00749         BX     lr
00750 }
00751 
00752 #elif (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) || defined ( __GNUC__ )
00753 __STATIC_FORCEINLINE void L1C_CleanInvalidateCache_sforce(uint32_t op) {
00754   __ASM volatile(
00755     "        PUSH    {R4-R11}                   \n"
00756 
00757     "        MRC     p15, 1, R6, c0, c0, 1      \n" // Read CLIDR
00758     "        ANDS    R3, R6, #0x07000000        \n" // Extract coherency level
00759     "        MOV     R3, R3, LSR #23            \n" // Total cache levels << 1
00760     "        BEQ     Finished                   \n" // If 0, no need to clean
00761 
00762     "        MOV     R10, #0                    \n" // R10 holds current cache level << 1
00763     "Loop1:  ADD     R2, R10, R10, LSR #1       \n" // R2 holds cache "Set" position
00764     "        MOV     R1, R6, LSR R2             \n" // Bottom 3 bits are the Cache-type for this level
00765     "        AND     R1, R1, #7                 \n" // Isolate those lower 3 bits
00766     "        CMP     R1, #2                     \n"
00767     "        BLT     Skip                       \n" // No cache or only instruction cache at this level
00768 
00769     "        MCR     p15, 2, R10, c0, c0, 0     \n" // Write the Cache Size selection register
00770     "        ISB                                \n" // ISB to sync the change to the CacheSizeID reg
00771     "        MRC     p15, 1, R1, c0, c0, 0      \n" // Reads current Cache Size ID register
00772     "        AND     R2, R1, #7                 \n" // Extract the line length field
00773     "        ADD     R2, R2, #4                 \n" // Add 4 for the line length offset (log2 16 bytes)
00774     "        LDR     R4, =0x3FF                 \n"
00775     "        ANDS    R4, R4, R1, LSR #3         \n" // R4 is the max number on the way size (right aligned)
00776     "        CLZ     R5, R4                     \n" // R5 is the bit position of the way size increment
00777     "        LDR     R7, =0x7FFF                \n"
00778     "        ANDS    R7, R7, R1, LSR #13        \n" // R7 is the max number of the index size (right aligned)
00779 
00780     "Loop2:  MOV     R9, R4                     \n" // R9 working copy of the max way size (right aligned)
00781 
00782     "Loop3:  ORR     R11, R10, R9, LSL R5       \n" // Factor in the Way number and cache number into R11
00783     "        ORR     R11, R11, R7, LSL R2       \n" // Factor in the Set number
00784     "        CMP     R0, #0                     \n"
00785     "        BNE     Dccsw                      \n"
00786     "        MCR     p15, 0, R11, c7, c6, 2     \n" // DCISW. Invalidate by Set/Way
00787     "        B       cont                       \n"
00788     "Dccsw:  CMP     R0, #1                     \n"
00789     "        BNE     Dccisw                     \n"
00790     "        MCR     p15, 0, R11, c7, c10, 2    \n" // DCCSW. Clean by Set/Way
00791     "        B       cont                       \n"
00792     "Dccisw: MCR     p15, 0, R11, c7, c14, 2    \n" // DCCISW. Clean and Invalidate by Set/Way
00793     "cont:   SUBS    R9, R9, #1                 \n" // Decrement the Way number
00794     "        BGE     Loop3                      \n"
00795     "        SUBS    R7, R7, #1                 \n" // Decrement the Set number
00796     "        BGE     Loop2                      \n"
00797     "Skip:   ADD     R10, R10, #2               \n" // Increment the cache number
00798     "        CMP     R3, R10                    \n"
00799     "        BGT     Loop1                      \n"
00800 
00801     "Finished:                                  \n"
00802     "        DSB                                \n"
00803     "        POP    {R4-R11}                      "
00804   );
00805 }
00806 
00807 #else
00808 __STATIC_FORCEINLINE void __L1C_MaintainDCacheSetWay_sforce(uint32_t level, uint32_t maint) {
00809     register volatile uint32_t Dummy;
00810     register volatile uint32_t ccsidr;
00811     uint32_t num_sets;
00812     uint32_t num_ways;
00813     uint32_t shift_way;
00814     uint32_t log2_linesize;
00815     uint32_t log2_num_ways;
00816 
00817     Dummy = level << 1;
00818     /* set csselr, select ccsidr register */
00819     __set_CCSIDR(Dummy);
00820     /* get current ccsidr register */
00821     ccsidr = __get_CCSIDR();
00822     num_sets = ((ccsidr & 0x0FFFE000) >> 13) + 1;
00823     num_ways = ((ccsidr & 0x00001FF8) >> 3) + 1;
00824     log2_linesize = (ccsidr & 0x00000007) + 2 + 2;
00825     log2_num_ways = log2_up(num_ways);
00826     shift_way = 32 - log2_num_ways;
00827     for (int way = num_ways-1; way >= 0; way--) {
00828         for (int set = num_sets-1; set >= 0; set--) {
00829             Dummy = (level << 1) | (set << log2_linesize) | (way << shift_way);
00830             switch (maint) {
00831                 case 0:
00832                     // DCISW. Invalidate by Set/Way
00833                     __ASM volatile("MCR p15, 0, %0, c7, c6, 2" : : "r"(Dummy) : "memory");
00834                     break;
00835                 case 1:
00836                     // DCCSW. Clean by Set/Way
00837                     __ASM volatile("MCR p15, 0, %0, c7, c10, 2" : : "r"(Dummy) : "memory");
00838                     break;
00839                 default:
00840                     // DCCISW. Clean and Invalidate by Set/Way
00841                     __ASM volatile("MCR p15, 0, %0, c7, c14, 2" : : "r"(Dummy) : "memory");
00842                     break;
00843             }
00844         }
00845     }
00846     __DMB();
00847 }
00848 
00849 __STATIC_FORCEINLINE void L1C_CleanInvalidateCache_sforce(uint32_t op) {
00850     register volatile uint32_t clidr;
00851     uint32_t cache_type;
00852     clidr =  __get_CLIDR();
00853     for (uint32_t i = 0; i<7; i++) {
00854         cache_type = (clidr >> i*3) & 0x7UL;
00855         if ((cache_type >= 2) && (cache_type <= 4)) {
00856             __L1C_MaintainDCacheSetWay_sforce(i, op);
00857         }
00858     }
00859 }
00860 #endif
00861 
00862 #ifdef MBED_VERSION
00863 
00864 void FlashAccess::cache_control(void) {
00865     unsigned int assoc;
00866 
00867     /* ==== Cleaning and invalidation of the L1 data cache ==== */
00868     L1C_CleanInvalidateCache_sforce(2);
00869     __DSB();
00870 
00871     /* ==== Cleaning and invalidation of the L2 cache ==== */
00872     if (PL310->AUX_CNT & (1<<16)) {
00873         assoc = 16;
00874     } else {
00875         assoc =  8;
00876     }
00877     PL310->INV_WAY = (1 << assoc) - 1;
00878     while(PL310->INV_WAY & ((1 << assoc) - 1)); // poll invalidate
00879     PL310->CACHE_SYNC = 0x0;
00880 
00881     /* ==== Invalidate all TLB entries ==== */
00882     __ca9u_inv_tlb_all();
00883 
00884     /* ==== Invalidate the L1 instruction cache ==== */
00885     __v7_inv_icache_all();
00886     __DSB();
00887     __ISB();
00888 }
00889 
00890 #else  // mbed-os 5.6.4
00891 
00892 void FlashAccess::cache_control(void) {
00893     unsigned int assoc;
00894 
00895     /* ==== Cleaning and invalidation of the L1 data cache ==== */
00896     L1C_CleanInvalidateCache_sforce(2);
00897     __DSB();
00898 
00899     /* ==== Cleaning and invalidation of the L2 cache ==== */
00900     if (L2C_310->AUX_CNT & (1U << 16U)) {
00901         assoc = 16U;
00902     } else {
00903         assoc =  8U;
00904     }
00905     L2C_310->CLEAN_INV_WAY = (1U << assoc) - 1U;
00906     while (L2C_310->CLEAN_INV_WAY & ((1U << assoc) - 1U)); // poll invalidate
00907     L2C_310->CACHE_SYNC = 0x0;
00908 
00909     /* ==== Invalidate all TLB entries ==== */
00910     __set_TLBIALL(0);
00911     __DSB();     // ensure completion of the invalidation
00912     __ISB();     // ensure instruction fetch path sees new state
00913 
00914     /* ==== Invalidate the L1 instruction cache ==== */
00915     __set_ICIALLU(0);
00916     __DSB();     // ensure completion of the invalidation
00917     __ISB();     // ensure instruction fetch path sees new I cache state
00918 }
00919 #endif