diff options
Diffstat (limited to '')
-rw-r--r-- | bsps/shared/dev/spi/xqspipsu_options.c | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/bsps/shared/dev/spi/xqspipsu_options.c b/bsps/shared/dev/spi/xqspipsu_options.c new file mode 100644 index 0000000000..c889d64abb --- /dev/null +++ b/bsps/shared/dev/spi/xqspipsu_options.c @@ -0,0 +1,532 @@ +/****************************************************************************** +* Copyright (C) 2014 - 2022 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xqspipsu_options.c +* @addtogroup Overview +* @{ +* +* This file implements functions to configure the QSPIPSU component, +* specifically some optional settings, clock and flash related information. +* +* <pre> +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- -------- ----------------------------------------------- +* 1.0 hk 08/21/14 First release +* sk 03/13/15 Added IO mode support. +* sk 04/24/15 Modified the code according to MISRAC-2012. +* 1.1 sk 04/12/16 Added debug message prints. +* 1.2 nsk 07/01/16 Modified XQspiPsu_SetOptions() to support +* LQSPI options and updated OptionsTable +* rk 07/15/16 Added support for TapDelays at different frequencies. +* 1.7 tjs 01/17/18 Added support to toggle the WP pin of flash. (PR#2448) +* 1.7 tjs 03/14/18 Added support in EL1 NS mode. (CR#974882) +* 1.8 tjs 05/02/18 Added support for IS25LP064 and IS25WP064. +* 1.8 tjs 07/26/18 Resolved cppcheck errors. (CR#1006336) +* 1.9 tjs 04/17/18 Updated register addresses as per the latest revision +* of versal (CR#999610) +* 1.9 aru 01/17/19 Fixes violations according to MISRAC-2012 +* in safety mode and modified the code such as +* Added Xil_MemCpy inplace of memcpy,Declared the pointer param +* as Pointer to const, declared XQspi_Set_TapDelay() as static. +* 1.9 akm 03/08/19 Set recommended clock and data tap delay values for 40MHZ, +* 100MHZ and 150MHZ frequencies(CR#1023187) +* 1.10 akm 08/22/19 Set recommended tap delay values for 37.5MHZ, 100MHZ and +* 150MHZ frequencies in Versal. +* 1.11 akm 11/07/19 Removed LQSPI register access in Versal. +* 1.11 akm 11/15/19 Fixed Coverity deadcode warning in +* XQspipsu_Calculate_Tapdelay(). +* 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and +* interrupts in XQspiPsu_CfgInitialize() API. +* 1.13 akm 01/04/21 Fix MISRA-C violations. +* 1.15 akm 03/03/22 Enable tapdelay settings for applications on Microblaze +* platform. +* +* </pre> +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xqspipsu_control.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +/** + * Create the table of options which are processed to get/set the device + * options. These options are table driven to allow easy maintenance and + * expansion of the options. + */ +typedef struct { + u32 Option; /**< Get/Set the device option */ + u32 Mask; /**< Mask */ +} OptionsMap; + +static OptionsMap OptionsTable[] = { + {XQSPIPSU_CLK_ACTIVE_LOW_OPTION, XQSPIPSU_CFG_CLK_POL_MASK}, + {XQSPIPSU_CLK_PHASE_1_OPTION, XQSPIPSU_CFG_CLK_PHA_MASK}, + {XQSPIPSU_MANUAL_START_OPTION, XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK}, +#if !defined (versal) + {XQSPIPSU_LQSPI_MODE_OPTION, XQSPIPSU_CFG_WP_HOLD_MASK}, +#endif +}; + +/** + * Number of options in option table + */ +#define XQSPIPSU_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap)) + +/*****************************************************************************/ +/** +* +* This function sets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned ON and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; +#if !defined (versal) + u32 QspiPsuOptions; +#endif + s32 Status; + u32 OptionsVal; + OptionsVal = Options; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); +#if !defined (versal) + QspiPsuOptions = OptionsVal & XQSPIPSU_LQSPI_MODE_OPTION; + OptionsVal &= (~XQSPIPSU_LQSPI_MODE_OPTION); +#endif + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((OptionsVal & OptionsTable[Index].Option) == + OptionsTable[Index].Option) { + /* Turn it on */ + ConfigReg |= OptionsTable[Index].Mask; + } else { + /* Turn it off */ + ConfigReg &= ~(OptionsTable[Index].Mask); + } + } + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + if ((OptionsVal & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)TRUE; + } +#if !defined (versal) + if ((QspiPsuOptions & XQSPIPSU_LQSPI_MODE_OPTION) != (u32)FALSE) { + if ((Options & XQSPIPSU_LQSPI_LESS_THEN_SIXTEENMB) != (u32)FALSE) { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_RST_STATE); + } else { + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_4_BYTE_STATE); + } + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_CFG_OFFSET,XQSPIPS_LQSPI_CFG_RST_STATE); + /* Enable the QSPI controller */ + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_EN_OFFSET,XQSPIPSU_EN_MASK); + } else { + /* + * Check for the LQSPI configuration options. + */ + ConfigReg = XQspiPsu_ReadReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET); + ConfigReg &= ~(XQSPIPSU_LQSPI_CR_LINEAR_MASK); + XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET, ConfigReg); + } +#endif + Status = (s32)XST_SUCCESS; + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function resets the options for the QSPIPSU device driver.The options +* control how the device behaves relative to the QSPIPSU bus. The device must be +* idle rather than busy transferring data before setting these device options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Options contains the specified options to be set. This is a bit +* mask where a 1 indicates the option should be turned OFF and +* a 0 indicates no action. One or more bit values may be +* contained in the mask. See the bit definitions named +* XQSPIPSU_*_OPTIONS in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting options. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options) +{ + u32 ConfigReg; + u32 Index; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + /* + * Loop through the options table, turning the option on + * depending on whether the bit is set in the incoming options flag. + */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + if ((Options & OptionsTable[Index].Option) != (u32)FALSE) { + /* Turn it off */ + ConfigReg &= ~OptionsTable[Index].Mask; + } + } + /* + * Now write the control register. Leave it to the upper layers + * to restart the device. + */ + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + if ((Options & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) { + InstancePtr->IsManualstart = (u8)FALSE; + } + + Status = (s32)XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** +* +* This function gets the options for the QSPIPSU device. The options control how +* the device behaves relative to the QSPIPSU bus. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* +* @return +* +* Options contains the specified options currently set. This is a bit value +* where a 1 means the option is on, and a 0 means the option is off. +* See the bit definitions named XQSPIPSU_*_OPTIONS in file xqspipsu.h. +* +* @note None. +* +******************************************************************************/ +u32 XQspiPsu_GetOptions(const XQspiPsu *InstancePtr) +{ + u32 OptionsFlag = 0; + u32 ConfigReg; + u32 Index; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Loop through the options table to grab options */ + for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) { + /* + * Get the current options from QSPIPSU configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + if ((ConfigReg & OptionsTable[Index].Mask) != (u32)FALSE) { + OptionsFlag |= OptionsTable[Index].Option; + } + } + return OptionsFlag; +} + +/*****************************************************************************/ +/** +* +* Configures the clock according to the prescaler passed. +* +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Prescaler - clock prescaler to be set. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* It must be stopped to re-initialize. +* +* @note None. +* +******************************************************************************/ +s32 XQspiPsu_SetClkPrescaler(const XQspiPsu *InstancePtr, u8 Prescaler) +{ + u32 ConfigReg; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM); + + /* + * Do not allow the slave select to change while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + /* + * Read the configuration register, mask out the relevant bits, and set + * them with the shifted value passed into the function. Write the + * results back to the configuration register. + */ + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + ConfigReg &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK; + ConfigReg |= (u32) ((u32)Prescaler & (u32)XQSPIPSU_CR_PRESC_MAXIMUM) << + XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT; + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + +#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__) + Status = XQspipsu_Calculate_Tapdelay(InstancePtr,Prescaler); +#else + Status = (s32)XST_SUCCESS; +#endif + } + return Status; +} + +/*****************************************************************************/ +/** +* +* This function should be used to tell the QSPIPSU driver the HW flash +* configuration being used. This API should be called at least once in the +* application. If desired, it can be called multiple times when switching +* between communicating to different flahs devices/using different configs. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param FlashCS - Flash Chip Select. +* @param FlashBus - Flash Bus (Upper, Lower or Both). +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note If this function is not called at least once in the application, +* the driver assumes there is a single flash connected to the +* lower bus and CS line. +* +******************************************************************************/ +void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FlashCS > 0U); + Xil_AssertVoid(FlashBus > 0U); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SelectFlash\r\n"); +#endif + + /* + * Bus and CS lines selected here will be updated in the instance and + * used for subsequent GENFIFO entries during transfer. + */ + + /* Choose slave select line */ + switch (FlashCS) { + case XQSPIPSU_SELECT_FLASH_CS_BOTH: + InstancePtr->GenFifoCS = (u32)XQSPIPSU_GENFIFO_CS_LOWER | + (u32)XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_UPPER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_CS_LOWER: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + default: + InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER; + break; + } + + /* Choose bus */ + switch (FlashBus) { + case XQSPIPSU_SELECT_FLASH_BUS_BOTH: + InstancePtr->GenFifoBus = (u32)XQSPIPSU_GENFIFO_BUS_LOWER | + (u32)XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_UPPER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER; + break; + case XQSPIPSU_SELECT_FLASH_BUS_LOWER: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + default: + InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER; + break; + } +#ifdef DEBUG + xil_printf("\nGenFifoCS is %08x and GenFifoBus is %08x\r\n", + InstancePtr->GenFifoCS, InstancePtr->GenFifoBus); +#endif + +} + +/*****************************************************************************/ +/** +* +* This function sets the Read mode for the QSPIPSU device driver.The device +* must be idle rather than busy transferring data before setting Read mode +* options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Mode contains the specified Mode to be set. See the +* bit definitions named XQSPIPSU_READMODE_* in the file xqspipsu.h. +* +* @return +* - XST_SUCCESS if options are successfully set. +* - XST_DEVICE_BUSY if the device is currently transferring data. +* The transfer must complete or be aborted before setting Mode. +* +* @note +* This function is not thread-safe. +* +******************************************************************************/ +s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode) +{ + u32 ConfigReg; + s32 Status; + +#ifdef DEBUG + xil_printf("\nXQspiPsu_SetReadMode\r\n"); +#endif + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Mode == XQSPIPSU_READMODE_DMA) || (Mode == XQSPIPSU_READMODE_IO)); + + /* + * Do not allow to modify the Control Register while a transfer is in + * progress. Not thread-safe. + */ + if (InstancePtr->IsBusy == (u32)TRUE) { + Status = (s32)XST_DEVICE_BUSY; + } else { + + InstancePtr->ReadMode = Mode; + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + + if (Mode == XQSPIPSU_READMODE_DMA) { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK; + } else { + ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK; + } + + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); + + Status = (s32)XST_SUCCESS; + } +#ifdef DEBUG + xil_printf("\nRead Mode is %08x\r\n", InstancePtr->ReadMode); +#endif + return Status; +} + +/*****************************************************************************/ +/** +* +* This function sets the Write Protect and Hold options for the QSPIPSU device +* driver.The device must be idle rather than busy transferring data before +* setting Write Protect and Hold options. +* +* @param InstancePtr is a pointer to the XQspiPsu instance. +* @param Value of the WP_HOLD bit in configuration register +* +* @return None +* +* @note +* This function is not thread-safe. This function can only be used with single +* flash configuration and x1/x2 data mode. This function cannot be used with +* x4 data mode and dual parallel and stacked flash configuration. +* +******************************************************************************/ +void XQspiPsu_SetWP(const XQspiPsu *InstancePtr, u8 Value) +{ + u32 ConfigReg; + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr->IsBusy != TRUE); + + ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, + XQSPIPSU_CFG_OFFSET); + ConfigReg |= (u32)((u32)Value << XQSPIPSU_CFG_WP_HOLD_SHIFT); + XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET, + ConfigReg); +} +/** @} */ |