/** * \brief Send instrucion over SPI or QSPI * * \param qspi Pointer to an Qspi instance. * * \return Returns 1 if At least one instruction end has been detected since the last read of QSPI_SR.; otherwise * returns 0. */ extern void QSPI_SendFrame( Qspi* qspi, qspiFrame *pFrame, AccesType ReadWrite) { uint32_t regIFR, regICR, DummyRead; uint32_t *pQspiBuffer = (uint32_t *)QSPIMEM_ADDR; assert((qspi->QSPI_MR) & QSPI_MR_SMM); regIFR = (pFrame->spiMode | QSPI_IFR_INSTEN | (pFrame->OptionLen << QSPI_IFR_OPTL_Pos) | (pFrame->DummyCycles << QSPI_IFR_NBDUM_Pos) | (pFrame->ContinuousRead << 14)) ; // Write the instruction to reg regICR = ( QSPI_ICR_OPT(pFrame->Option) | QSPI_ICR_INST(pFrame->Instruction)); if(pFrame->OptionEn) { regIFR|=QSPI_IFR_OPTEN; } /* Instruction frame without Data, only Instruction**/ if(!(pFrame->DataSize)) { if(pFrame->InstAddrFlag) // If contain Address, put in IAr reg { qspi->QSPI_IAR = pFrame->InstAddr; regIFR |= QSPI_IFR_ADDREN; } qspi->QSPI_ICR = regICR; // update Instruction code reg qspi->QSPI_IFR = regIFR; // Instruction Frame reg } else /* Instruction frame with Data and Instruction**/ { regIFR |= QSPI_IFR_DATAEN; if(ReadWrite) { regIFR |= QSPI_IFR_TFRTYP_TRSFR_WRITE; qspi->QSPI_ICR = regICR; qspi->QSPI_IFR = regIFR ; DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses if(pFrame->InstAddrFlag) { pQspiBuffer += pFrame->InstAddr; } memcpy(pQspiBuffer ,pFrame->pData, pFrame->DataSize); } else { qspi->QSPI_ICR = regICR; qspi->QSPI_IFR = regIFR ; DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses memcpy(pFrame->pData, pQspiBuffer, pFrame->DataSize); } } memory_barrier(); qspi->QSPI_CR = QSPI_CR_LASTXFER; // End transmission after all data has been sent while(!(qspi->QSPI_SR & QSPI_SR_INSTRE)); // poll CR reg to know status if Intrustion has end }
/** * \brief Send instrucion over SPI or QSPI * * \param qspi Pointer to an Qspi instance. * * \return Returns 1 if At least one instruction end has been detected since the last read of QSPI_SR.; otherwise * returns 0. */ extern void QSPI_SendFrameToMem( Qspi* qspi, qspiFrame *pFrame, AccesType ReadWrite) { uint32_t regIFR, regICR, DummyRead ; uint8_t *pQspiMem = (uint8_t *)QSPIMEM_ADDR; assert((qspi->QSPI_MR) & QSPI_MR_SMM); regIFR = (pFrame->spiMode | QSPI_IFR_INSTEN | QSPI_IFR_DATAEN | QSPI_IFR_ADDREN | (pFrame->OptionLen << QSPI_IFR_OPTL_Pos) | (pFrame->DummyCycles << QSPI_IFR_NBDUM_Pos) | (pFrame->ContinuousRead << 14)) ; // Write the instruction to reg regICR = ( QSPI_ICR_OPT(pFrame->Option) | QSPI_ICR_INST(pFrame->Instruction)); if(pFrame->OptionEn) { regIFR|=QSPI_IFR_OPTEN; } pQspiMem += pFrame->InstAddr; if(ReadWrite) { regIFR |= QSPI_IFR_TFRTYP_TRSFR_WRITE_MEMORY; memory_barrier(); qspi->QSPI_ICR = regICR; qspi->QSPI_IFR = regIFR ; DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses memcpy(pQspiMem ,pFrame->pData, pFrame->DataSize); } else { regIFR |= QSPI_IFR_TFRTYP_TRSFR_READ_MEMORY; memory_barrier(); qspi->QSPI_ICR = regICR; qspi->QSPI_IFR = regIFR ; DummyRead = qspi->QSPI_IFR; // to synchronize system bus accesses memcpy(pFrame->pData, pQspiMem , pFrame->DataSize); // Read QSPI AHB memory space } memory_barrier(); qspi->QSPI_CR = QSPI_CR_LASTXFER; // End transmission after all data has been sent while(!(qspi->QSPI_SR & QSPI_SR_INSTRE)); // poll CR reg to know status if Intrustion has end }
bool qspi_perform_command(Qspi *qspi, const struct _qspi_cmd *cmd) { uint32_t iar, icr, ifr; uint32_t offset; uint8_t *ptr; iar = 0; icr = 0; ifr = (cmd->ifr_width & QSPI_IFR_WIDTH_Msk) | (cmd->ifr_type & QSPI_IFR_TFRTYP_Msk); /* Compute address parameters */ switch (cmd->enable.address) { case 4: ifr |= QSPI_IFR_ADDRL_32_BIT; /* fallback to the 24-bit address case */ case 3: iar = (cmd->enable.data) ? 0 : QSPI_IAR_ADDR(cmd->address); ifr |= QSPI_IFR_ADDREN; offset = cmd->address; break; case 0: offset = 0; break; default: return false; } /* Compute instruction parameters */ if (cmd->enable.instruction) { icr |= QSPI_ICR_INST(cmd->instruction); ifr |= QSPI_IFR_INSTEN; } /* Compute option parameters */ if (cmd->enable.mode && cmd->num_mode_cycles) { uint32_t mode_cycle_bits, mode_bits; icr |= QSPI_ICR_OPT(cmd->mode); ifr |= QSPI_IFR_OPTEN; switch (ifr & QSPI_IFR_WIDTH_Msk) { case QSPI_IFR_WIDTH_SINGLE_BIT_SPI: case QSPI_IFR_WIDTH_DUAL_OUTPUT: case QSPI_IFR_WIDTH_QUAD_OUTPUT: mode_cycle_bits = 1; break; case QSPI_IFR_WIDTH_DUAL_IO: case QSPI_IFR_WIDTH_DUAL_CMD: mode_cycle_bits = 2; break; case QSPI_IFR_WIDTH_QUAD_IO: case QSPI_IFR_WIDTH_QUAD_CMD: mode_cycle_bits = 4; break; default: return false; } mode_bits = cmd->num_mode_cycles * mode_cycle_bits; switch (mode_bits) { case 1: ifr |= QSPI_IFR_OPTL_OPTION_1BIT; break; case 2: ifr |= QSPI_IFR_OPTL_OPTION_2BIT; break; case 4: ifr |= QSPI_IFR_OPTL_OPTION_4BIT; break; case 8: ifr |= QSPI_IFR_OPTL_OPTION_8BIT; break; default: return false; } } /* Set number of dummy cycles */ if (cmd->enable.dummy) ifr |= QSPI_IFR_NBDUM(cmd->num_dummy_cycles); else ifr |= QSPI_IFR_NBDUM(0); /* Set data enable */ if (cmd->enable.data) { ifr |= QSPI_IFR_DATAEN; /* Special case for Continous Read Mode */ if (!cmd->tx_buffer && !cmd->rx_buffer) ifr |= QSPI_IFR_CRM_ENABLED; } /* Set QSPI Instruction Frame registers */ qspi->QSPI_IAR = iar; qspi->QSPI_ICR = icr; qspi->QSPI_IFR = ifr; /* Skip to the final steps if there is no data */ if (!cmd->enable.data) goto no_data; /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */ (void)qspi->QSPI_IFR; /* Send/Receive data */ if (cmd->tx_buffer) { /* Write data */ #ifdef CONFIG_HAVE_AESB if(cmd->use_aesb) ptr = (uint8_t*)get_qspi_aesb_mem_from_addr(qspi); else #endif ptr = (uint8_t*)get_qspi_mem_from_addr(qspi); qspi_memcpy(ptr + offset, cmd->tx_buffer, cmd->buffer_len); } else if (cmd->rx_buffer) { /* Read data */ #ifdef CONFIG_HAVE_AESB if (cmd->use_aesb) ptr = (uint8_t*)get_qspi_aesb_mem_from_addr(qspi); else #endif ptr = (uint8_t*)get_qspi_mem_from_addr(qspi); qspi_memcpy(cmd->rx_buffer, ptr + offset, cmd->buffer_len); } else { /* Stop here for continuous read */ return true; } no_data: /* Release the chip-select */ qspi->QSPI_CR = QSPI_CR_LASTXFER; /* Wait for INSTRuction End */ struct _timeout timeout; timer_start_timeout(&timeout, cmd->timeout); while (!(qspi->QSPI_SR & QSPI_SR_INSTRE)) { if (timer_timeout_reached(&timeout)) { trace_debug("qspi_perform_command timeout reached\r\n"); return false; } } return true; }
/** * \brief Configures instruction register with a given command for QSPI * * \param pQspi Pointer to a Qspi instance. * \param dwInst Instruction Code * \param dwOpt Instruction Code option */ __STATIC_INLINE void QSPI_SetInst(Qspi *pQspi, uint8_t dwInst, uint8_t dwOpt) { assert(pQspi); pQspi->QSPI_ICR = (dwInst | QSPI_ICR_OPT(dwOpt)); }