blob: 8d378b550477f3936af34e9a1c63f06ea169fe01 [file] [log] [blame]
/*
* Copyright 2021-2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "board.h"
#include "fsl_cache.h"
#include "fsl_clock.h"
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "fsl_flexspi.h"
#include "fsl_io_mux.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define BOARD_FLEXSPI_DLL_LOCK_RETRY (10)
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/* Initialize debug console. */
void BOARD_InitDebugConsole(void)
{
uint32_t uartClkSrcFreq = 0;
/* attach FRG0 clock to FLEXCOMM3 (debug console) */
CLOCK_SetFRGClock(BOARD_DEBUG_UART_FRG_CLK);
CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
uartClkSrcFreq = BOARD_DEBUG_UART_CLK_FREQ;
DbgConsole_Init(BOARD_DEBUG_UART_INSTANCE, BOARD_DEBUG_UART_BAUDRATE, BOARD_DEBUG_UART_TYPE, uartClkSrcFreq);
}
static status_t flexspi_hyper_ram_read_id(FLEXSPI_Type * base, uint16_t * buffer)
{
flexspi_transfer_t flashXfer;
status_t status;
/* Write data */
flashXfer.deviceAddress = 0x00;
flashXfer.port = kFLEXSPI_PortB1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = 15;
flashXfer.data = (uint32_t *) buffer;
flashXfer.dataSize = 2;
status = FLEXSPI_TransferBlocking(base, &flashXfer);
return status;
}
static status_t flexspi_hyper_ram_read_register(FLEXSPI_Type * base, uint32_t address, uint16_t * buffer)
{
flexspi_transfer_t flashXfer;
status_t status;
/* Write data */
flashXfer.deviceAddress = address;
flashXfer.port = kFLEXSPI_PortB1;
flashXfer.cmdType = kFLEXSPI_Read;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = 13;
flashXfer.data = (uint32_t *) buffer;
flashXfer.dataSize = 2;
status = FLEXSPI_TransferBlocking(base, &flashXfer);
return status;
}
static status_t flexspi_hyper_ram_write_register(FLEXSPI_Type * base, uint32_t address, uint16_t * buffer)
{
flexspi_transfer_t flashXfer;
status_t status;
/* Write data */
flashXfer.deviceAddress = address;
flashXfer.port = kFLEXSPI_PortB1;
flashXfer.cmdType = kFLEXSPI_Write;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = 14;
flashXfer.data = (uint32_t *) buffer;
flashXfer.dataSize = 2;
status = FLEXSPI_TransferBlocking(base, &flashXfer);
return status;
}
/* Initialize psram. */
status_t BOARD_InitPsRam(void)
{
flexspi_device_config_t deviceconfig = {
.flexspiRootClk = 320000000, /* 320MHZ SPI serial clock, DDR serial clock 160M */
.isSck2Enabled = false,
.flashSize = 0x1000, /* 32Mb/KByte */
.addressShift = true,
.CSIntervalUnit = kFLEXSPI_CsIntervalUnit1SckCycle,
.CSInterval = 5,
.CSHoldTime = 2,
.CSSetupTime = 3,
.dataValidTime = 1,
.columnspace = 9 + 5, /* CA:9 + CA_SHIFT:5 */
.enableWordAddress = false,
.AWRSeqIndex = 12,
.AWRSeqNumber = 1,
.ARDSeqIndex = 11,
.ARDSeqNumber = 1,
.AHBWriteWaitUnit = kFLEXSPI_AhbWriteWaitUnit2AhbCycle,
.AHBWriteWaitInterval = 0,
.enableWriteMask = true,
};
uint32_t customLUT[20] = {
/* Read Data */
[0] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0xAA, kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00),
[1] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16),
[2] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 28, kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01),
/* Write Data */
[4] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x22, kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00),
[5] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16),
[6] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 28, kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_4PAD, 0x01),
/* Read Register */
[8] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0xCC, kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00),
[9] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16),
[10] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_DDR, kFLEXSPI_4PAD, 12, kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01),
/* Write Register */
[12] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x66, kFLEXSPI_Command_DDR, kFLEXSPI_4PAD, 0x00),
[13] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16, kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16),
[14] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_4PAD, 0x01, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
/* Read ID */
[16] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_4PAD, 0xE0, kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_4PAD, 16),
[17] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_4PAD, 16, kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_4PAD, 0x08),
[18] = FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_4PAD, 0x01, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00),
};
flexspi_config_t config;
#if BOARD_ENABLE_PSRAM_CACHE
cache64_config_t cacheCfg;
#endif
status_t status = kStatus_Success;
if (!BOARD_IS_XIP()) /* FlexSPI not initialized */
{
CLOCK_EnableClock(kCLOCK_Flexspi);
RESET_ClearPeripheralReset(kFLEXSPI_RST_SHIFT_RSTn);
BOARD_SetFlexspiClock(FLEXSPI, 5U, 1U);
/* Get FLEXSPI default settings and configure the flexspi. */
FLEXSPI_GetDefaultConfig(&config);
/* Init FLEXSPI. */
config.rxSampleClock = kFLEXSPI_ReadSampleClkExternalInputFromDqsPad;
config.rxSampleClockPortB = kFLEXSPI_ReadSampleClkExternalInputFromDqsPad;
config.rxSampleClockDiff = true;
/*Set AHB buffer size for reading data through AHB bus. */
config.ahbConfig.enableAHBPrefetch = true;
config.ahbConfig.enableAHBBufferable = true;
config.ahbConfig.enableAHBCachable = true;
config.ahbConfig.enableReadAddressOpt = true;
for (uint8_t i = 1; i < FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 1; i++)
{
config.ahbConfig.buffer[i].bufferSize = 0;
}
/* FlexSPI has total 1KB RX buffer.
* Set DMA0 master to use AHB Rx Buffer0.
*/
config.ahbConfig.buffer[0].masterIndex = 10; /* GDMA */
config.ahbConfig.buffer[0].bufferSize = 512; /* Allocate 512B bytes for DMA0 */
config.ahbConfig.buffer[0].enablePrefetch = true;
config.ahbConfig.buffer[0].priority = 0;
/* All other masters use last buffer with 512B bytes. */
config.ahbConfig.buffer[FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 1].bufferSize = 512;
#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_COMBINATIONEN)
config.enableCombination = false;
#endif
FLEXSPI_Init(BOARD_FLEXSPI_PSRAM, &config);
}
/* Configure flash settings according to serial flash feature. */
FLEXSPI_SetFlashConfig(BOARD_FLEXSPI_PSRAM, &deviceconfig, kFLEXSPI_PortB1);
/* Update bottom LUT table (44-63). */
FLEXSPI_UpdateLUT(BOARD_FLEXSPI_PSRAM, 44U, customLUT, ARRAY_SIZE(customLUT));
/* Do software reset. */
FLEXSPI_SoftwareReset(BOARD_FLEXSPI_PSRAM);
/* Read identification: the Manufacturer ID of ISSI's PSRAM(IS66/67WVQ8M4DALL) is 0x03U */
uint16_t identification = 0x00U;
uint16_t registerVal = 0x00U;
status = flexspi_hyper_ram_read_id(BOARD_FLEXSPI_PSRAM, &identification);
if ((status != kStatus_Success) || (identification & 0x03U) != 0x03U)
{
status = kStatus_Fail;
}
/* Read configuration register: the default setting is 0xF052(see table 6.1 Configuration Register in
PSRAM's(IS66/67WVQ8M4DALL) datasheet), which Latency code(CR[7:4]) is 0101b, which supported max frequency is
200MHz.*/
status = flexspi_hyper_ram_read_register(BOARD_FLEXSPI_PSRAM, 0x04U << 9, &registerVal);
if ((status != kStatus_Success) || registerVal != 0xF052)
{
status = kStatus_Fail;
}
/* Initial access latency configuration, which is located in bit3 of CR. */
registerVal |= 0x01UL << 3;
/* Write configuration register: */
status = flexspi_hyper_ram_write_register(BOARD_FLEXSPI_PSRAM, 0x04U << 9, &registerVal);
if ((status != kStatus_Success) || registerVal != 0xF05A)
{
status = kStatus_Fail;
}
/* Reset */
registerVal = 0x00U;
/* Read configuration register: changes default Variable Latency into Fixed Latency: 0xF05A.
Note: FlexSPI only supports fixed latency mode for ISSI's psram. */
status = flexspi_hyper_ram_read_register(BOARD_FLEXSPI_PSRAM, 0x04U << 9, &registerVal);
if ((status != kStatus_Success) || registerVal != 0xF05A)
{
status = kStatus_Fail;
}
#if BOARD_ENABLE_PSRAM_CACHE
CACHE64_GetDefaultConfig(&cacheCfg);
/* Suppose:
Flash on PC bus starting from 0x08000000, controlled by cache 0.
PSRAM on PS bus starting from 0x28000000, controlled by cache 1.
*/
CACHE64_Init(CACHE64_POLSEL1, &cacheCfg);
CACHE64_EnableWriteBuffer(CACHE64_CTRL1, true);
CACHE64_EnableCache(CACHE64_CTRL1);
#endif
return status;
}
void BOARD_InitSleepPinConfig(void)
{
int32_t i;
/* Set all non-AON pins output low level in sleep mode. */
for (i = 0; i < 22; i++)
{
IO_MUX_SetPinOutLevelInSleep(i, IO_MUX_SleepPinLevelLow);
}
for (i = 28; i < 64; i++)
{
IO_MUX_SetPinOutLevelInSleep(i, IO_MUX_SleepPinLevelLow);
}
/* Set RF_CNTL 0-3 output low level in sleep mode. */
for (i = 0; i < 4; i++)
{
IO_MUX_SetRfPinOutLevelInSleep(i, IO_MUX_SleepPinLevelLow);
}
}
void BOARD_DeinitFlash(FLEXSPI_Type * base)
{
/* Enable FLEXSPI clock again */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_MASK;
/* Enable FLEXSPI module */
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
/* Wait until FLEXSPI is not busy */
while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) && (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)))
{
}
/* Disable module during the reset procedure */
base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
}
void BOARD_InitFlash(FLEXSPI_Type * base)
{
uint32_t status;
uint32_t lastStatus;
uint32_t retry;
/* Loopback from DQS pad can maximize RD board flash speed. */
if ((base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) != FLEXSPI_MCR0_RXCLKSRC(1))
{
base->MCR0 = (base->MCR0 & ~FLEXSPI_MCR0_RXCLKSRC_MASK) | FLEXSPI_MCR0_RXCLKSRC(1);
}
/* If serial root clock is >= 100 MHz, DLLEN set to 1, OVRDEN set to 0, then SLVDLYTARGET setting of 0x0 is
* recommended. */
base->DLLCR[0] = 0x1U;
/* Enable FLEXSPI module */
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK)
{
}
/* Need to wait DLL locked if DLL enabled */
if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK))
{
lastStatus = base->STS2;
retry = BOARD_FLEXSPI_DLL_LOCK_RETRY;
/* Wait slave delay line locked and slave reference delay line locked. */
do
{
status = base->STS2;
if ((status & (FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK)) ==
(FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK))
{
/* Locked */
retry = 100;
break;
}
else if (status == lastStatus)
{
/* Same delay cell number in calibration */
retry--;
}
else
{
retry = BOARD_FLEXSPI_DLL_LOCK_RETRY;
lastStatus = status;
}
} while (retry > 0);
/* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */
for (; retry > 0U; retry--)
{
__NOP();
}
}
}
/* BOARD_SetFlexspiClock run in RAM used to configure FlexSPI clock source and divider when XIP. */
void BOARD_SetFlexspiClock(FLEXSPI_Type * base, uint32_t src, uint32_t divider)
{
if ((CLKCTL0->FLEXSPIFCLKSEL != CLKCTL0_FLEXSPIFCLKSEL_SEL(src)) ||
((CLKCTL0->FLEXSPIFCLKDIV & CLKCTL0_FLEXSPIFCLKDIV_DIV_MASK) != (divider - 1)))
{
/* Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the flash works correctly after the
FLEXSPI root clock changed as the default FLEXSPI configuration may does not work for the new root clock
frequency. */
BOARD_DeinitFlash(base);
/* Disable clock before changing clock source */
CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI0_MASK;
/* Update flexspi clock. */
CLKCTL0->FLEXSPIFCLKSEL = CLKCTL0_FLEXSPIFCLKSEL_SEL(src);
CLKCTL0->FLEXSPIFCLKDIV |= CLKCTL0_FLEXSPIFCLKDIV_RESET_MASK; /* Reset the divider counter */
CLKCTL0->FLEXSPIFCLKDIV = CLKCTL0_FLEXSPIFCLKDIV_DIV(divider - 1);
while ((CLKCTL0->FLEXSPIFCLKDIV) & CLKCTL0_FLEXSPIFCLKDIV_REQFLAG_MASK)
{
}
/* Enable FLEXSPI clock again */
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_MASK;
BOARD_InitFlash(base);
}
}
/* This function is used to change FlexSPI clock to a stable source before clock sources(Such as PLL and Main clock)
* updating in case XIP(execute code on FLEXSPI memory.) */
void BOARD_FlexspiClockSafeConfig(void)
{
/* Move FLEXSPI clock source to T3 256m / 2 to avoid instruction/data fetch issue in XIP when
* updating PLL and main clock.
*/
BOARD_SetFlexspiClock(FLEXSPI, 6U, 2U);
}
void BOARD_CLIAttachClk(void)
{
/* attach FRG3 clock to FLEXCOMM3 (debug console) */
CLOCK_SetFRGClock(BOARD_CLI_FRG_CLK);
CLOCK_AttachClk(BOARD_CLI_CLK_ATTACH);
}