* arch/arm/src/phy62xx/flash.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* @file flash.c
* @brief Contains all functions support for flash driver
* @version 0.0
* @date 27. Nov. 2017
* @author qing.han
****************************************************************************/
* Included Files
****************************************************************************/
#include "rom_sym_def.h"
#include <string.h>
#include "types.h"
#include "flash.h"
#include "log.h"
#include "pwrmgr.h"
#include "error.h"
#define SPIF_WAIT_IDLE_CYC (32)
#define SPIF_STATUS_WAIT_IDLE(n) \
do \
{ \
while ((AP_SPIF->fcmd &0x02)==0x02) \
{ \
volatile int delay_cycle = n; \
while (delay_cycle--){;} \
} \
while ((AP_SPIF->config & 0x80000000) == 0);\
} while (0);
#define HAL_CACHE_ENTER_BYPASS_SECTION() do{ \
_HAL_CS_ALLOC_();\
HAL_ENTER_CRITICAL_SECTION();\
AP_CACHE->CTRL0 = 0x02; \
AP_PCR->CACHE_RST = 0x02;\
AP_PCR->CACHE_BYPASS = 1; \
HAL_EXIT_CRITICAL_SECTION();\
}while(0);
#define HAL_CACHE_EXIT_BYPASS_SECTION() do{ \
_HAL_CS_ALLOC_();\
HAL_ENTER_CRITICAL_SECTION();\
AP_CACHE->CTRL0 = 0x00;\
AP_PCR->CACHE_RST = 0x03;\
AP_PCR->CACHE_BYPASS = 0;\
HAL_EXIT_CRITICAL_SECTION();\
}while(0);
#define spif_wait_nobusy(flg, tout_ns, return_val) {if(_spif_wait_nobusy_x(flg, tout_ns)){if(return_val){ return return_val;}}}
static xflash_Ctx_t s_xflashCtx =
{
.spif_ref_clk = SYS_CLK_DLL_64M,
.rd_instr = XFRD_FCMD_READ_DUAL
};
chipMAddr_t g_chipMAddr;
static void hal_cache_tag_flush(void);
* Private Functions
****************************************************************************/
static void __RAMRUN hal_cache_tag_flush(void)
{
_HAL_CS_ALLOC_();
HAL_ENTER_CRITICAL_SECTION();
uint32_t cb = AP_PCR->CACHE_BYPASS;
volatile int dly = 8;
if (cb == 0)
{
AP_PCR->CACHE_BYPASS = 1;
}
AP_CACHE->CTRL0 = 0x02;
while (dly--)
{
}
AP_CACHE->CTRL0 = 0x03;
dly = 8;
while (dly--)
{
}
AP_CACHE->CTRL0 = 0x00;
if (cb == 0)
{
AP_PCR->CACHE_BYPASS = 0;
}
HAL_EXIT_CRITICAL_SECTION();
}
static uint8_t __RAMRUN _spif_read_status_reg_x(void)
{
uint8_t status;
spif_cmd(FCMD_RDST, 0, 2, 0, 0, 0);
SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC);
spif_rddata(&status, 1);
return status;
}
static int __RAMRUN _spif_wait_nobusy_x(uint8_t flg, uint32_t tout_ns)
{
uint8_t status;
volatile int tout = (int)(tout_ns);
for (; tout ; tout--)
{
status = _spif_read_status_reg_x();
if ((status & flg) == 0)
return PPlus_SUCCESS;
WaitRTCCount(5);
}
return PPlus_ERR_BUSY;
}
void __RAMRUN hal_spif_init(void)
{
*(volatile uint32_t *) 0x4000c804 = 0x801003b;
return;
#if 0
* enable qspi(divisor 12)
*/
*(volatile uint32_t *) 0x4000c890 = 0x6000001;
* config flash: Write Enable for Volatile Status Reg 50h
*/
*(volatile uint32_t *) 0x4000c8a8 = 0x200;
*(volatile uint32_t *) 0x4000c890 = 0x1009001;
while ((tmp & 2) != 0x2)
{
*(int *) 0x4000c890 = 0x35900001;
tmp = *(uint32_t *) 0x4000c8a0;
}
*(volatile uint32_t *) 0x4000c828 = 0x10;
*(volatile uint32_t *) 0x4000c804 = 0x41220eb;
return;
while (1)
{
if (AP_SPIF->config & BIT(31))
{
WaitUs(1);
break;
}
}
#endif
}
void __RAMRUN hal_cache_init(void)
{
volatile int dly = 100;
hal_spif_init();
hal_clk_gate_enable(MOD_HCLK_CACHE);
hal_clk_gate_enable(MOD_PCLK_CACHE);
AP_PCR->CACHE_RST = 0x02;
while (dly--)
{
}
AP_PCR->CACHE_RST = 0x03;
hal_cache_tag_flush();
AP_PCR->CACHE_BYPASS = 0;
}
static void __RAMRUN hw_spif_cache_config(void)
{
spif_config(s_xflashCtx.spif_ref_clk, 1, s_xflashCtx.rd_instr, 0, 0);
AP_SPIF->wr_completion_ctrl = 0xff010005;
NVIC_DisableIRQ(SPIF_IRQn);
NVIC_SetPriority((IRQn_Type)SPIF_IRQn, IRQ_PRIO_HAL);
hal_cache_init();
}
int __RAMRUN hal_spif_cache_init(xflash_Ctx_t cfg)
{
hw_spif_cache_config();
hal_pwrmgr_register(MOD_SPIF, NULL, hw_spif_cache_config);
return PPlus_SUCCESS;
}
int __RAMRUN hal_flash_read(uint32_t addr, uint8_t *data, uint32_t size)
{
volatile uint8_t *u8_spif_addr = (volatile uint8_t *)
((addr & 0x7ffff) | FLASH_BASE_ADDR);
#if(SPIF_FLASH_SIZE == FLASH_SIZE_1MB)
uint32_t remap = addr & 0xf80000;
if (remap)
{
AP_SPIF->remap = remap;
AP_SPIF->config |= 0x10000;
}
#endif
HAL_CACHE_ENTER_BYPASS_SECTION();
for (int i = 0; i < size; i++)
data[i] = u8_spif_addr[i];
HAL_CACHE_EXIT_BYPASS_SECTION();
#if(SPIF_FLASH_SIZE == FLASH_SIZE_1MB)
if (remap)
{
AP_SPIF->remap = 0;
AP_SPIF->config &= ~0x10000ul;
}
#endif
return PPlus_SUCCESS;
}
int __RAMRUN hal_flash_write(uint32_t addr, uint8_t *data, uint32_t size)
{
uint8_t retval;
HAL_CACHE_ENTER_BYPASS_SECTION();
SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC);
spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY);
retval = spif_write(addr, data, size);
SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC);
spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY);
HAL_CACHE_EXIT_BYPASS_SECTION();
return retval;
}
int __RAMRUN hal_flash_erase_sector(unsigned int addr)
{
uint8_t retval;
uint32_t cb = AP_PCR->CACHE_BYPASS;
HAL_CACHE_ENTER_BYPASS_SECTION();
SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC);
spif_wait_nobusy(SFLG_WIP, SPIF_TIMEOUT, PPlus_ERR_BUSY);
retval = spif_erase_sector(addr);
SPIF_STATUS_WAIT_IDLE(SPIF_WAIT_IDLE_CYC);
spif_wait_nobusy(SFLG_WELWIP, SPIF_TIMEOUT, PPlus_ERR_BUSY);
HAL_CACHE_EXIT_BYPASS_SECTION();
if (cb == 0)
{
hal_cache_tag_flush();
}
return retval;
}
int __RAMRUN flash_write_word(unsigned int offset, uint32_t value)
{
uint32_t temp = value;
offset &= 0x00ffffff;
return (hal_flash_write (offset, (uint8_t *) &temp, 4));
}