blob: 33cfd067baee8071cb0b571f1c24ce9c165582ec [file] [log] [blame]
/*
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "app.h"
#include "board.h"
#include "fsl_debug_console.h"
#include "fsl_qspi.h"
#include "fsl_common.h"
#include "pin_mux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define DUMMY_MASTER (0xE)
/*******************************************************************************
* Prototypes
******************************************************************************/
extern void qspi_nor_flash_init(QuadSPI_Type *base);
#if defined(FLASH_ENABLE_QUAD_CMD)
extern void enable_quad_mode(void);
#endif
#if defined(FLASH_ENABLE_OCTAL_CMD)
extern void enable_octal_mode(void);
#endif
extern void erase_sector(uint32_t addr);
extern void erase_all(void);
extern void program_page(uint32_t dest_addr, uint32_t *src_addr);
extern void BOARD_SetQspiClock(QuadSPI_Type *qspi, uint32_t qspiClockSrc, uint32_t divider);
/*******************************************************************************
* Variables
******************************************************************************/
static uint32_t buff[64]; /* Test data */
#if !defined(FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL) || (!FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL)
static bool isDivNeedRestore = false;
#endif
/*******************************************************************************
* Code
******************************************************************************/
uint32_t lut[FSL_FEATURE_QSPI_LUT_DEPTH] =
{/* Seq0 :Quad Read */
/* CMD: 0x6B - Quad Read, Single pad */
/* ADDR: 0x18 - 24bit address, Single pads */
/* DUMMY: 0x06 - 8 clock cyles, Quad pads */
/* READ: 0x80 - Read 128 bytes, Quad pads */
/* JUMP_ON_CS: 0 */
[0] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x6B, QSPI_ADDR, QSPI_PAD_1, 0x18),
[1] = QSPI_LUT_SEQ(QSPI_DUMMY, QSPI_PAD_4, 0x08, QSPI_READ, QSPI_PAD_4, 0x80),
[2] = QSPI_LUT_SEQ(QSPI_JMP_ON_CS, QSPI_PAD_1, 0x0, 0, 0, 0),
/* Seq1: Write Enable */
/* CMD: 0x06 - Write Enable, Single pad */
[4] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x06, 0, 0, 0),
/* Seq2: Erase All */
/* CMD: 0x60 - Erase All chip, Single pad */
[8] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x60, 0, 0, 0),
/* Seq3: Read Status */
/* CMD: 0x05 - Read Status, single pad */
/* READ: 0x01 - Read 1 byte */
[12] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x05, QSPI_READ, QSPI_PAD_1, 0x1),
/* Seq4: Page Program */
/* CMD: 0x02 - Page Program, Single pad */
/* ADDR: 0x18 - 24bit address, Quad pad */
/* WRITE: 0x80 - Write 128 bytes at one pass, Quad pad */
[16] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x38, QSPI_ADDR, QSPI_PAD_4, 0x18),
[17] = QSPI_LUT_SEQ(QSPI_WRITE, QSPI_PAD_4, 0x80, 0, 0, 0),
/* Seq5: Write Register */
/* CMD: 0x01 - Write Status Register, single pad */
/* WRITE: 0x01 - Write 1 byte of data, single pad */
[20] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x61, QSPI_WRITE, QSPI_PAD_1, 0x1),
/* Seq6: Read Config Register */
/* CMD: 0x15 - Read Config register, single pad */
/* READ: 0x01 - Read 1 byte */
[24] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0x15, QSPI_READ, QSPI_PAD_1, 0x1),
/* Seq7: Erase Sector */
/* CMD: 0x20 - Sector Erase, single pad */
/* ADDR: 0x18 - 24 bit address, single pad */
[28] = QSPI_LUT_SEQ(QSPI_CMD, QSPI_PAD_1, 0xD8, QSPI_ADDR, QSPI_PAD_1, 0x18),
/* Match MISRA rule */
[63] = 0};
qspi_flash_config_t single_config = {.flashA1Size = FLASH_SIZE, /* 4MB */
.flashA2Size = 0,
#if defined(FSL_FEATURE_QSPI_SUPPORT_PARALLEL_MODE) && (FSL_FEATURE_QSPI_SUPPORT_PARALLEL_MODE)
.flashB1Size = FLASH_SIZE,
.flashB2Size = 0,
#endif
#if !defined(FSL_FEATURE_QSPI_HAS_NO_TDH) || (!FSL_FEATURE_QSPI_HAS_NO_TDH)
.dataHoldTime = 0,
#endif
.CSHoldTime = 0,
.CSSetupTime = 0,
.cloumnspace = 0,
.dataLearnValue = 0,
.endian = kQSPI_64LittleEndian,
.enableWordAddress = false};
/* Use QSPI polling way to program serial flash */
void qspi_polling(void)
{
uint32_t i = 0;
uint32_t err = 0;
uint32_t addr = 0;
#if !defined(QSPI_ERASE_ADDR_OFFSET)
addr = FSL_FEATURE_QSPI_AMBA_BASE;
#else
addr = FSL_FEATURE_QSPI_AMBA_BASE + QSPI_ERASE_ADDR_OFFSET;
#endif
erase_sector(addr);
PRINTF("Erase finished!\r\n");
#if !defined(FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL) || (!FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL)
/* Reduce frequency while clock divder is less than 2 */
uint8_t qspiClockDiv = ((EXAMPLE_QSPI->MCR & QuadSPI_MCR_SCLKCFG_MASK) >> QuadSPI_MCR_SCLKCFG_SHIFT) + 1U;
if (qspiClockDiv == 1U)
{
/* Reduce the frequency */
isDivNeedRestore = true;
QSPI_Enable(EXAMPLE_QSPI, false);
EXAMPLE_QSPI->MCR &= ~QuadSPI_MCR_SCLKCFG_MASK;
EXAMPLE_QSPI->MCR |= QuadSPI_MCR_SCLKCFG(1U);
QSPI_Enable(EXAMPLE_QSPI, true);
}
#endif
#if defined(FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE)
BOARD_SetQspiClock(EXAMPLE_QSPI, CLKCTL0_OSPIFCLKSEL_SEL(0), 10);
#endif
/* Program pages in a sector */
for (i = 0; i < FLASH_SECTORE_SIZE / FLASH_PAGE_SIZE; i++)
{
program_page(addr + i * FLASH_PAGE_SIZE, buff);
}
PRINTF("Program data finished!\r\n");
#if !defined(FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL) || (!FSL_FEATURE_QSPI_CLOCK_CONTROL_EXTERNAL)
/* Restore the frequency if needed */
if (isDivNeedRestore)
{
QSPI_Enable(EXAMPLE_QSPI, false);
EXAMPLE_QSPI->MCR &= ~QuadSPI_MCR_SCLKCFG_MASK;
EXAMPLE_QSPI->MCR |= QuadSPI_MCR_SCLKCFG(0U);
QSPI_Enable(EXAMPLE_QSPI, true);
}
#endif
#if defined(FLASH_NEED_DQS)
#if defined(FSL_SDK_DRIVER_QUICK_ACCESS_ENABLE)
BOARD_SetQspiClock(EXAMPLE_QSPI, CLKCTL0_OSPIFCLKSEL_SEL(0), 2);
#else
/* Re-configure QSPI Serial clock frequency in order to acheive high performance. */
QSPI_ClockUpdate(EXAMPLE_QSPI);
#endif
#endif
for (i = 0; i < FLASH_SECTORE_SIZE / 4; i++)
{
if (((uint32_t *)addr)[i] != buff[i % 64])
{
PRINTF("The data in %d is wrong!!\r\n", i);
PRINTF("The flash value in %d is %d\r\n", i, ((uint32_t *)addr)[i]);
err++;
}
}
if (err == 0)
{
PRINTF("Program through QSPI polling succeed!\r\n");
}
}
int main(void)
{
uint32_t i = 0;
/* Board specific RDC settings */
BOARD_RdcInit();
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitMemory();
CLOCK_SetRootMux(kCLOCK_RootQspi, kCLOCK_QspiRootmuxSysPll1Div8); /* Set QSPI source to SYSTEM PLL1 DIV8 100MHZ */
CLOCK_SetRootDivider(kCLOCK_RootQspi, 1U, 2U); /* Set root clock to 100MHZ / 2 = 50MHZ */
/*Enable QSPI clock */
PRINTF("QSPI example started!\r\n");
/* Copy the LUT table */
memcpy(single_config.lookuptable, lut, sizeof(lut));
qspi_nor_flash_init(EXAMPLE_QSPI);
/*Initialize data buffer */
for (i = 0; i < 64; i++)
{
buff[i] = i;
}
#if defined(FLASH_ENABLE_QUAD_CMD)
/* Enable Quad mode for the flash */
enable_quad_mode();
#endif
#if defined(FLASH_ENABLE_OCTAL_CMD)
enable_ddr_mode();
/* Enable Octal mode for the flash */
enable_octal_mode();
#endif
/* Use polling to program flash. */
qspi_polling();
while (1)
{
}
}