/** * * QSPI bus begin transaction function. * * @param dev - QSPI device handle * * @return none * *****************************************************************************/ static void qspi_xc7z_transaction_begin(cyg_spi_device *dev) { entry_debug(); cyg_qspi_xc7z_device_t *xc7z_qspi_dev = (cyg_qspi_xc7z_device_t *) dev; cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)xc7z_qspi_dev->qspi_device.spi_bus; cyg_uint32 val; if (!xc7z_qspi_dev->init) { xc7z_qspi_dev->init = true; qspi_xc7z_calc_bratediv(xc7z_qspi_dev); } // Configure SPI channel 0 - this is the only channel we // use for all devices since we drive chip selects manually HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); val &= (~XQSPIPS_CR_CPOL_MASK) & (~XQSPIPS_CR_CPHA_MASK); if (1 == xc7z_qspi_dev->cl_pol) val |= XQSPIPS_CR_CPOL_MASK; if (1 == xc7z_qspi_dev->cl_pha) val |= XQSPIPS_CR_CPHA_MASK; // Write new settings HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); }
/** * * QSPI bus transfer function in poll mode without IRQ. * * @param qspi_bus - QSPI bus handle * @param count - Number of bytes to transmit. * @param tx_data - Pointer to TX buffer. * @param rx_data - Pointer to RX buffer. * * @return none * *****************************************************************************/ static void qspi_xc7z_transfer_polled(cyg_qspi_xc7z_device_t *dev, cyg_uint32 count, const cyg_uint8 *tx_data, cyg_uint8 *rx_data) { entry_debug(); cyg_uint32 val; cyg_uint32 data; cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)dev->qspi_device.spi_bus; // Set tx buf pointer and counter if (NULL != tx_data) HAL_DCACHE_STORE(tx_data, count); // Set rx buf pointer and counter if (NULL != rx_data) HAL_DCACHE_FLUSH(rx_data, count); while(qspi_bus->us_rx_bytes) { /* if ((qspi_bus->us_tx_bytes) && ((qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_FAST_READ) || (qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_DUAL_READ) || (qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_QUAD_READ))) {*/ qspi_xc7z_fill_tx_fifo(qspi_bus, count); // } HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); val |= XQSPIPS_CR_MANSTRT_MASK | XQSPIPS_CR_SSFORCE_MASK; HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); /* Read out the data from the RX FIFO */ HAL_READ_UINT32(qspi_bus->base + XQSPIPS_SR_OFFSET, val); while ((val & XQSPIPS_IXR_RXNEMPTY_MASK) && (qspi_bus->us_rx_bytes > 0) ) { HAL_READ_UINT32(qspi_bus->base + XQSPIPS_RXD_OFFSET, data); if (qspi_bus->lp_rx_buf != NULL) { if (qspi_bus->us_rx_bytes < 4) qspi_xc7z_copy_read_data(qspi_bus, data, qspi_bus->us_rx_bytes); else qspi_xc7z_copy_read_data(qspi_bus, data, 4); } else { qspi_bus->us_rx_bytes -= (qspi_bus->us_rx_bytes < 4) ? qspi_bus->us_rx_bytes : 4; } HAL_READ_UINT32(qspi_bus->base + XQSPIPS_SR_OFFSET, val); } } }
/** * * QSPI bus finalize transaction function. * * @param dev - QSPI device handle * * @return none * *****************************************************************************/ static void qspi_xc7z_transaction_end(cyg_spi_device* dev) { entry_debug(); cyg_qspi_xc7z_device_t * xc7z_qspi_dev = (cyg_qspi_xc7z_device_t *)dev; cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)xc7z_qspi_dev->qspi_device.spi_bus; qspi_xc7z_drop_cs((cyg_qspi_xc7z_device_t *) dev); // Disable device HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_ER_OFFSET, 0x00); }
/** * * QSPI bus RX prepare data (for Zynq specific FIFO). * For correct working with unaligned data, used 1-byte transactions. * * @param qspi_bus - QSPI bus handle * @param data - 4-byte variable which RX data has. * @param len_burst - Size of data in bytes [1..4]. * * @return none * *****************************************************************************/ static void qspi_xc7z_copy_read_data(cyg_qspi_xc7z_bus_t *qspi_bus, cyg_uint32 data, cyg_uint8 len_burst ) { entry_debug(); cyg_uint8 btemp; if (qspi_bus->lp_rx_buf) { switch (len_burst) { case 1: *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 24) & 0xFF; qspi_bus->lp_rx_buf += 1; break; case 2: *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 16) & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 24) & 0xFF; qspi_bus->lp_rx_buf += 1; break; case 3: *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 8) & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 16) & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 24) & 0xFF; qspi_bus->lp_rx_buf += 1; break; case 4: *((cyg_uint8 *)qspi_bus->lp_rx_buf) = data & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 8) & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 16) & 0xFF; qspi_bus->lp_rx_buf += 1; *((cyg_uint8 *)qspi_bus->lp_rx_buf) = (data >> 24) & 0xFF; qspi_bus->lp_rx_buf += 1; break; default: /* This will never execute */ break; } } if (qspi_bus->us_rx_bytes < len_burst) qspi_bus->us_rx_bytes = 0; else qspi_bus->us_rx_bytes -= len_burst; }
internal void dl_list_debug( entry* head ) { printf("Debug list %p\n", (void*) head ); if( head != NULL ) { entry* start = head; entry* current = head; do { entry_debug( current ); node_debug( current->node ); current = current->next; } while( current != start ); } }
/** * * QSPI bus drop CS function * * @param dev - QSPI device handle * * @return none * *****************************************************************************/ static void qspi_xc7z_drop_cs(cyg_qspi_xc7z_device_t *dev) { entry_debug(); cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)dev->qspi_device.spi_bus; if (!qspi_bus->cs_up) return; // Drop CS CYGACC_CALL_IF_DELAY_US(dev->cs_dw_udly); qspi_xc7z_set_npcs(qspi_bus, 1); qspi_bus->cs_up = false; }
/** * * QSPI bus control chip select signal * * @param qspi_bus - QSPI bus handle * @param val - 1-CS is High, 0-CS is Low. * * @return none * *****************************************************************************/ static void qspi_xc7z_set_npcs(cyg_qspi_xc7z_bus_t *qspi_bus,int val) { entry_debug(); cyg_uint32 reg; HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); if (!val) reg &= ~(1 << XQSPIPS_CR_SSCTRL_SHIFT); else reg |= (1 << XQSPIPS_CR_SSCTRL_SHIFT); HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); }
/** * * QSPI bus initialization function from eCOS * * @return none * *****************************************************************************/ void cyg_qspi_xc7z_bus_init(void) { entry_debug(); #ifdef CYGHWR_DEVS_QSPI_ARM_XC7Z // NOTE: here we let the SPI controller control // the data in, out and clock signals, but // we need to handle the chip selects manually // in order to achieve better chip select control // in between transactions. // Put SPI MISO, MOSI and SPCK pins into peripheral mode qspi_xc7z_init_bus(&cyg_qspi_xc7z_bus0); #endif }
// Remove a node from the cache in order: clean data, clean index, dirty data, dirty index // Make sure we don't evict ones with refcount > 0 as they are in use node* node_cache_evict_node( node_cache* nc ) { node* result = NULL; u32 evict_order[4] = { NC_LIST_DATA_CLEAN, NC_LIST_INDEX_CLEAN, NC_LIST_DATA_DIRTY, NC_LIST_INDEX_DIRTY }; for( u32 i=0; i<4; i++ ) { entry* list = nc->list[ evict_order[i] ]; printf("Trying to evict from list %d\n", i); if( list != NULL ) { dl_list_debug( list ); entry* current = list; do { if( current->refcount == 0 ) { node* to_be_evicted = current->node; printf("\tEviction candidate found: \n"); entry_debug( current ); node_debug( to_be_evicted ); node_store_on_disk( to_be_evicted ); to_be_evicted->flags = 0; // reset all, though only would need ~NODE_FLAG_USED result = to_be_evicted; // we can immediately reuse this one if needed u32 bucket_entry_index = index_from_node_pointer( nc, to_be_evicted ); entry* bucket_entry = &nc->bucket_entries[bucket_entry_index]; u32 bucket_index = bucket_index_from_node( to_be_evicted ); nc->bucket[bucket_index] = dl_list_remove( nc->bucket[bucket_index], bucket_entry ); nc->list[ evict_order[i] ] = dl_list_remove( list, current ); dl_list_debug( nc->list[ evict_order[i] ] ); c.evicts[ evict_order[i] ]++; goto DONE; } current = current->next; } while( current != list ); } } assert( result != NULL ); if( result == NULL ) { printf("[FAIL]: Could not evict any nodes. Maybe all are in use? (refcount > 0)\n"); } DONE: return result; }
/** * * QSPI bus send flash memory instruction function (for Zynq specific QSPI HW). * * @param qspi_bus - QSPI bus handle * * @return none * *****************************************************************************/ static void qspi_xc7z_send_instruction(cyg_qspi_xc7z_bus_t *qspi_bus) { entry_debug(); cyg_uint32 index; cyg_uint8 instruction; cyg_uint32 data = 0; qspi_bus->uc_tx_instr = 0; if ((!qspi_bus->lp_tx_buf) || (!qspi_bus->us_tx_bytes)) return; if (*((cyg_uint8 *)qspi_bus->lp_tx_buf) == 0) return; instruction = *((cyg_uint8 *)qspi_bus->lp_tx_buf); for (index = 0; index < ARRAY_SIZE(qpifFlashInst); index++) if (instruction == qpifFlashInst[index].OpCode) break; if (index == ARRAY_SIZE(qpifFlashInst)) { diag_printf("illegal instruction %02X\n",instruction); return; } qspi_bus->uc_tx_instr = qpifFlashInst[index].OpCode; /* Get the instruction */ qspi_xc7z_copy_write_data(qspi_bus, &data, qpifFlashInst[index].InstSize); /* Write the instruction to LSB of the FIFO. The core is * designed such that it is not necessary to check whether the * write FIFO is full before writing. However, write would be * delayed if the user tries to write when write FIFO is full */ HAL_WRITE_UINT32(qspi_bus->base + qpifFlashInst[index].TxOffset, data); }
/** * * QSPI bus transaction transfer function. * * @param dev - QSPI device handle * @param polled - Poll mode flash: 1-Polled, 0-IRQ * @param count - Number of bytes to transmit. * @param tx_data - Pointer to TX buffer. * @param rx_data - Pointer to RX buffer. * * @return none * *****************************************************************************/ static void qspi_xc7z_transaction_transfer(cyg_spi_device *dev, cyg_bool polled, cyg_uint32 count, const cyg_uint8 *tx_data, cyg_uint8 *rx_data, cyg_bool drop_cs) { entry_debug(); cyg_qspi_xc7z_device_t *xc7z_qspi_dev = (cyg_qspi_xc7z_device_t *) dev; cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)xc7z_qspi_dev->qspi_device.spi_bus; // Setup poiner to buffers qspi_bus->lp_tx_buf = tx_data; qspi_bus->lp_rx_buf = rx_data; qspi_bus->us_tx_bytes = count; qspi_bus->us_rx_bytes = count; // Select the device if not already selected qspi_xc7z_start_transfer(xc7z_qspi_dev); // Perform the transfer if (polled) qspi_xc7z_transfer_polled(xc7z_qspi_dev, count, tx_data, rx_data); else qspi_xc7z_transfer(xc7z_qspi_dev, count, tx_data, rx_data); // Deselect the device if requested if (drop_cs) qspi_xc7z_drop_cs(xc7z_qspi_dev); // Clear pointers qspi_bus->lp_tx_buf = 0; qspi_bus->lp_rx_buf = 0; qspi_bus->us_tx_bytes = 0; qspi_bus->us_rx_bytes = 0; }
/** * * QSPI bus start transfer function * * @param dev - QSPI device handle * * @return none * *****************************************************************************/ static void qspi_xc7z_start_transfer(cyg_qspi_xc7z_device_t *dev) { entry_debug(); cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)dev->qspi_device.spi_bus; if (qspi_bus->cs_up) return; HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_ER_OFFSET, XQSPIPS_ER_ENABLE_MASK); // Force minimal delay between two transfers - in case two transfers // follow each other w/o delay, then we have to wait here in order for // the peripheral device to detect cs transition from inactive to active. CYGACC_CALL_IF_DELAY_US(dev->tr_bt_udly); // Raise CS qspi_xc7z_set_npcs(qspi_bus, 0); CYGACC_CALL_IF_DELAY_US(dev->cs_up_udly); qspi_bus->cs_up = true; qspi_bus->uc_tx_instr = 0; }
/** * * QSPI bus set config function. * * @param dev - QSPI device handle * @param key - IO control number of key * @param buf - Pointer to BUF * @param len - Pointer to length * * @return Status of operation: ENOERR - all good, -EINVAL - fail to find IO control number * *****************************************************************************/ static int qspi_xc7z_set_config(cyg_spi_device *dev, cyg_uint32 key, const void *buf, cyg_uint32 *len) { entry_debug(); cyg_qspi_xc7z_device_t *xc7z_qspi_dev = (cyg_qspi_xc7z_device_t *) dev; switch (key) { case CYG_IO_SET_CONFIG_SPI_CLOCKRATE: { if (*len != sizeof(cyg_uint32)) return -EINVAL; else { cyg_uint32 cl_brate = *((cyg_uint32 *)buf); cyg_uint32 old_cl_brate = xc7z_qspi_dev->cl_brate; xc7z_qspi_dev->cl_brate = cl_brate; if (!qspi_xc7z_calc_bratediv(xc7z_qspi_dev)) { xc7z_qspi_dev->cl_brate = old_cl_brate; qspi_xc7z_calc_bratediv(xc7z_qspi_dev); return -EINVAL; } } } break; default: return -EINVAL; } return ENOERR; }
/** * * QSPI bus transfer with IRQ function. * * @param qspi_bus - QSPI bus handle * @param count - Number of bytes to transmit. * @param tx_data - Pointer to TX buffer. * @param rx_data - Pointer to RX buffer. * * @return none * *****************************************************************************/ static void qspi_xc7z_transfer(cyg_qspi_xc7z_device_t *dev, cyg_uint32 count, const cyg_uint8 *tx_data, cyg_uint8 *rx_data) { entry_debug(); cyg_qspi_xc7z_bus_t *qspi_bus = (cyg_qspi_xc7z_bus_t *)dev->qspi_device.spi_bus; cyg_uint32 val; // Enable device HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_ER_OFFSET, XQSPIPS_ER_ENABLE_MASK); // Enable manual start HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); val |= XQSPIPS_CR_MANSTRTEN_MASK | XQSPIPS_CR_SSFORCE_MASK; HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); // Set tx buf pointer and counter if (NULL != tx_data) HAL_DCACHE_STORE(tx_data, count); // Set rx buf pointer and counter if (NULL != rx_data) HAL_DCACHE_FLUSH(rx_data, count); // Send first instruction if(qspi_bus->uc_tx_instr == 0) qspi_xc7z_send_instruction(qspi_bus); { if ((qspi_bus->us_tx_bytes) && ((qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_FAST_READ) || (qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_DUAL_READ) || (qspi_bus->uc_tx_instr != XQSPIPS_FLASH_OPCODE_QUAD_READ) )) qspi_xc7z_fill_tx_fifo(qspi_bus,count); // Enable the QSPI int events we are interested in HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_IER_OFFSET, XQSPIPS_IXR_TXOW_MASK | XQSPIPS_IXR_MODF_MASK); HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); val |= XQSPIPS_CR_MANSTRT_MASK; HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, val); cyg_drv_mutex_lock(&qspi_bus->transfer_mx); { qspi_bus->transfer_end = false; // Unmask the SPI int cyg_drv_interrupt_unmask(qspi_bus->interrupt_number); // Wait for its completion cyg_drv_dsr_lock(); { while (!qspi_bus->transfer_end) cyg_drv_cond_wait(&qspi_bus->transfer_cond); } cyg_drv_dsr_unlock(); } cyg_drv_mutex_unlock(&qspi_bus->transfer_mx); } }
/** * * QSPI bus TX prepare data function (for Zynq specific FIFO). * * @param qspi_bus - QSPI bus handle * @param data - 4-byte variable which TX data has. * @param len_burst - Size of data in bytes [1..4]. * * @return none * *****************************************************************************/ static void qspi_xc7z_copy_write_data(cyg_qspi_xc7z_bus_t *qspi_bus, cyg_uint32 *data, cyg_uint8 len_burst ) { entry_debug(); cyg_uint8 *d = (cyg_uint8*)qspi_bus->lp_tx_buf; int i; if (qspi_bus->lp_tx_buf) { switch (len_burst) { case 1: *data = *((cyg_uint8 *)qspi_bus->lp_tx_buf); qspi_bus->lp_tx_buf += 1; *data |= 0xFFFFFF00; break; case 2: *data = d[0] | (d[1] << 8); qspi_bus->lp_tx_buf += 2; *data |= 0xFFFF0000; break; case 3: *data = *((cyg_uint16 *)qspi_bus->lp_tx_buf); qspi_bus->lp_tx_buf += 2; *data |= (*((cyg_uint8 *)qspi_bus->lp_tx_buf) << 16); qspi_bus->lp_tx_buf += 1; *data |= 0xFF000000; break; case 4: *data = *((cyg_uint32 *)qspi_bus->lp_tx_buf); qspi_bus->lp_tx_buf += 4; break; default: /* This will never execute */ break; } } else { switch (len_burst) { case 1: *data = 0; *data |= 0xFFFFFF00; break; case 2: *data = 0; *data |= 0xFFFF0000; break; case 3: *data = 0; *data |= 0xFF000000; break; case 4: *data = 0; break; default: /* This will never execute */ break; } } if (qspi_bus->us_tx_bytes < len_burst) qspi_bus->us_tx_bytes = 0; else qspi_bus->us_tx_bytes -= len_burst; }
/** * * QSPI bus initialization function * * @param qspi_bus - Driver handle * * @return none * *****************************************************************************/ static void qspi_xc7z_init_bus(cyg_qspi_xc7z_bus_t * qspi_bus) { entry_debug(); volatile cyg_uint32 reg; // Create and attach SPI interrupt object cyg_drv_interrupt_create(qspi_bus->interrupt_number, 4, (cyg_addrword_t)qspi_bus, qspi_xc7z_ISR, qspi_xc7z_DSR, &qspi_bus->qspi_interrupt_handle, &qspi_bus->qspi_interrupt); cyg_drv_interrupt_attach(qspi_bus->qspi_interrupt_handle); cyg_drv_interrupt_mask(qspi_bus->interrupt_number); // Init transfer mutex and condition cyg_drv_mutex_init(&qspi_bus->transfer_mx); cyg_drv_cond_init(&qspi_bus->transfer_cond, &qspi_bus->transfer_mx); // Init flags qspi_bus->transfer_end = true; qspi_bus->cs_up = false; // Unlock SLCR regs HAL_WRITE_UINT32(XC7Z_SYS_CTRL_BASEADDR + XSLCR_UNLOCK_OFFSET, XSLCR_UNLOCK_KEY); // Enable clock to QSPI module HAL_READ_UINT32( XC7Z_SYS_CTRL_BASEADDR + XSLCRAPER_CLK_CTRL_OFFSET, reg); reg |= XSLCRAPER_CLK_CTRL_QSPI_EN; HAL_WRITE_UINT32(XC7Z_SYS_CTRL_BASEADDR + XSLCRAPER_CLK_CTRL_OFFSET, reg); // Lock SLCR regs HAL_WRITE_UINT32(XC7Z_SYS_CTRL_BASEADDR + XSLCR_LOCK_OFFSET, XSLCR_LOCK_KEY); // Soft reset the SPI controller HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_ER_OFFSET, 0x00); //TODO changed, originally was just setting a value without reading HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); reg &= (1 << 17); // preserve the reserved bit which is described as "do not modify" reg |= (1 << 31); HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); // Disable linear mode HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_LQSPI_CR_OFFSET, 0x00); // Clear status HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_SR_OFFSET, 0x7F); // Clear the RX FIFO HAL_READ_UINT32(qspi_bus->base + XQSPIPS_SR_OFFSET, reg); while (reg & XQSPIPS_IXR_RXNEMPTY_MASK) { HAL_READ_UINT32(qspi_bus->base + XQSPIPS_RXD_OFFSET, reg); HAL_READ_UINT32(qspi_bus->base + XQSPIPS_SR_OFFSET, reg); } HAL_READ_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); reg &= 0xFBFFFFFF; /* Set little endian mode of TX FIFO */ reg |= (XQSPIPS_CR_IFMODE_MASK | XQSPIPS_CR_MANSTRTEN_MASK | XQSPIPS_CR_SSFORCE_MASK | XQSPIPS_CR_SSCTRL_MASK | XQSPIPS_CR_DATA_SZ_MASK | XQSPIPS_CR_MSTREN_MASK); HAL_WRITE_UINT32(qspi_bus->base + XQSPIPS_CR_OFFSET, reg); // Configure SPI pins // All pins was configured in HAL // Call upper layer bus init CYG_SPI_BUS_COMMON_INIT(&qspi_bus->qspi_bus); }