2014-03-17 17:52:35 -05:00
/* Altera TSE SGDMA and MSGDMA Linux driver
* Copyright ( C ) 2014 Altera Corporation . All rights reserved
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <linux/netdevice.h>
# include "altera_utils.h"
# include "altera_tse.h"
# include "altera_msgdmahw.h"
2014-04-28 23:23:13 +02:00
# include "altera_msgdma.h"
2014-03-17 17:52:35 -05:00
/* No initialization work to do for MSGDMA */
int msgdma_initialize ( struct altera_tse_private * priv )
{
return 0 ;
}
void msgdma_uninitialize ( struct altera_tse_private * priv )
{
}
2014-04-24 16:58:08 -05:00
void msgdma_start_rxdma ( struct altera_tse_private * priv )
{
}
2014-03-17 17:52:35 -05:00
void msgdma_reset ( struct altera_tse_private * priv )
{
int counter ;
/* Reset Rx mSGDMA */
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_MASK , priv - > rx_dma_csr ,
msgdma_csroffs ( status ) ) ;
csrwr32 ( MSGDMA_CSR_CTL_RESET , priv - > rx_dma_csr ,
msgdma_csroffs ( control ) ) ;
2014-03-17 17:52:35 -05:00
counter = 0 ;
while ( counter + + < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR ) {
2014-05-14 14:38:36 -05:00
if ( tse_bit_is_clear ( priv - > rx_dma_csr , msgdma_csroffs ( status ) ,
2014-03-17 17:52:35 -05:00
MSGDMA_CSR_STAT_RESETTING ) )
break ;
udelay ( 1 ) ;
}
if ( counter > = ALTERA_TSE_SW_RESET_WATCHDOG_CNTR )
netif_warn ( priv , drv , priv - > dev ,
" TSE Rx mSGDMA resetting bit never cleared! \n " ) ;
/* clear all status bits */
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_MASK , priv - > rx_dma_csr , msgdma_csroffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
/* Reset Tx mSGDMA */
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_MASK , priv - > tx_dma_csr ,
msgdma_csroffs ( status ) ) ;
csrwr32 ( MSGDMA_CSR_CTL_RESET , priv - > tx_dma_csr ,
msgdma_csroffs ( control ) ) ;
2014-03-17 17:52:35 -05:00
counter = 0 ;
while ( counter + + < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR ) {
2014-05-14 14:38:36 -05:00
if ( tse_bit_is_clear ( priv - > tx_dma_csr , msgdma_csroffs ( status ) ,
2014-03-17 17:52:35 -05:00
MSGDMA_CSR_STAT_RESETTING ) )
break ;
udelay ( 1 ) ;
}
if ( counter > = ALTERA_TSE_SW_RESET_WATCHDOG_CNTR )
netif_warn ( priv , drv , priv - > dev ,
" TSE Tx mSGDMA resetting bit never cleared! \n " ) ;
/* clear all status bits */
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_MASK , priv - > tx_dma_csr , msgdma_csroffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_disable_rxirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
tse_clear_bit ( priv - > rx_dma_csr , msgdma_csroffs ( control ) ,
MSGDMA_CSR_CTL_GLOBAL_INTR ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_enable_rxirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
tse_set_bit ( priv - > rx_dma_csr , msgdma_csroffs ( control ) ,
MSGDMA_CSR_CTL_GLOBAL_INTR ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_disable_txirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
tse_clear_bit ( priv - > tx_dma_csr , msgdma_csroffs ( control ) ,
MSGDMA_CSR_CTL_GLOBAL_INTR ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_enable_txirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
tse_set_bit ( priv - > tx_dma_csr , msgdma_csroffs ( control ) ,
MSGDMA_CSR_CTL_GLOBAL_INTR ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_clear_rxirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_IRQ , priv - > rx_dma_csr , msgdma_csroffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
}
void msgdma_clear_txirq ( struct altera_tse_private * priv )
{
2014-05-14 14:38:36 -05:00
csrwr32 ( MSGDMA_CSR_STAT_IRQ , priv - > tx_dma_csr , msgdma_csroffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
}
/* return 0 to indicate transmit is pending */
int msgdma_tx_buffer ( struct altera_tse_private * priv , struct tse_buffer * buffer )
{
2014-05-14 14:38:36 -05:00
csrwr32 ( lower_32_bits ( buffer - > dma_addr ) , priv - > tx_dma_desc ,
msgdma_descroffs ( read_addr_lo ) ) ;
csrwr32 ( upper_32_bits ( buffer - > dma_addr ) , priv - > tx_dma_desc ,
msgdma_descroffs ( read_addr_hi ) ) ;
csrwr32 ( 0 , priv - > tx_dma_desc , msgdma_descroffs ( write_addr_lo ) ) ;
csrwr32 ( 0 , priv - > tx_dma_desc , msgdma_descroffs ( write_addr_hi ) ) ;
csrwr32 ( buffer - > len , priv - > tx_dma_desc , msgdma_descroffs ( len ) ) ;
csrwr32 ( 0 , priv - > tx_dma_desc , msgdma_descroffs ( burst_seq_num ) ) ;
csrwr32 ( MSGDMA_DESC_TX_STRIDE , priv - > tx_dma_desc ,
msgdma_descroffs ( stride ) ) ;
csrwr32 ( MSGDMA_DESC_CTL_TX_SINGLE , priv - > tx_dma_desc ,
msgdma_descroffs ( control ) ) ;
2014-03-17 17:52:35 -05:00
return 0 ;
}
u32 msgdma_tx_completions ( struct altera_tse_private * priv )
{
u32 ready = 0 ;
u32 inuse ;
u32 status ;
/* Get number of sent descriptors */
2014-05-14 14:38:36 -05:00
inuse = csrrd32 ( priv - > tx_dma_csr , msgdma_csroffs ( rw_fill_level ) )
& 0xffff ;
2014-03-17 17:52:35 -05:00
if ( inuse ) { /* Tx FIFO is not empty */
ready = priv - > tx_prod - priv - > tx_cons - inuse - 1 ;
} else {
/* Check for buffered last packet */
2014-05-14 14:38:36 -05:00
status = csrrd32 ( priv - > tx_dma_csr , msgdma_csroffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
if ( status & MSGDMA_CSR_STAT_BUSY )
ready = priv - > tx_prod - priv - > tx_cons - 1 ;
else
ready = priv - > tx_prod - priv - > tx_cons ;
}
return ready ;
}
/* Put buffer to the mSGDMA RX FIFO
*/
2014-04-24 16:58:08 -05:00
void msgdma_add_rx_desc ( struct altera_tse_private * priv ,
2014-03-17 17:52:35 -05:00
struct tse_buffer * rxbuffer )
{
u32 len = priv - > rx_dma_buf_sz ;
dma_addr_t dma_addr = rxbuffer - > dma_addr ;
u32 control = ( MSGDMA_DESC_CTL_END_ON_EOP
| MSGDMA_DESC_CTL_END_ON_LEN
| MSGDMA_DESC_CTL_TR_COMP_IRQ
| MSGDMA_DESC_CTL_EARLY_IRQ
| MSGDMA_DESC_CTL_TR_ERR_IRQ
| MSGDMA_DESC_CTL_GO ) ;
2014-05-14 14:38:36 -05:00
csrwr32 ( 0 , priv - > rx_dma_desc , msgdma_descroffs ( read_addr_lo ) ) ;
csrwr32 ( 0 , priv - > rx_dma_desc , msgdma_descroffs ( read_addr_hi ) ) ;
csrwr32 ( lower_32_bits ( dma_addr ) , priv - > rx_dma_desc ,
msgdma_descroffs ( write_addr_lo ) ) ;
csrwr32 ( upper_32_bits ( dma_addr ) , priv - > rx_dma_desc ,
msgdma_descroffs ( write_addr_hi ) ) ;
csrwr32 ( len , priv - > rx_dma_desc , msgdma_descroffs ( len ) ) ;
csrwr32 ( 0 , priv - > rx_dma_desc , msgdma_descroffs ( burst_seq_num ) ) ;
csrwr32 ( 0x00010001 , priv - > rx_dma_desc , msgdma_descroffs ( stride ) ) ;
csrwr32 ( control , priv - > rx_dma_desc , msgdma_descroffs ( control ) ) ;
2014-03-17 17:52:35 -05:00
}
/* status is returned on upper 16 bits,
* length is returned in lower 16 bits
*/
u32 msgdma_rx_status ( struct altera_tse_private * priv )
{
u32 rxstatus = 0 ;
u32 pktlength ;
u32 pktstatus ;
2014-05-14 14:38:36 -05:00
if ( csrrd32 ( priv - > rx_dma_csr , msgdma_csroffs ( resp_fill_level ) )
& 0xffff ) {
pktlength = csrrd32 ( priv - > rx_dma_resp ,
msgdma_respoffs ( bytes_transferred ) ) ;
pktstatus = csrrd32 ( priv - > rx_dma_resp ,
msgdma_respoffs ( status ) ) ;
2014-03-17 17:52:35 -05:00
rxstatus = pktstatus ;
rxstatus = rxstatus < < 16 ;
rxstatus | = ( pktlength & 0xffff ) ;
}
return rxstatus ;
}