1 /******************************************************************************
3 * Copyright (C) 2014 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
32 /*****************************************************************************/
35 * @file xqspipsu_options.c
36 * @addtogroup qspipsu_v1_0
39 * This file implements funcitons to configure the QSPIPSU component,
40 * specifically some optional settings, clock and flash related information.
43 * MODIFICATION HISTORY:
45 * Ver Who Date Changes
46 * ----- --- -------- -----------------------------------------------
47 * 1.0 hk 08/21/14 First release
48 * sk 03/13/15 Added IO mode support.
49 * sk 04/24/15 Modified the code according to MISRAC-2012.
50 * 1.1 sk 04/12/16 Added debug message prints.
51 * 1.2 nsk 07/01/16 Modified XQspiPsu_SetOptions() to support
52 * LQSPI options and updated OptionsTable
53 * rk 07/15/16 Added support for TapDelays at different frequencies.
57 ******************************************************************************/
59 /***************************** Include Files *********************************/
63 /************************** Constant Definitions *****************************/
65 /**************************** Type Definitions *******************************/
67 /***************** Macros (Inline Functions) Definitions *********************/
69 #if defined (ARMR5) || (__aarch64__)
70 #define TAPDLY_BYPASS_VALVE_40MHZ 0x01
71 #define TAPDLY_BYPASS_VALVE_100MHZ 0x01
72 #define USE_DLY_LPBK 0x01
73 #define USE_DATA_DLY_ADJ 0x01
74 #define DATA_DLY_ADJ_DLY 0X02
75 #define LPBK_DLY_ADJ_DLY0 0X02
78 /************************** Function Prototypes ******************************/
80 #if defined (ARMR5) || (__aarch64__)
81 s32 XQspi_Set_TapDelay(XQspiPsu * InstancePtr,u32 TapdelayBypass,
82 u32 LPBKDelay,u32 Datadelay);
83 static s32 XQspipsu_Calculate_Tapdelay(XQspiPsu *InstancePtr, u8 Prescaler);
86 /************************** Variable Definitions *****************************/
89 * Create the table of options which are processed to get/set the device
90 * options. These options are table driven to allow easy maintenance and
91 * expansion of the options.
98 static OptionsMap OptionsTable[] = {
99 {XQSPIPSU_CLK_ACTIVE_LOW_OPTION, XQSPIPSU_CFG_CLK_POL_MASK},
100 {XQSPIPSU_CLK_PHASE_1_OPTION, XQSPIPSU_CFG_CLK_PHA_MASK},
101 {XQSPIPSU_MANUAL_START_OPTION, XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK},
102 {XQSPIPSU_LQSPI_MODE_OPTION, XQSPIPSU_CFG_WP_HOLD_MASK},
105 #define XQSPIPSU_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap))
107 /*****************************************************************************/
110 * This function sets the options for the QSPIPSU device driver.The options
111 * control how the device behaves relative to the QSPIPSU bus. The device must be
112 * idle rather than busy transferring data before setting these device options.
114 * @param InstancePtr is a pointer to the XQspiPsu instance.
115 * @param Options contains the specified options to be set. This is a bit
116 * mask where a 1 indicates the option should be turned ON and
117 * a 0 indicates no action. One or more bit values may be
118 * contained in the mask. See the bit definitions named
119 * XQSPIPSU_*_OPTIONS in the file xqspipsu.h.
122 * - XST_SUCCESS if options are successfully set.
123 * - XST_DEVICE_BUSY if the device is currently transferring data.
124 * The transfer must complete or be aborted before setting options.
127 * This function is not thread-safe.
129 ******************************************************************************/
130 s32 XQspiPsu_SetOptions(XQspiPsu *InstancePtr, u32 Options)
137 Xil_AssertNonvoid(InstancePtr != NULL);
138 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
141 * Do not allow to modify the Control Register while a transfer is in
142 * progress. Not thread-safe.
144 if (InstancePtr->IsBusy == TRUE) {
145 Status = (s32)XST_DEVICE_BUSY;
148 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
149 XQSPIPSU_CFG_OFFSET);
150 QspiPsuOptions = Options & XQSPIPSU_LQSPI_MODE_OPTION;
151 Options &= ~XQSPIPSU_LQSPI_MODE_OPTION;
153 * Loop through the options table, turning the option on
154 * depending on whether the bit is set in the incoming options flag.
156 for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
157 if ((Options & OptionsTable[Index].Option) != FALSE) {
159 ConfigReg |= OptionsTable[Index].Mask;
162 ConfigReg &= ~(OptionsTable[Index].Mask);
167 * Now write the control register. Leave it to the upper layers
168 * to restart the device.
170 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
173 if ((Options & XQSPIPSU_MANUAL_START_OPTION) != FALSE) {
174 InstancePtr->IsManualstart = TRUE;
177 * Check for the LQSPI configuration options.
179 ConfigReg = XQspiPsu_ReadReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET);
181 if (QspiPsuOptions & XQSPIPSU_LQSPI_MODE_OPTION) {
182 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET,XQSPIPS_LQSPI_CR_RST_STATE);
183 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_CFG_OFFSET,XQSPIPS_LQSPI_CFG_RST_STATE);
184 /* Enable the QSPI controller */
185 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_EN_OFFSET,XQSPIPSU_EN_MASK);
188 ConfigReg &= ~(XQSPIPSU_LQSPI_CR_LINEAR_MASK);
189 XQspiPsu_WriteReg(XQSPIPS_BASEADDR,XQSPIPSU_LQSPI_CR_OFFSET, ConfigReg);
192 Status = XST_SUCCESS;
198 /*****************************************************************************/
201 * This function resets the options for the QSPIPSU device driver.The options
202 * control how the device behaves relative to the QSPIPSU bus. The device must be
203 * idle rather than busy transferring data before setting these device options.
205 * @param InstancePtr is a pointer to the XQspiPsu instance.
206 * @param Options contains the specified options to be set. This is a bit
207 * mask where a 1 indicates the option should be turned OFF and
208 * a 0 indicates no action. One or more bit values may be
209 * contained in the mask. See the bit definitions named
210 * XQSPIPSU_*_OPTIONS in the file xqspipsu.h.
213 * - XST_SUCCESS if options are successfully set.
214 * - XST_DEVICE_BUSY if the device is currently transferring data.
215 * The transfer must complete or be aborted before setting options.
218 * This function is not thread-safe.
220 ******************************************************************************/
221 s32 XQspiPsu_ClearOptions(XQspiPsu *InstancePtr, u32 Options)
227 Xil_AssertNonvoid(InstancePtr != NULL);
228 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
231 * Do not allow to modify the Control Register while a transfer is in
232 * progress. Not thread-safe.
234 if (InstancePtr->IsBusy == TRUE) {
235 Status = (s32)XST_DEVICE_BUSY;
238 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
239 XQSPIPSU_CFG_OFFSET);
242 * Loop through the options table, turning the option on
243 * depending on whether the bit is set in the incoming options flag.
245 for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
246 if ((Options & OptionsTable[Index].Option) != FALSE) {
248 ConfigReg &= ~OptionsTable[Index].Mask;
253 * Now write the control register. Leave it to the upper layers
254 * to restart the device.
256 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
259 if ((Options & XQSPIPSU_MANUAL_START_OPTION) != FALSE) {
260 InstancePtr->IsManualstart = FALSE;
263 Status = XST_SUCCESS;
269 /*****************************************************************************/
272 * This function gets the options for the QSPIPSU device. The options control how
273 * the device behaves relative to the QSPIPSU bus.
275 * @param InstancePtr is a pointer to the XQspiPsu instance.
279 * Options contains the specified options currently set. This is a bit value
280 * where a 1 means the option is on, and a 0 means the option is off.
281 * See the bit definitions named XQSPIPSU_*_OPTIONS in file xqspipsu.h.
285 ******************************************************************************/
286 u32 XQspiPsu_GetOptions(XQspiPsu *InstancePtr)
292 Xil_AssertNonvoid(InstancePtr != NULL);
293 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
296 * Get the current options from QSPIPSU configuration register.
298 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
299 XQSPIPSU_CFG_OFFSET);
301 /* Loop through the options table to grab options */
302 for (Index = 0U; Index < XQSPIPSU_NUM_OPTIONS; Index++) {
303 if ((ConfigReg & OptionsTable[Index].Mask) != FALSE) {
304 OptionsFlag |= OptionsTable[Index].Option;
311 #if defined (ARMR5) || (__aarch64__)
312 /*****************************************************************************/
315 * This function sets the Tapdelay values for the QSPIPSU device driver.The device
316 * must be idle rather than busy transferring data before setting Tapdelay.
318 * @param InstancePtr is a pointer to the XQspiPsu instance.
319 * @param TapdelayBypss contains the IOU_TAPDLY_BYPASS register value.
320 * @param LPBKDelay contains the GQSPI_LPBK_DLY_ADJ register value.
321 * @param Datadelay contains the QSPI_DATA_DLY_ADJ register value.
324 * - XST_SUCCESS if options are successfully set.
325 * - XST_DEVICE_BUSY if the device is currently transferring data.
326 * The transfer must complete or be aborted before setting TapDelay.
329 * This function is not thread-safe.
331 ******************************************************************************/
332 s32 XQspi_Set_TapDelay(XQspiPsu * InstancePtr,u32 TapdelayBypass,
333 u32 LPBKDelay,u32 Datadelay)
337 Xil_AssertNonvoid(InstancePtr != NULL);
338 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
341 * Do not allow to modify the Control Register while a transfer is in
342 * progress. Not thread-safe.
344 if (InstancePtr->IsBusy == TRUE) {
345 Status = XST_DEVICE_BUSY;
347 XQspiPsu_WriteReg(XPS_SYS_CTRL_BASEADDR,IOU_TAPDLY_BYPASS_OFFSET,
349 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
350 XQSPIPSU_LPBK_DLY_ADJ_OFFSET,LPBKDelay);
351 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
352 XQSPIPSU_DATA_DLY_ADJ_OFFSET,Datadelay);
353 Status = XST_SUCCESS;
358 /*****************************************************************************/
361 * Configures the clock according to the prescaler passed.
364 * @param InstancePtr is a pointer to the XQspiPsu instance.
365 * @param Prescaler - clock prescaler.
368 * - XST_SUCCESS if successful.
369 * - XST_DEVICE_BUSY if the device is currently transferring data.
370 * The transfer must complete or be aborted before setting Tapdelay.
374 ******************************************************************************/
375 static s32 XQspipsu_Calculate_Tapdelay(XQspiPsu *InstancePtr, u8 Prescaler)
377 u32 FreqDiv, Divider, Tapdelay, LBkModeReg, delayReg;
380 Divider = (1 << (Prescaler+1));
382 FreqDiv = (InstancePtr->Config.InputClockHz)/Divider;
383 Tapdelay = XQspiPsu_ReadReg(XPS_SYS_CTRL_BASEADDR,
384 IOU_TAPDLY_BYPASS_OFFSET);
386 Tapdelay = Tapdelay & (~IOU_TAPDLY_BYPASS_LQSPI_RX_MASK);
388 LBkModeReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
389 XQSPIPSU_LPBK_DLY_ADJ_OFFSET);
391 LBkModeReg = (LBkModeReg &
392 (~(XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_MASK))) &
393 (LBkModeReg & (~(XQSPIPSU_LPBK_DLY_ADJ_DLY1_MASK))) &
394 (LBkModeReg & (~(XQSPIPSU_LPBK_DLY_ADJ_DLY0_MASK)));
396 delayReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
397 XQSPIPSU_DATA_DLY_ADJ_OFFSET);
399 delayReg = (delayReg &
400 (~(XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_MASK))) &
401 (delayReg & (~( XQSPIPSU_DATA_DLY_ADJ_DLY_MASK)));
403 if(FreqDiv < XQSPIPSU_FREQ_40MHZ){
404 Tapdelay = Tapdelay |
405 (TAPDLY_BYPASS_VALVE_40MHZ << IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT);
406 } else if (FreqDiv <= XQSPIPSU_FREQ_100MHZ) {
407 Tapdelay = Tapdelay | (TAPDLY_BYPASS_VALVE_100MHZ << IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT);
408 LBkModeReg = LBkModeReg |
409 (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT);
410 delayReg = delayReg |
411 (USE_DATA_DLY_ADJ << XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT) |
412 (DATA_DLY_ADJ_DLY << XQSPIPSU_DATA_DLY_ADJ_DLY_SHIFT);
413 } else if (FreqDiv <= XQSPIPSU_FREQ_150MHZ) {
414 LBkModeReg = LBkModeReg |
415 (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT ) |
416 (LPBK_DLY_ADJ_DLY0 << XQSPIPSU_LPBK_DLY_ADJ_DLY0_SHIFT);
418 Status = XQspi_Set_TapDelay(InstancePtr, Tapdelay, LBkModeReg, delayReg);
424 /*****************************************************************************/
427 * Configures the clock according to the prescaler passed.
430 * @param InstancePtr is a pointer to the XQspiPsu instance.
431 * @param Prescaler - clock prescaler to be set.
434 * - XST_SUCCESS if successful.
435 * - XST_DEVICE_IS_STARTED if the device is already started.
436 * - XST_DEVICE_BUSY if the device is currently transferring data.
437 * It must be stopped to re-initialize.
441 ******************************************************************************/
442 s32 XQspiPsu_SetClkPrescaler(XQspiPsu *InstancePtr, u8 Prescaler)
447 Xil_AssertNonvoid(InstancePtr != NULL);
448 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
449 Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM);
452 * Do not allow the slave select to change while a transfer is in
453 * progress. Not thread-safe.
455 if (InstancePtr->IsBusy == TRUE) {
456 Status = (s32)XST_DEVICE_BUSY;
460 * Read the configuration register, mask out the relevant bits, and set
461 * them with the shifted value passed into the function. Write the
462 * results back to the configuration register.
464 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
465 XQSPIPSU_CFG_OFFSET);
467 ConfigReg &= (u32)(~XQSPIPSU_CFG_BAUD_RATE_DIV_MASK);
468 ConfigReg |= (u32) ((u32)Prescaler & (u32)XQSPIPSU_CR_PRESC_MAXIMUM) <<
469 XQSPIPSU_CFG_BAUD_RATE_DIV_SHIFT;
471 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
472 XQSPIPSU_CFG_OFFSET, ConfigReg);
474 #if defined (ARMR5) || (__aarch64__)
475 Status = XQspipsu_Calculate_Tapdelay(InstancePtr,Prescaler);
477 Status = XST_SUCCESS;
484 /*****************************************************************************/
487 * This funciton should be used to tell the QSPIPSU driver the HW flash
488 * configuration being used. This API should be called atleast once in the
489 * application. If desired, it can be called multiple times when switching
490 * between communicating to different flahs devices/using different configs.
492 * @param InstancePtr is a pointer to the XQspiPsu instance.
493 * @param FlashCS - Flash Chip Select.
494 * @param FlashBus - Flash Bus (Upper, Lower or Both).
497 * - XST_SUCCESS if successful.
498 * - XST_DEVICE_IS_STARTED if the device is already started.
499 * It must be stopped to re-initialize.
501 * @note If this funciton is not called atleast once in the application,
502 * the driver assumes there is a single flash connected to the
503 * lower bus and CS line.
505 ******************************************************************************/
506 void XQspiPsu_SelectFlash(XQspiPsu *InstancePtr, u8 FlashCS, u8 FlashBus)
508 Xil_AssertVoid(InstancePtr != NULL);
511 xil_printf("\nXQspiPsu_SelectFlash\r\n");
515 * Bus and CS lines selected here will be updated in the instance and
516 * used for subsequent GENFIFO entries during transfer.
519 /* Choose slave select line */
521 case XQSPIPSU_SELECT_FLASH_CS_BOTH:
522 InstancePtr->GenFifoCS = (u32)XQSPIPSU_GENFIFO_CS_LOWER |
523 (u32)XQSPIPSU_GENFIFO_CS_UPPER;
525 case XQSPIPSU_SELECT_FLASH_CS_UPPER:
526 InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_UPPER;
528 case XQSPIPSU_SELECT_FLASH_CS_LOWER:
529 InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
532 InstancePtr->GenFifoCS = XQSPIPSU_GENFIFO_CS_LOWER;
538 case XQSPIPSU_SELECT_FLASH_BUS_BOTH:
539 InstancePtr->GenFifoBus = (u32)XQSPIPSU_GENFIFO_BUS_LOWER |
540 (u32)XQSPIPSU_GENFIFO_BUS_UPPER;
542 case XQSPIPSU_SELECT_FLASH_BUS_UPPER:
543 InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_UPPER;
545 case XQSPIPSU_SELECT_FLASH_BUS_LOWER:
546 InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
549 InstancePtr->GenFifoBus = XQSPIPSU_GENFIFO_BUS_LOWER;
553 xil_printf("\nGenFifoCS is %08x and GenFifoBus is %08x\r\n",
554 InstancePtr->GenFifoCS, InstancePtr->GenFifoBus);
559 /*****************************************************************************/
562 * This function sets the Read mode for the QSPIPSU device driver.The device
563 * must be idle rather than busy transferring data before setting Read mode
566 * @param InstancePtr is a pointer to the XQspiPsu instance.
567 * @param Mode contains the specified Mode to be set. See the
568 * bit definitions named XQSPIPSU_READMODE_* in the file xqspipsu.h.
571 * - XST_SUCCESS if options are successfully set.
572 * - XST_DEVICE_BUSY if the device is currently transferring data.
573 * The transfer must complete or be aborted before setting Mode.
576 * This function is not thread-safe.
578 ******************************************************************************/
579 s32 XQspiPsu_SetReadMode(XQspiPsu *InstancePtr, u32 Mode)
585 xil_printf("\nXQspiPsu_SetReadMode\r\n");
588 Xil_AssertNonvoid(InstancePtr != NULL);
589 Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
592 * Do not allow to modify the Control Register while a transfer is in
593 * progress. Not thread-safe.
595 if (InstancePtr->IsBusy == TRUE) {
596 Status = (s32)XST_DEVICE_BUSY;
599 InstancePtr->ReadMode = Mode;
601 ConfigReg = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
602 XQSPIPSU_CFG_OFFSET);
604 if (Mode == XQSPIPSU_READMODE_DMA) {
605 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
606 ConfigReg |= XQSPIPSU_CFG_MODE_EN_DMA_MASK;
608 ConfigReg &= ~XQSPIPSU_CFG_MODE_EN_MASK;
611 XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
614 Status = XST_SUCCESS;
617 xil_printf("\nRead Mode is %08x\r\n", InstancePtr->ReadMode);