Beispiel #1
0
void OS_dcache_invalidate_mlines(void *addr, uint32_t length)
{
#if (PSP_HAS_DATA_CACHE && USBCFG_BUFF_PROPERTY_CACHEABLE)
    if ((addr < (void *)__UNCACHED_DATA_START) || (((uint32_t)addr + length) > (uint32_t)__UNCACHED_DATA_END))
    {
        if (((uint32_t)addr & (PSP_CACHE_LINE_SIZE - 1)) != 0)
        {
            _dcache_flush_mlines((void *)addr, PSP_CACHE_LINE_SIZE);
        }
        if (((uint32_t)((uint8_t *)addr + length) & (PSP_CACHE_LINE_SIZE - 1)) != 0)
        {
            _dcache_flush_mlines((uint8_t *)addr + length, PSP_CACHE_LINE_SIZE);
        }
        _dcache_invalidate_mlines(addr, length);
    }
#endif
}
static _mqx_int _dspi_dma_tx_rx
    (
        /* [IN] Device specific context structure */
        void                          *io_info_ptr,

        /* [IN] Data to transmit */
        uint8_t                     *txbuf,

        /* [OUT] Received data */
        uint8_t                     *rxbuf,

        /* [IN] Length of transfer in bytes */
        uint32_t                        len
    )
{
    DSPI_DMA_INFO_STRUCT_PTR           dspi_info_ptr = (DSPI_DMA_INFO_STRUCT_PTR)io_info_ptr;
    int                                regw;

    uint32_t                            head_len;
    uint32_t                            tail_len;
    uint32_t                            zero_copy_len;

    _mqx_int                           result;

    /* Check whether there is at least something to transfer */
    if (0 == len) {
        return 0;
    }

    /* Check frame width */
    if (DSPI_CTAR_FMSZ_GET(dspi_info_ptr->DSPI_PTR->CTAR[0]) > 7)
    {
        len = len & (~1UL); /* Round down to whole frames */
        regw = 2;
    }
    else {
        regw = 1;
    }

    /* If there is no data to transmit, prepare dummy pattern in proper byte order */
    if (NULL == txbuf) {
        if (regw == 1) {
            dspi_info_ptr->TX_BUF[0] = dspi_info_ptr->DUMMY_PATTERN & 0xFF;
        }
        else {
            dspi_info_ptr->TX_BUF[0] = (dspi_info_ptr->DUMMY_PATTERN>>8) & 0xFF;
            dspi_info_ptr->TX_BUF[1] = dspi_info_ptr->DUMMY_PATTERN & 0xFF;
        }
        _dcache_flush_line(dspi_info_ptr->TX_BUF);
    }

    if (!(len % PSP_CACHE_LINE_SIZE) && !((uint32_t)txbuf % PSP_CACHE_LINE_SIZE) && !((uint32_t)rxbuf % PSP_CACHE_LINE_SIZE)) {
        /* Everything is perfectly aligned, perform single zero copy operation without any head or tail */
        head_len = 0;
        tail_len = 0;
    }
    else if (len <= 2*PSP_CACHE_LINE_SIZE) {
        /* The whole transfer fits into intermediate buffers, perform single transfer (head only) */
        head_len = len;
        tail_len = 0;
    }
    else {
        /* Split the transfer into head, zero copy portion and tail */
        uint32_t cache_line_offset;

        uint32_t tx_head_len;
        uint32_t tx_tail_len;

        uint32_t rx_head_len;
        uint32_t rx_tail_len;

        if (NULL != rxbuf) {
            cache_line_offset = (uint32_t)rxbuf % PSP_CACHE_LINE_SIZE;
            rx_head_len = cache_line_offset ? PSP_CACHE_LINE_SIZE - cache_line_offset : 0;
            rx_tail_len = (((uint32_t)rxbuf + len) % PSP_CACHE_LINE_SIZE);
        }
        else {
            rx_head_len = 0;
            rx_tail_len = 0;
        }

        if (NULL != txbuf) {
            cache_line_offset = (uint32_t)txbuf % PSP_CACHE_LINE_SIZE;
            tx_head_len = cache_line_offset ? PSP_CACHE_LINE_SIZE - cache_line_offset : 0;
            tx_tail_len = (((uint32_t)txbuf + len) % PSP_CACHE_LINE_SIZE);

        }
        else {
            tx_head_len = 0;
            tx_tail_len = 0;
        }

        head_len = (rx_head_len > tx_head_len) ? rx_head_len : tx_head_len;
        tail_len = (rx_tail_len > tx_tail_len) ? rx_tail_len : tx_tail_len;

        if (regw > 1) {
            head_len += (head_len & 1);
            tail_len += (tail_len & 1);
        }
    }

    zero_copy_len =  len - head_len - tail_len;

    /* Head processed through intermediate buffers */
    if (head_len) {
        if (txbuf) {
            _mem_copy(txbuf, dspi_info_ptr->TX_BUF, head_len);
            _dcache_flush_mlines(dspi_info_ptr->TX_BUF, len);
            result = _dspi_dma_transfer(dspi_info_ptr, dspi_info_ptr->TX_BUF, dspi_info_ptr->RX_BUF, head_len, regw);
        }
        else {
            result = _dspi_dma_transfer(dspi_info_ptr, NULL, dspi_info_ptr->RX_BUF, head_len, regw);
        }
        if (result != head_len) {
            return IO_ERROR;
        }
        /*
         * Copy to application buffer intentionally ommited.
         * It is done later after invalidation of zero copy area as it may overlap into it.
         */
    }

    /* Zero copy area */
    if (zero_copy_len) {
        uint8_t *txbuf_real;
        uint8_t *rxbuf_real;

        txbuf_real = txbuf ? txbuf + head_len : NULL;
        rxbuf_real = rxbuf ? rxbuf + head_len : NULL;

        if (txbuf_real) {
            _dcache_flush_mlines(txbuf_real, zero_copy_len);
        }
        result = _dspi_dma_transfer(dspi_info_ptr, txbuf_real, rxbuf_real, zero_copy_len, regw);
        if (rxbuf_real)
        {
            _dcache_invalidate_mlines(rxbuf_real, zero_copy_len);
        }

        if (result != zero_copy_len) {
            return IO_ERROR;
        }
    }

    /* Copy head data into application buffer if desired */
    if (head_len && rxbuf) {
       _dcache_invalidate_mlines(dspi_info_ptr->RX_BUF, head_len);
       _mem_copy(dspi_info_ptr->RX_BUF, rxbuf, head_len);
    }

    /* Tail processed through intermediate buffers */
    if (tail_len) {
        if (txbuf) {
            _mem_copy(txbuf + len - tail_len, dspi_info_ptr->TX_BUF, tail_len);
            _dcache_flush_mlines(dspi_info_ptr->TX_BUF, tail_len);
            result = _dspi_dma_transfer(dspi_info_ptr, dspi_info_ptr->TX_BUF, dspi_info_ptr->RX_BUF, tail_len, regw);
        }
        else {
            result = _dspi_dma_transfer(dspi_info_ptr, NULL, dspi_info_ptr->RX_BUF, tail_len, regw);
        }
        if (result != tail_len) {
            return IO_ERROR;
        }
        if (rxbuf) {
            _dcache_invalidate_mlines(dspi_info_ptr->RX_BUF, tail_len);
            _mem_copy(dspi_info_ptr->RX_BUF, rxbuf + len - tail_len, tail_len);
        }
    }

    return len;
}