blob: 38e6eb07d271668994e114f7f6a7e7eb4643bf59 [file] [log] [blame]
/**
* \addtogroup BSP
* \{
* \addtogroup SYSTEM
* \{
* \addtogroup MEMORY
*
* \{
*/
/**
****************************************************************************************
*
* @file qspi_winbond.h
*
* @brief QSPI flash driver for Winbond flashes - common code
*
* Copyright (c) 2016, Dialog Semiconductor
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
****************************************************************************************
*/
#ifndef _QSPI_WINBOND_H_
#define _QSPI_WINBOND_H_
#define WINBOND_ID 0xEF
#if (FLASH_AUTODETECT == 1) || (dg_configFLASH_MANUFACTURER_ID == WINBOND_ID)
#include "qspi_common.h"
#define W25Q_ERASE_PROGRAM_SUSPEND 0x75
#define W25Q_ERASE_PROGRAM_RESUME 0x7A
#define W25Q_WRITE_STATUS_REGISTER2 0x31
#define W25Q_PAGE_PROGRAM 0x02
#define W25Q_WRITE_ENABLE_NON_VOL 0x50
#define W25Q_READ_STATUS_REGISTER2 0x35
#define W25Q_BLOCK_ERASE_64K 0xD8
#define W25Q_FAST_READ_QPI 0x0B
#define W25Q_READ_DEVICE_ID_SINGLE 0x90 // Requires single mode for the command entry!
#define W25Q_READ_DEVICE_ID_DUAL 0x92 // Requires dual mode for the command entry!
#define W25Q_READ_DEVICE_ID_QUAD 0x94
#define W25Q_READ_UNIQUE_ID 0x4B // Requires single mode for the command entry!
#define W25Q_READ_SFDP_REG 0x5A // Requires single mode for the command entry!
#define W25Q_ERASE_SECURITY_REGS 0x44 // Requires single mode for the command entry!
#define W25Q_PROGR_SECURITY_REGS 0x42 // Requires single mode for the command entry!
#define W25Q_READ_SECURITY_REGS 0x48 // Requires single mode for the command entry!
#define W25Q_ENTER_QPI_MODE 0x38 // Requires single mode for the command entry!
#define W25Q_EXIT_QPI_MODE 0xFF // Requires quad mode for the command entry!
/* Suspend */
#define W25Q_STATUS2_SUS_BIT 7
#define W25Q_STATUS2_SUS_MASK (1 << W25Q_STATUS2_SUS_BIT)
/* QPI Enable */
#define W25Q_STATUS2_QE_BIT 1
#define W25Q_STATUS2_QE_MASK (1 << W25Q_STATUS2_QE_BIT)
// Flash power up/down timings
#define W25Q_POWER_DOWN_DELAY_US 3
#define W25Q_RELEASE_POWER_DOWN_DELAY_US 3
#define W25Q_POWER_UP_DELAY_US 10
#if (dg_configFLASH_POWER_OFF == 1)
/**
* \brief uCode for handling the QSPI FLASH activation from power off.
*/
/*
* Should work with all Winbond flashes -- verified with W25Q80EW.
*
* Delay 10usec
* 0x01 // CMD_NBYTES = 0, CMD_TX_MD = 0 (Single), CMD_VALID = 1
* 0xA0 // CMD_WT_CNT_LS = 160 --> 10000 / 62.5 = 160 = 10usec
* 0x00 // CMD_WT_CNT_MS = 0
* Exit from Fast Read mode
* 0x09 // CMD_NBYTES = 1, CMD_TX_MD = 0 (Single), CMD_VALID = 1
* 0x00 // CMD_WT_CNT_LS = 0
* 0x00 // CMD_WT_CNT_MS = 0
* 0xFF // Enable Reset
* (up to 16 words)
*/
const uint32_t w25q_ucode_wakeup[] = {
0x09000001 | (((uint16_t)(W25Q_POWER_UP_DELAY_US*1000/62.5) & 0xFFFF) << 8),
0x00FF0000,
};
#elif (dg_configFLASH_POWER_DOWN == 1)
/**
* \brief uCode for handling the QSPI FLASH release from power-down.
*/
/*
* Should work with all Winbond flashes -- verified with W25Q80EW.
*
* 0x09 // CMD_NBYTES = 1, CMD_TX_MD = 0 (Single), CMD_VALID = 1
* 0x30 // CMD_WT_CNT_LS = 3000 / 62.5 = 48 // 3usec
* 0x00 // CMD_WT_CNT_MS = 0
* 0xAB // Release Power Down
* (up to 16 words)
*/
const uint32_t w25q_ucode_wakeup[] = {
0xAB000009 | (((uint16_t)(W25Q_RELEASE_POWER_DOWN_DELAY_US*1000/62.5) & 0xFFFF) << 8),
};
#else
/**
* \brief uCode for handling the QSPI FLASH exit from the "Continuous Read Mode".
*/
/*
* Should work with all Winbond flashes -- verified with W25Q80EW.
*
* 0x25 // CMD_NBYTES = 4, CMD_TX_MD = 2 (Quad), CMD_VALID = 1
* 0x00 // CMD_WT_CNT_LS = 0
* 0x00 // CMD_WT_CNT_MS = 0
* 0x55 // Clocks 0-1 (A23-16)
* 0x55 // Clocks 2-3 (A15-8)
* 0x55 // Clocks 4-5 (A7-0)
* 0x55 // Clocks 6-7 (M7-0) : M5-4 != '10' ==> Disable "Continuous Read Mode"
* (up to 16 words)
*/
const uint32_t w25q_ucode_wakeup[] = {
0x55000025,
0x00555555,
};
#endif
static bool flash_w25q_is_suspended(void);
static void flash_w25q_initialize(uint8_t device_type, uint8_t device_density);
static void flash_w25q_deactivate_command_entry_mode(void);
/**
* \brief Enable volatile writes to Status Register bits
* \details When this command is issued, any writes to any of the Status Registers of the Flash are
* done as volatile writes. This command is valid only when the Write Status Register command
* follows.
*
* \note This function blocks until the Flash has processed the command.
*/
QSPI_SECTION __attribute__((unused)) static inline void flash_w25q_wre_volatile(void)
{
uint8_t cmd[] = { W25Q_WRITE_ENABLE_NON_VOL };
qspi_write(cmd, 1);
/* Verify */
while (flash_is_busy());
}
QSPI_SECTION __attribute__((unused)) static inline uint8_t flash_w25q_read_status_register_2(void)
{
__DBG_QSPI_VOLATILE__ uint8_t status;
uint8_t cmd[] = { W25Q_READ_STATUS_REGISTER2 };
qspi_transact(cmd, 1, &status, 1);
return status;
}
/**
* \brief Write the Status Register 2 of the Flash
*
* \param[in] value The value to be written.
*
* \note This function blocks until the Flash has processed the command. No verification that the
* value has been actually written is done though. It is up to the caller to decide whether
* such verification is needed or not and execute it on its own.
*/
QSPI_SECTION __attribute__((unused)) static inline void flash_w25q_write_status_register_2(uint8_t value)
{
uint8_t cmd[] = { W25Q_WRITE_STATUS_REGISTER2, value };
qspi_write(cmd, 2);
/* Wait for the Flash to process the command */
while (flash_is_busy());
}
QSPI_SECTION static inline void flash_w25q_enable_quad_mode(void)
{
uint8_t status;
status = flash_w25q_read_status_register_2();
if (!(status & W25Q_STATUS2_QE_MASK)) {
flash_write_enable();
flash_w25q_write_status_register_2(status | W25Q_STATUS2_QE_MASK);
}
}
QSPI_SECTION static bool flash_w25q_is_suspended(void)
{
__DBG_QSPI_VOLATILE__ uint8_t status;
status = flash_w25q_read_status_register_2();
return (status & W25Q_STATUS2_SUS_MASK) != 0;
}
QSPI_SECTION static void flash_w25q_initialize(uint8_t device_type, uint8_t device_density)
{
flash_activate_command_entry_mode();
flash_w25q_enable_quad_mode();
flash_deactivate_command_entry_mode();
}
QSPI_SECTION static void flash_w25q_deactivate_command_entry_mode(void)
{
}
#endif
#endif /* _QSPI_WINBOND_H_ */
/**
* \}
* \}
* \}
*/