/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in Linear mode. This function writes data to the serial * FLASH in QSPI mode and reads data in Linear QSPI mode. * * @param None. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int LinearQspiFlashExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set the prescaler for QSPI clock */ XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Set Manual Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); FlashReadID(); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read from the flash in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Set Auto Start and Manual Chip select options and drive the * HOLD_B high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Erase the flash. */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write the data in the write buffer to the serial FLASH a page at a * time, starting from TEST_ADDRESS */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, (Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); } /* * Read from the flash in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != (u8)(UniqueValue + Test)) { return XST_FAILURE; } } return XST_SUCCESS; }
/***************************************************************************** * * The purpose of this function is to illustrate how to use the XQspiPs * device driver in Linear mode. This function writes data to the serial * FLASH in QSPI mode and reads data in Linear QSPI mode. * * @param None. * * @return XST_SUCCESS if successful, else XST_FAILURE. * * @note None. * *****************************************************************************/ int LinearQspiFlashExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId) { int Status; u8 UniqueValue; int Count; int Page; XQspiPs_Config *QspiConfig; /* * Initialize the QSPI driver so that it's ready to use */ QspiConfig = XQspiPs_LookupConfig(QspiDeviceId); if (NULL == QspiConfig) { return XST_FAILURE; } Status = XQspiPs_CfgInitialize(QspiInstancePtr, QspiConfig, QspiConfig->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Perform a self-test to check hardware build */ Status = XQspiPs_SelfTest(QspiInstancePtr); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Enable two flash memories on seperate buses */ XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_WRITE); /* * Set the QSPI device as a master and enable manual CS, manual start * and flash interface mode options and drive HOLD_B pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_MANUAL_START_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetClkPrescaler(QspiInstancePtr, XQSPIPS_CLK_PRESCALE_8); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Assert the FLASH chip select. */ XQspiPs_SetSlaveSelect(QspiInstancePtr); /* * Erase the flash sectors */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write data to the two flash memories on seperate buses, starting from * TEST_ADDRESS. This is same as writing to a single flash memory. The * LQSPI controller takes care of splitting the data words and writing * them to the two flash memories. The user needs to take care of the * address translation */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, ((Page * PAGE_SIZE) + TEST_ADDRESS) / 2, PAGE_SIZE, WRITE_CMD); } /* * Read from the two flash memories on seperate buses in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != WriteBuffer[DATA_OFFSET + (Count % PAGE_SIZE)]) { return XST_FAILURE; } } /* * Set the QSPI device as a master and enable manual CS, manual start * and flash interface mode options and drive HOLD_B pin high. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_FORCE_SSELECT_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); /* * Initialize the write buffer for a pattern to write to the FLASH * and the read buffer to zero so it can be verified after the read, the * test value that is added to the unique value allows the value to be * changed in a debug environment to guarantee */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE; Count++, UniqueValue++) { WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue + Test); } memset(ReadBuffer, 0x00, sizeof(ReadBuffer)); /* * Erase the flash sectors */ FlashErase(QspiInstancePtr, TEST_ADDRESS, MAX_DATA); /* * Write data to the two flash memories on seperate buses, starting from * TEST_ADDRESS. This is same as writing to a single flash memory. The * LQSPI controller takes care of splitting the data words and writing * them to the two flash memories. The user needs to take care of the * address translation */ for (Page = 0; Page < PAGE_COUNT; Page++) { FlashWrite(QspiInstancePtr, ((Page * PAGE_SIZE) + TEST_ADDRESS) / 2, PAGE_SIZE, WRITE_CMD); } /* * Read from the two flash memories on seperate buses in LQSPI mode. */ XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION); XQspiPs_SetLqspiConfigReg(QspiInstancePtr, DUAL_QSPI_CONFIG_QUAD_READ); Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, TEST_ADDRESS, MAX_DATA); if (Status != XST_SUCCESS) { return XST_FAILURE; } /* * Setup a pointer to the start of the data that was read into the read * buffer and verify the data read is the data that was written */ for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA; Count++, UniqueValue++) { if (ReadBuffer[Count] != WriteBuffer[DATA_OFFSET + (Count % PAGE_SIZE)]) { return XST_FAILURE; } } return XST_SUCCESS; }