Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /******************************************************************************
0002 * Copyright (C) 2014 - 2022 Xilinx, Inc.  All rights reserved.
0003 * SPDX-License-Identifier: MIT
0004 ******************************************************************************/
0005 
0006 /*****************************************************************************/
0007 /**
0008 *
0009 * @file xqspipsu_options.c
0010 * @addtogroup Overview
0011 * @{
0012 *
0013 * This file implements functions to configure the QSPIPSU component,
0014 * specifically some optional settings, clock and flash related information.
0015 *
0016 * <pre>
0017 * MODIFICATION HISTORY:
0018 *
0019 * Ver   Who Date     Changes
0020 * ----- --- -------- -----------------------------------------------
0021 * 1.0   hk  08/21/14 First release
0022 *       sk  03/13/15 Added IO mode support.
0023 *       sk  04/24/15 Modified the code according to MISRAC-2012.
0024 * 1.1   sk  04/12/16 Added debug message prints.
0025 * 1.2   nsk 07/01/16 Modified XQspiPsu_SetOptions() to support
0026 *            LQSPI options and updated OptionsTable
0027 *       rk  07/15/16 Added support for TapDelays at different frequencies.
0028 * 1.7   tjs 01/17/18 Added support to toggle the WP pin of flash. (PR#2448)
0029 * 1.7   tjs 03/14/18 Added support in EL1 NS mode. (CR#974882)
0030 * 1.8  tjs 05/02/18 Added support for IS25LP064 and IS25WP064.
0031 * 1.8  tjs 07/26/18 Resolved cppcheck errors. (CR#1006336)
0032 * 1.9   tjs 04/17/18 Updated register addresses as per the latest revision
0033 *                    of versal (CR#999610)
0034 * 1.9  aru 01/17/19 Fixes violations according to MISRAC-2012
0035 *                  in safety mode and modified the code such as
0036 *                  Added Xil_MemCpy inplace of memcpy,Declared the pointer param
0037 *                  as Pointer to const, declared XQspi_Set_TapDelay() as static.
0038 * 1.9 akm 03/08/19 Set recommended clock and data tap delay values for 40MHZ,
0039 *          100MHZ and 150MHZ frequencies(CR#1023187)
0040 * 1.10 akm 08/22/19 Set recommended tap delay values for 37.5MHZ, 100MHZ and
0041 *           150MHZ frequencies in Versal.
0042 * 1.11  akm 11/07/19 Removed LQSPI register access in Versal.
0043 * 1.11  akm 11/15/19 Fixed Coverity deadcode warning in
0044 *               XQspipsu_Calculate_Tapdelay().
0045 * 1.11 akm 03/09/20 Reorganize the source code, enable qspi controller and
0046 *            interrupts in XQspiPsu_CfgInitialize() API.
0047 * 1.13 akm 01/04/21 Fix MISRA-C violations.
0048 * 1.15 akm 03/03/22 Enable tapdelay settings for applications on Microblaze
0049 *            platform.
0050 *
0051 * </pre>
0052 *
0053 ******************************************************************************/
0054 
0055 /***************************** Include Files *********************************/
0056 
0057 #include "xqspipsu_control.h"
0058 
0059 /************************** Constant Definitions *****************************/
0060 
0061 /**************************** Type Definitions *******************************/
0062 
0063 /***************** Macros (Inline Functions) Definitions *********************/
0064 
0065 /************************** Function Prototypes ******************************/
0066 
0067 /************************** Variable Definitions *****************************/
0068 
0069 /**
0070  * Create the table of options which are processed to get/set the device
0071  * options. These options are table driven to allow easy maintenance and
0072  * expansion of the options.
0073  */
0074 typedef struct {
0075     u32 Option; /**< Get/Set the device option */
0076     u32 Mask;   /**< Mask */
0077 } OptionsMap;
0078 
0079 static OptionsMap OptionsTable[] = {
0080     {XQSPIPSU_CLK_ACTIVE_LOW_OPTION, XQSPIPSU_CFG_CLK_POL_MASK},
0081     {XQSPIPSU_CLK_PHASE_1_OPTION, XQSPIPSU_CFG_CLK_PHA_MASK},
0082     {XQSPIPSU_MANUAL_START_OPTION, XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK},
0083 #if !defined (versal)
0084     {XQSPIPSU_LQSPI_MODE_OPTION, XQSPIPSU_CFG_WP_HOLD_MASK},
0085 #endif
0086 };
0087 
0088 /**
0089  * Number of options in option table
0090  */
0091 #define XQSPIPSU_NUM_OPTIONS    (sizeof(OptionsTable) / sizeof(OptionsMap))
0092 
0093 /*****************************************************************************/
0094 /**
0095 *
0096 * This function sets the options for the QSPIPSU device driver.The options
0097 * control how the device behaves relative to the QSPIPSU bus. The device must be
0098 * idle rather than busy transferring data before setting these device options.
0099 *
0100 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0101 * @param    Options contains the specified options to be set. This is a bit
0102 *       mask where a 1 indicates the option should be turned ON and
0103 *       a 0 indicates no action. One or more bit values may be
0104 *       contained in the mask. See the bit definitions named
0105 *       XQSPIPSU_*_OPTIONS in the file xqspipsu.h.
0106 *
0107 * @return
0108 *       - XST_SUCCESS if options are successfully set.
0109 *       - XST_DEVICE_BUSY if the device is currently transferring data.
0110 *       The transfer must complete or be aborted before setting options.
0111 *
0112 * @note
0113 * This function is not thread-safe.
0114 *
0115 ******************************************************************************/
0116 s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options)
0117 {
0118     u32 ConfigReg;
0119     u32 Index;
0120 #if !defined (versal)
0121     u32 QspiPsuOptions;
0122 #endif
0123     s32 Status;
0124     u32 OptionsVal;
0125     OptionsVal = Options;
0126 
0127     Xil_AssertNonvoid(InstancePtr != NULL);
0128     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0129 
0130     /*
0131      * Do not allow to modify the Control Register while a transfer is in
0132      * progress. Not thread-safe.
0133      */
0134     if (InstancePtr->IsBusy == (u32)TRUE) {
0135         Status = (s32)XST_DEVICE_BUSY;
0136     } else {
0137         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0138                           XQSPIPSU_CFG_OFFSET);
0139 #if !defined (versal)
0140         QspiPsuOptions = OptionsVal & XQSPIPSU_LQSPI_MODE_OPTION;
0141         OptionsVal &= (~XQSPIPSU_LQSPI_MODE_OPTION);
0142 #endif
0143         /*
0144          * Loop through the options table, turning the option on
0145          * depending on whether the bit is set in the incoming options flag.
0146          */
0147         for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
0148             if ((OptionsVal & OptionsTable[Index].Option) ==
0149                     OptionsTable[Index].Option) {
0150                 /* Turn it on */
0151                 ConfigReg |= OptionsTable[Index].Mask;
0152             } else {
0153                 /* Turn it off */
0154                 ConfigReg &= ~(OptionsTable[Index].Mask);
0155             }
0156         }
0157         /*
0158          * Now write the control register. Leave it to the upper layers
0159          * to restart the device.
0160          */
0161         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
0162                  ConfigReg);
0163 
0164         if ((OptionsVal & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) {
0165             InstancePtr->IsManualstart = (u8)TRUE;
0166         }
0167 #if !defined (versal)
0168         if ((QspiPsuOptions & XQSPIPSU_LQSPI_MODE_OPTION) != (u32)FALSE) {
0169             if ((Options & XQSPIPSU_LQSPI_LESS_THEN_SIXTEENMB) != (u32)FALSE) {
0170                 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_RST_STATE);
0171             } else {
0172                 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_4_BYTE_STATE);
0173             }
0174             XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_CFG_OFFSET,XQSPIPS_LQSPI_CFG_RST_STATE);
0175             /* Enable the QSPI controller */
0176             XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_EN_OFFSET,XQSPIPSU_EN_MASK);
0177         } else {
0178             /*
0179              * Check for the LQSPI configuration options.
0180              */
0181             ConfigReg = XQspiPsu_ReadReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET);
0182             ConfigReg &= ~(XQSPIPSU_LQSPI_CR_LINEAR_MASK);
0183             XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET, ConfigReg);
0184         }
0185 #endif
0186         Status = (s32)XST_SUCCESS;
0187     }
0188     return Status;
0189 }
0190 
0191 /*****************************************************************************/
0192 /**
0193 *
0194 * This function resets the options for the QSPIPSU device driver.The options
0195 * control how the device behaves relative to the QSPIPSU bus. The device must be
0196 * idle rather than busy transferring data before setting these device options.
0197 *
0198 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0199 * @param    Options contains the specified options to be set. This is a bit
0200 *       mask where a 1 indicates the option should be turned OFF and
0201 *       a 0 indicates no action. One or more bit values may be
0202 *       contained in the mask. See the bit definitions named
0203 *       XQSPIPSU_*_OPTIONS in the file xqspipsu.h.
0204 *
0205 * @return
0206 *       - XST_SUCCESS if options are successfully set.
0207 *       - XST_DEVICE_BUSY if the device is currently transferring data.
0208 *       The transfer must complete or be aborted before setting options.
0209 *
0210 * @note
0211 * This function is not thread-safe.
0212 *
0213 ******************************************************************************/
0214 s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options)
0215 {
0216     u32 ConfigReg;
0217     u32 Index;
0218     s32 Status;
0219 
0220     Xil_AssertNonvoid(InstancePtr != NULL);
0221     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0222 
0223     /*
0224      * Do not allow to modify the Control Register while a transfer is in
0225      * progress. Not thread-safe.
0226      */
0227     if (InstancePtr->IsBusy == (u32)TRUE) {
0228         Status = (s32)XST_DEVICE_BUSY;
0229     } else {
0230 
0231         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0232                           XQSPIPSU_CFG_OFFSET);
0233 
0234         /*
0235          * Loop through the options table, turning the option on
0236          * depending on whether the bit is set in the incoming options flag.
0237          */
0238         for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
0239             if ((Options & OptionsTable[Index].Option) != (u32)FALSE) {
0240                 /* Turn it off */
0241                 ConfigReg &= ~OptionsTable[Index].Mask;
0242             }
0243         }
0244         /*
0245          * Now write the control register. Leave it to the upper layers
0246          * to restart the device.
0247          */
0248         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
0249                  ConfigReg);
0250 
0251         if ((Options & XQSPIPSU_MANUAL_START_OPTION) != (u32)FALSE) {
0252             InstancePtr->IsManualstart = (u8)FALSE;
0253         }
0254 
0255         Status = (s32)XST_SUCCESS;
0256     }
0257 
0258     return Status;
0259 }
0260 
0261 /*****************************************************************************/
0262 /**
0263 *
0264 * This function gets the options for the QSPIPSU device. The options control how
0265 * the device behaves relative to the QSPIPSU bus.
0266 *
0267 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0268 *
0269 * @return
0270 *
0271 * Options contains the specified options currently set. This is a bit value
0272 * where a 1 means the option is on, and a 0 means the option is off.
0273 * See the bit definitions named XQSPIPSU_*_OPTIONS in file xqspipsu.h.
0274 *
0275 * @note     None.
0276 *
0277 ******************************************************************************/
0278 u32 XQspiPsu_GetOptions(const XQspiPsu *InstancePtr)
0279 {
0280     u32 OptionsFlag = 0;
0281     u32 ConfigReg;
0282     u32 Index;
0283 
0284     Xil_AssertNonvoid(InstancePtr != NULL);
0285     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0286 
0287     /* Loop through the options table to grab options */
0288     for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
0289         /*
0290          * Get the current options from QSPIPSU configuration register.
0291          */
0292         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0293                               XQSPIPSU_CFG_OFFSET);
0294         if ((ConfigReg & OptionsTable[Index].Mask) != (u32)FALSE) {
0295             OptionsFlag |= OptionsTable[Index].Option;
0296         }
0297     }
0298     return OptionsFlag;
0299 }
0300 
0301 /*****************************************************************************/
0302 /**
0303 *
0304 * Configures the clock according to the prescaler passed.
0305 *
0306 *
0307 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0308 * @param    Prescaler - clock prescaler to be set.
0309 *
0310 * @return
0311 *       - XST_SUCCESS if successful.
0312 *       - XST_DEVICE_IS_STARTED if the device is already started.
0313 *       - XST_DEVICE_BUSY if the device is currently transferring data.
0314 *       It must be stopped to re-initialize.
0315 *
0316 * @note     None.
0317 *
0318 ******************************************************************************/
0319 s32 XQspiPsu_SetClkPrescaler(const XQspiPsu *InstancePtr, u8 Prescaler)
0320 {
0321     u32 ConfigReg;
0322     s32 Status;
0323 
0324     Xil_AssertNonvoid(InstancePtr != NULL);
0325     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0326     Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM);
0327 
0328     /*
0329      * Do not allow the slave select to change while a transfer is in
0330      * progress. Not thread-safe.
0331      */
0332     if (InstancePtr->IsBusy == (u32)TRUE) {
0333         Status = (s32)XST_DEVICE_BUSY;
0334     } else {
0335         /*
0336          * Read the configuration register, mask out the relevant bits, and set
0337          * them with the shifted value passed into the function. Write the
0338          * results back to the configuration register.
0339          */
0340         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0341                           XQSPIPSU_CFG_OFFSET);
0342 
0343         ConfigReg &= ~(u32)XQSPIPSU_CFG_BAUD_RATE_DIV_MASK;
0344         ConfigReg |= (u32) ((u32)Prescaler & (u32)XQSPIPSU_CR_PRESC_MAXIMUM) <<
0345                     XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT;
0346 
0347         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
0348                 ConfigReg);
0349 
0350 #if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__)
0351         Status = XQspipsu_Calculate_Tapdelay(InstancePtr,Prescaler);
0352 #else
0353         Status = (s32)XST_SUCCESS;
0354 #endif
0355     }
0356     return Status;
0357 }
0358 
0359 /*****************************************************************************/
0360 /**
0361 *
0362 * This function should be used to tell the QSPIPSU driver the HW flash
0363 * configuration being used. This API should be called at least once in the
0364 * application. If desired, it can be called multiple times when switching
0365 * between communicating to different flahs devices/using different configs.
0366 *
0367 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0368 * @param    FlashCS - Flash Chip Select.
0369 * @param    FlashBus - Flash Bus (Upper, Lower or Both).
0370 *
0371 * @return
0372 *       - XST_SUCCESS if successful.
0373 *       - XST_DEVICE_IS_STARTED if the device is already started.
0374 *       It must be stopped to re-initialize.
0375 *
0376 * @note     If this function is not called at least once in the application,
0377 *       the driver assumes there is a single flash connected to the
0378 *       lower bus and CS line.
0379 *
0380 ******************************************************************************/
0381 void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus)
0382 {
0383     Xil_AssertVoid(InstancePtr != NULL);
0384     Xil_AssertVoid(FlashCS > 0U);
0385     Xil_AssertVoid(FlashBus > 0U);
0386     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0387 
0388 #ifdef DEBUG
0389     xil_printf("\nXQspiPsu_SelectFlash\r\n");
0390 #endif
0391 
0392     /*
0393      * Bus and CS lines selected here will be updated in the instance and
0394      * used for subsequent GENFIFO entries during transfer.
0395      */
0396 
0397     /* Choose slave select line */
0398     switch (FlashCS) {
0399         case XQSPIPSU_SELECT_FLASH_CS_BOTH:
0400             InstancePtr->GenFifoCS = (u32)XQSPIPSU_GENFIFO_CS_LOWER |
0401                         (u32)XQSPIPSU_GENFIFO_CS_UPPER;
0402             break;
0403         case XQSPIPSU_SELECT_FLASH_CS_UPPER:
0404             InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER;
0405             break;
0406         case XQSPIPSU_SELECT_FLASH_CS_LOWER:
0407             InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
0408             break;
0409         default:
0410             InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
0411             break;
0412     }
0413 
0414     /* Choose bus */
0415     switch (FlashBus) {
0416         case XQSPIPSU_SELECT_FLASH_BUS_BOTH:
0417             InstancePtr->GenFifoBus = (u32)XQSPIPSU_GENFIFO_BUS_LOWER |
0418                         (u32)XQSPIPSU_GENFIFO_BUS_UPPER;
0419             break;
0420         case XQSPIPSU_SELECT_FLASH_BUS_UPPER:
0421             InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER;
0422             break;
0423         case XQSPIPSU_SELECT_FLASH_BUS_LOWER:
0424             InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
0425             break;
0426         default:
0427             InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
0428             break;
0429     }
0430 #ifdef DEBUG
0431     xil_printf("\nGenFifoCS is %08x and GenFifoBus is %08x\r\n",
0432                 InstancePtr->GenFifoCS, InstancePtr->GenFifoBus);
0433 #endif
0434 
0435 }
0436 
0437 /*****************************************************************************/
0438 /**
0439 *
0440 * This function sets the Read mode for the QSPIPSU device driver.The device
0441 * must be idle rather than busy transferring data before setting Read mode
0442 * options.
0443 *
0444 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0445 * @param    Mode contains the specified Mode to be set. See the
0446 *       bit definitions named XQSPIPSU_READMODE_* in the file xqspipsu.h.
0447 *
0448 * @return
0449 *       - XST_SUCCESS if options are successfully set.
0450 *       - XST_DEVICE_BUSY if the device is currently transferring data.
0451 *       The transfer must complete or be aborted before setting Mode.
0452 *
0453 * @note
0454 * This function is not thread-safe.
0455 *
0456 ******************************************************************************/
0457 s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode)
0458 {
0459     u32 ConfigReg;
0460     s32 Status;
0461 
0462 #ifdef DEBUG
0463     xil_printf("\nXQspiPsu_SetReadMode\r\n");
0464 #endif
0465 
0466     Xil_AssertNonvoid(InstancePtr != NULL);
0467     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0468     Xil_AssertNonvoid((Mode == XQSPIPSU_READMODE_DMA) || (Mode == XQSPIPSU_READMODE_IO));
0469 
0470     /*
0471      * Do not allow to modify the Control Register while a transfer is in
0472      * progress. Not thread-safe.
0473      */
0474     if (InstancePtr->IsBusy == (u32)TRUE) {
0475         Status = (s32)XST_DEVICE_BUSY;
0476     } else {
0477 
0478         InstancePtr->ReadMode = Mode;
0479 
0480         ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0481                           XQSPIPSU_CFG_OFFSET);
0482 
0483         if (Mode == XQSPIPSU_READMODE_DMA) {
0484             ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
0485             ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
0486         } else {
0487             ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
0488         }
0489 
0490         XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
0491                  ConfigReg);
0492 
0493         Status = (s32)XST_SUCCESS;
0494     }
0495 #ifdef DEBUG
0496     xil_printf("\nRead Mode is %08x\r\n", InstancePtr->ReadMode);
0497 #endif
0498     return Status;
0499 }
0500 
0501 /*****************************************************************************/
0502 /**
0503 *
0504 * This function sets the Write Protect and Hold options for the QSPIPSU device
0505 * driver.The device must be idle rather than busy transferring data before
0506 * setting Write Protect and Hold options.
0507 *
0508 * @param    InstancePtr is a pointer to the XQspiPsu instance.
0509 * @param    Value of the WP_HOLD bit in configuration register
0510 *
0511 * @return   None
0512 *
0513 * @note
0514 * This function is not thread-safe. This function can only be used with single
0515 * flash configuration and x1/x2 data mode. This function cannot be used with
0516 * x4 data mode and dual parallel and stacked flash configuration.
0517 *
0518 ******************************************************************************/
0519 void XQspiPsu_SetWP(const XQspiPsu *InstancePtr, u8 Value)
0520 {
0521     u32 ConfigReg;
0522     Xil_AssertVoid(InstancePtr != NULL);
0523     Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
0524     Xil_AssertVoid(InstancePtr->IsBusy != TRUE);
0525 
0526     ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
0527             XQSPIPSU_CFG_OFFSET);
0528     ConfigReg |= (u32)((u32)Value << XQSPIPSU_CFG_WP_HOLD_SHIFT);
0529     XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
0530                     ConfigReg);
0531 }
0532 /** @} */