2011-11-17 23:17:04 +08:00
/*
* Driver for CSR SiRFprimaII onboard UARTs .
*
* Copyright ( c ) 2011 Cambridge Silicon Radio Limited , a CSR plc group company .
*
* Licensed under GPLv2 or later .
*/
# include <linux/module.h>
# include <linux/ioport.h>
# include <linux/platform_device.h>
# include <linux/init.h>
# include <linux/sysrq.h>
# include <linux/console.h>
# include <linux/tty.h>
# include <linux/tty_flip.h>
# include <linux/serial_core.h>
# include <linux/serial.h>
# include <linux/clk.h>
# include <linux/of.h>
# include <linux/slab.h>
# include <linux/io.h>
2013-08-15 06:52:15 +08:00
# include <linux/of_gpio.h>
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
# include <linux/dmaengine.h>
# include <linux/dma-direction.h>
# include <linux/dma-mapping.h>
2011-11-17 23:17:04 +08:00
# include <asm/irq.h>
# include <asm/mach/irq.h>
# include "sirfsoc_uart.h"
static unsigned int
sirfsoc_uart_pio_tx_chars ( struct sirfsoc_uart_port * sirfport , int count ) ;
static unsigned int
sirfsoc_uart_pio_rx_chars ( struct uart_port * port , unsigned int max_rx_count ) ;
static struct uart_driver sirfsoc_uart_drv ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
static void sirfsoc_uart_tx_dma_complete_callback ( void * param ) ;
static void sirfsoc_uart_start_next_rx_dma ( struct uart_port * port ) ;
static void sirfsoc_uart_rx_dma_complete_callback ( void * param ) ;
2011-11-17 23:17:04 +08:00
static const struct sirfsoc_baudrate_to_regv baudrate_to_regv [ ] = {
{ 4000000 , 2359296 } ,
{ 3500000 , 1310721 } ,
{ 3000000 , 1572865 } ,
{ 2500000 , 1245186 } ,
{ 2000000 , 1572866 } ,
{ 1500000 , 1245188 } ,
{ 1152000 , 1638404 } ,
{ 1000000 , 1572869 } ,
{ 921600 , 1114120 } ,
{ 576000 , 1245196 } ,
{ 500000 , 1245198 } ,
{ 460800 , 1572876 } ,
{ 230400 , 1310750 } ,
{ 115200 , 1310781 } ,
{ 57600 , 1310843 } ,
{ 38400 , 1114328 } ,
{ 19200 , 1114545 } ,
{ 9600 , 1114979 } ,
} ;
static struct sirfsoc_uart_port sirfsoc_uart_ports [ SIRFSOC_UART_NR ] = {
[ 0 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 0 ,
} ,
} ,
[ 1 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 1 ,
} ,
} ,
[ 2 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 2 ,
} ,
} ,
2012-12-25 17:32:04 +08:00
[ 3 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 3 ,
} ,
} ,
[ 4 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 4 ,
} ,
} ,
2013-08-25 20:18:41 +08:00
[ 5 ] = {
. port = {
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF ,
. line = 5 ,
} ,
} ,
2011-11-17 23:17:04 +08:00
} ;
static inline struct sirfsoc_uart_port * to_sirfport ( struct uart_port * port )
{
return container_of ( port , struct sirfsoc_uart_port , port ) ;
}
static inline unsigned int sirfsoc_uart_tx_empty ( struct uart_port * port )
{
unsigned long reg ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_fifo_status * ufifo_st = & sirfport - > uart_reg - > fifo_status ;
reg = rd_regl ( port , ureg - > sirfsoc_tx_fifo_status ) ;
return ( reg & ufifo_st - > ff_empty ( port - > line ) ) ? TIOCSER_TEMT : 0 ;
2011-11-17 23:17:04 +08:00
}
static unsigned int sirfsoc_uart_get_mctrl ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
2013-08-15 06:52:15 +08:00
if ( ! sirfport - > hw_flow_ctrl | | ! sirfport - > ms_enabled )
2011-11-17 23:17:04 +08:00
goto cts_asserted ;
2013-08-15 06:52:15 +08:00
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
2013-08-12 18:15:35 +08:00
if ( ! ( rd_regl ( port , ureg - > sirfsoc_afc_ctrl ) &
SIRFUART_AFC_CTS_STATUS ) )
2011-11-17 23:17:04 +08:00
goto cts_asserted ;
else
goto cts_deasserted ;
2013-08-15 06:52:15 +08:00
} else {
if ( ! gpio_get_value ( sirfport - > cts_gpio ) )
goto cts_asserted ;
else
goto cts_deasserted ;
2011-11-17 23:17:04 +08:00
}
cts_deasserted :
return TIOCM_CAR | TIOCM_DSR ;
cts_asserted :
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS ;
}
static void sirfsoc_uart_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
2011-11-17 23:17:04 +08:00
unsigned int assert = mctrl & TIOCM_RTS ;
unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0 ;
unsigned int current_val ;
2013-08-15 06:52:15 +08:00
if ( ! sirfport - > hw_flow_ctrl | | ! sirfport - > ms_enabled )
return ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
2013-08-12 18:15:35 +08:00
current_val = rd_regl ( port , ureg - > sirfsoc_afc_ctrl ) & ~ 0xFF ;
2011-11-17 23:17:04 +08:00
val | = current_val ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_afc_ctrl , val ) ;
2013-08-15 06:52:15 +08:00
} else {
if ( ! val )
gpio_set_value ( sirfport - > rts_gpio , 1 ) ;
else
gpio_set_value ( sirfport - > rts_gpio , 0 ) ;
2011-11-17 23:17:04 +08:00
}
}
static void sirfsoc_uart_stop_tx ( struct uart_port * port )
{
2013-08-07 13:35:38 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2013-08-07 13:35:38 +08:00
2014-01-30 13:57:29 +08:00
if ( sirfport - > tx_dma_chan ) {
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
if ( sirfport - > tx_dma_state = = TX_DMA_RUNNING ) {
dmaengine_pause ( sirfport - > tx_dma_chan ) ;
sirfport - > tx_dma_state = TX_DMA_PAUSE ;
} else {
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ uint_en - > sirfsoc_txfifo_empty_en ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_txfifo_empty_en ) ;
}
} else {
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ uint_en - > sirfsoc_txfifo_empty_en ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_txfifo_empty_en ) ;
}
}
static void sirfsoc_uart_tx_with_dma ( struct sirfsoc_uart_port * sirfport )
{
struct uart_port * port = & sirfport - > port ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
struct circ_buf * xmit = & port - > state - > xmit ;
unsigned long tran_size ;
unsigned long tran_start ;
unsigned long pio_tx_size ;
tran_size = CIRC_CNT_TO_END ( xmit - > head , xmit - > tail , UART_XMIT_SIZE ) ;
tran_start = ( unsigned long ) ( xmit - > buf + xmit - > tail ) ;
if ( uart_circ_empty ( xmit ) | | uart_tx_stopped ( port ) | |
! tran_size )
return ;
if ( sirfport - > tx_dma_state = = TX_DMA_PAUSE ) {
dmaengine_resume ( sirfport - > tx_dma_chan ) ;
return ;
}
if ( sirfport - > tx_dma_state = = TX_DMA_RUNNING )
return ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( uint_en - > sirfsoc_txfifo_empty_en ) ) ;
else
2013-08-12 18:15:35 +08:00
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_txfifo_empty_en ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
/*
* DMA requires buffer address and buffer length are both aligned with
* 4 bytes , so we use PIO for
* 1. if address is not aligned with 4 bytes , use PIO for the first 1 ~ 3
* bytes , and move to DMA for the left part aligned with 4 bytes
* 2. if buffer length is not aligned with 4 bytes , use DMA for aligned
* part first , move to PIO for the left 1 ~ 3 bytes
*/
if ( tran_size < 4 | | BYTES_TO_ALIGN ( tran_start ) ) {
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_STOP ) ;
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ) |
SIRFUART_IO_MODE ) ;
if ( BYTES_TO_ALIGN ( tran_start ) ) {
pio_tx_size = sirfsoc_uart_pio_tx_chars ( sirfport ,
BYTES_TO_ALIGN ( tran_start ) ) ;
tran_size - = pio_tx_size ;
}
if ( tran_size < 4 )
sirfsoc_uart_pio_tx_chars ( sirfport , tran_size ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) |
uint_en - > sirfsoc_txfifo_empty_en ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
uint_en - > sirfsoc_txfifo_empty_en ) ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_START ) ;
} else {
/* tx transfer mode switch into dma mode */
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_STOP ) ;
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ) &
~ SIRFUART_IO_MODE ) ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_START ) ;
tran_size & = ~ ( 0x3 ) ;
sirfport - > tx_dma_addr = dma_map_single ( port - > dev ,
xmit - > buf + xmit - > tail ,
tran_size , DMA_TO_DEVICE ) ;
sirfport - > tx_dma_desc = dmaengine_prep_slave_single (
sirfport - > tx_dma_chan , sirfport - > tx_dma_addr ,
tran_size , DMA_MEM_TO_DEV , DMA_PREP_INTERRUPT ) ;
if ( ! sirfport - > tx_dma_desc ) {
dev_err ( port - > dev , " DMA prep slave single fail \n " ) ;
return ;
}
sirfport - > tx_dma_desc - > callback =
sirfsoc_uart_tx_dma_complete_callback ;
sirfport - > tx_dma_desc - > callback_param = ( void * ) sirfport ;
sirfport - > transfer_size = tran_size ;
dmaengine_submit ( sirfport - > tx_dma_desc ) ;
dma_async_issue_pending ( sirfport - > tx_dma_chan ) ;
sirfport - > tx_dma_state = TX_DMA_RUNNING ;
}
2011-11-17 23:17:04 +08:00
}
2013-08-08 17:41:43 +09:00
static void sirfsoc_uart_start_tx ( struct uart_port * port )
2011-11-17 23:17:04 +08:00
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > tx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfsoc_uart_tx_with_dma ( sirfport ) ;
else {
2014-07-03 21:26:59 +08:00
sirfsoc_uart_pio_tx_chars ( sirfport ,
SIRFSOC_UART_IO_TX_REASONABLE_CNT ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_START ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) |
uint_en - > sirfsoc_txfifo_empty_en ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
uint_en - > sirfsoc_txfifo_empty_en ) ;
}
2011-11-17 23:17:04 +08:00
}
static void sirfsoc_uart_stop_rx ( struct uart_port * port )
{
2013-08-07 13:35:38 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , 0 ) ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan ) {
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( SIRFUART_RX_DMA_INT_EN ( port , uint_en ) |
uint_en - > sirfsoc_rx_done_en ) ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
SIRFUART_RX_DMA_INT_EN ( port , uint_en ) |
uint_en - > sirfsoc_rx_done_en ) ;
dmaengine_terminate_all ( sirfport - > rx_dma_chan ) ;
} else {
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( SIRFUART_RX_IO_INT_EN ( port , uint_en ) ) ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
SIRFUART_RX_IO_INT_EN ( port , uint_en ) ) ;
}
2011-11-17 23:17:04 +08:00
}
static void sirfsoc_uart_disable_ms ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2013-08-07 13:35:38 +08:00
2011-11-17 23:17:04 +08:00
if ( ! sirfport - > hw_flow_ctrl )
return ;
2013-08-15 06:52:15 +08:00
sirfport - > ms_enabled = false ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
wr_regl ( port , ureg - > sirfsoc_afc_ctrl ,
rd_regl ( port , ureg - > sirfsoc_afc_ctrl ) & ~ 0x3FF ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
2013-08-15 06:52:15 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ uint_en - > sirfsoc_cts_en ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_cts_en ) ;
2013-08-12 18:15:35 +08:00
} else
2013-08-15 06:52:15 +08:00
disable_irq ( gpio_to_irq ( sirfport - > cts_gpio ) ) ;
}
static irqreturn_t sirfsoc_uart_usp_cts_handler ( int irq , void * dev_id )
{
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) dev_id ;
struct uart_port * port = & sirfport - > port ;
2014-05-26 19:02:07 +08:00
spin_lock ( & port - > lock ) ;
2013-08-15 06:52:15 +08:00
if ( gpio_is_valid ( sirfport - > cts_gpio ) & & sirfport - > ms_enabled )
uart_handle_cts_change ( port ,
! gpio_get_value ( sirfport - > cts_gpio ) ) ;
2014-05-26 19:02:07 +08:00
spin_unlock ( & port - > lock ) ;
2013-08-15 06:52:15 +08:00
return IRQ_HANDLED ;
2011-11-17 23:17:04 +08:00
}
static void sirfsoc_uart_enable_ms ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2013-08-07 13:35:38 +08:00
2011-11-17 23:17:04 +08:00
if ( ! sirfport - > hw_flow_ctrl )
return ;
2013-08-15 06:52:15 +08:00
sirfport - > ms_enabled = true ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
wr_regl ( port , ureg - > sirfsoc_afc_ctrl ,
rd_regl ( port , ureg - > sirfsoc_afc_ctrl ) |
SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
2013-08-15 06:52:15 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg )
| uint_en - > sirfsoc_cts_en ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
uint_en - > sirfsoc_cts_en ) ;
2013-08-12 18:15:35 +08:00
} else
2013-08-15 06:52:15 +08:00
enable_irq ( gpio_to_irq ( sirfport - > cts_gpio ) ) ;
2011-11-17 23:17:04 +08:00
}
static void sirfsoc_uart_break_ctl ( struct uart_port * port , int break_state )
{
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
unsigned long ulcon = rd_regl ( port , ureg - > sirfsoc_line_ctrl ) ;
if ( break_state )
ulcon | = SIRFUART_SET_BREAK ;
else
ulcon & = ~ SIRFUART_SET_BREAK ;
wr_regl ( port , ureg - > sirfsoc_line_ctrl , ulcon ) ;
}
2011-11-17 23:17:04 +08:00
}
static unsigned int
sirfsoc_uart_pio_rx_chars ( struct uart_port * port , unsigned int max_rx_count )
{
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_fifo_status * ufifo_st = & sirfport - > uart_reg - > fifo_status ;
2011-11-17 23:17:04 +08:00
unsigned int ch , rx_count = 0 ;
2013-08-12 18:15:35 +08:00
struct tty_struct * tty ;
tty = tty_port_tty_get ( & port - > state - > port ) ;
if ( ! tty )
return - ENODEV ;
while ( ! ( rd_regl ( port , ureg - > sirfsoc_rx_fifo_status ) &
ufifo_st - > ff_empty ( port - > line ) ) ) {
ch = rd_regl ( port , ureg - > sirfsoc_rx_fifo_data ) |
SIRFUART_DUMMY_READ ;
2011-11-17 23:17:04 +08:00
if ( unlikely ( uart_handle_sysrq_char ( port , ch ) ) )
continue ;
uart_insert_char ( port , 0 , 0 , ch , TTY_NORMAL ) ;
rx_count + + ;
if ( rx_count > = max_rx_count )
break ;
}
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > rx_io_count + = rx_count ;
2011-11-17 23:17:04 +08:00
port - > icount . rx + = rx_count ;
2013-08-19 20:14:28 +05:30
2011-11-17 23:17:04 +08:00
return rx_count ;
}
static unsigned int
sirfsoc_uart_pio_tx_chars ( struct sirfsoc_uart_port * sirfport , int count )
{
struct uart_port * port = & sirfport - > port ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_fifo_status * ufifo_st = & sirfport - > uart_reg - > fifo_status ;
2011-11-17 23:17:04 +08:00
struct circ_buf * xmit = & port - > state - > xmit ;
unsigned int num_tx = 0 ;
while ( ! uart_circ_empty ( xmit ) & &
2013-08-12 18:15:35 +08:00
! ( rd_regl ( port , ureg - > sirfsoc_tx_fifo_status ) &
ufifo_st - > ff_full ( port - > line ) ) & &
2011-11-17 23:17:04 +08:00
count - - ) {
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_fifo_data ,
xmit - > buf [ xmit - > tail ] ) ;
2011-11-17 23:17:04 +08:00
xmit - > tail = ( xmit - > tail + 1 ) & ( UART_XMIT_SIZE - 1 ) ;
port - > icount . tx + + ;
num_tx + + ;
}
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
return num_tx ;
}
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
static void sirfsoc_uart_tx_dma_complete_callback ( void * param )
{
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) param ;
struct uart_port * port = & sirfport - > port ;
struct circ_buf * xmit = & port - > state - > xmit ;
unsigned long flags ;
2014-05-26 19:02:07 +08:00
spin_lock_irqsave ( & port - > lock , flags ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
xmit - > tail = ( xmit - > tail + sirfport - > transfer_size ) &
( UART_XMIT_SIZE - 1 ) ;
port - > icount . tx + = sirfport - > transfer_size ;
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
if ( sirfport - > tx_dma_addr )
dma_unmap_single ( port - > dev , sirfport - > tx_dma_addr ,
sirfport - > transfer_size , DMA_TO_DEVICE ) ;
sirfport - > tx_dma_state = TX_DMA_IDLE ;
sirfsoc_uart_tx_with_dma ( sirfport ) ;
2014-05-26 19:02:07 +08:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
}
static void sirfsoc_uart_insert_rx_buf_to_tty (
struct sirfsoc_uart_port * sirfport , int count )
{
struct uart_port * port = & sirfport - > port ;
struct tty_port * tport = & port - > state - > port ;
int inserted ;
inserted = tty_insert_flip_string ( tport ,
sirfport - > rx_dma_items [ sirfport - > rx_completed ] . xmit . buf , count ) ;
port - > icount . rx + = inserted ;
}
static void sirfsoc_rx_submit_one_dma_desc ( struct uart_port * port , int index )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
sirfport - > rx_dma_items [ index ] . xmit . tail =
sirfport - > rx_dma_items [ index ] . xmit . head = 0 ;
sirfport - > rx_dma_items [ index ] . desc =
dmaengine_prep_slave_single ( sirfport - > rx_dma_chan ,
sirfport - > rx_dma_items [ index ] . dma_addr , SIRFSOC_RX_DMA_BUF_SIZE ,
DMA_DEV_TO_MEM , DMA_PREP_INTERRUPT ) ;
if ( ! sirfport - > rx_dma_items [ index ] . desc ) {
dev_err ( port - > dev , " DMA slave single fail \n " ) ;
return ;
}
sirfport - > rx_dma_items [ index ] . desc - > callback =
sirfsoc_uart_rx_dma_complete_callback ;
sirfport - > rx_dma_items [ index ] . desc - > callback_param = sirfport ;
sirfport - > rx_dma_items [ index ] . cookie =
dmaengine_submit ( sirfport - > rx_dma_items [ index ] . desc ) ;
dma_async_issue_pending ( sirfport - > rx_dma_chan ) ;
}
static void sirfsoc_rx_tmo_process_tl ( unsigned long param )
{
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) param ;
struct uart_port * port = & sirfport - > port ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
struct sirfsoc_int_status * uint_st = & sirfport - > uart_reg - > uart_int_st ;
unsigned int count ;
unsigned long flags ;
2014-01-03 15:44:08 +08:00
struct dma_tx_state tx_state ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
2014-05-26 19:02:07 +08:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2014-01-03 15:44:08 +08:00
while ( DMA_COMPLETE = = dmaengine_tx_status ( sirfport - > rx_dma_chan ,
sirfport - > rx_dma_items [ sirfport - > rx_completed ] . cookie , & tx_state ) ) {
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfsoc_uart_insert_rx_buf_to_tty ( sirfport ,
SIRFSOC_RX_DMA_BUF_SIZE ) ;
2013-09-21 09:02:10 +08:00
sirfport - > rx_completed + + ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > rx_completed % = SIRFSOC_RX_LOOP_BUF_CNT ;
}
count = CIRC_CNT ( sirfport - > rx_dma_items [ sirfport - > rx_issued ] . xmit . head ,
sirfport - > rx_dma_items [ sirfport - > rx_issued ] . xmit . tail ,
SIRFSOC_RX_DMA_BUF_SIZE ) ;
if ( count > 0 )
sirfsoc_uart_insert_rx_buf_to_tty ( sirfport , count ) ;
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ) |
SIRFUART_IO_MODE ) ;
2014-01-27 14:23:39 +08:00
sirfsoc_uart_pio_rx_chars ( port , 4 - sirfport - > rx_io_count ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
if ( sirfport - > rx_io_count = = 4 ) {
sirfport - > rx_io_count = 0 ;
wr_regl ( port , ureg - > sirfsoc_int_st_reg ,
uint_st - > sirfsoc_rx_done ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( uint_en - > sirfsoc_rx_done_en ) ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_rx_done_en ) ;
sirfsoc_uart_start_next_rx_dma ( port ) ;
} else {
wr_regl ( port , ureg - > sirfsoc_int_st_reg ,
uint_st - > sirfsoc_rx_done ) ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) |
( uint_en - > sirfsoc_rx_done_en ) ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
uint_en - > sirfsoc_rx_done_en ) ;
}
2014-05-26 19:02:07 +08:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
tty_flip_buffer_push ( & port - > state - > port ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
}
static void sirfsoc_uart_handle_rx_tmo ( struct sirfsoc_uart_port * sirfport )
{
struct uart_port * port = & sirfport - > port ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
struct dma_tx_state tx_state ;
dmaengine_tx_status ( sirfport - > rx_dma_chan ,
sirfport - > rx_dma_items [ sirfport - > rx_issued ] . cookie , & tx_state ) ;
dmaengine_terminate_all ( sirfport - > rx_dma_chan ) ;
sirfport - > rx_dma_items [ sirfport - > rx_issued ] . xmit . head =
SIRFSOC_RX_DMA_BUF_SIZE - tx_state . residue ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( uint_en - > sirfsoc_rx_timeout_en ) ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_rx_timeout_en ) ;
tasklet_schedule ( & sirfport - > rx_tmo_process_tasklet ) ;
}
static void sirfsoc_uart_handle_rx_done ( struct sirfsoc_uart_port * sirfport )
{
struct uart_port * port = & sirfport - > port ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
struct sirfsoc_int_status * uint_st = & sirfport - > uart_reg - > uart_int_st ;
sirfsoc_uart_pio_rx_chars ( port , 4 - sirfport - > rx_io_count ) ;
if ( sirfport - > rx_io_count = = 4 ) {
sirfport - > rx_io_count = 0 ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
~ ( uint_en - > sirfsoc_rx_done_en ) ) ;
else
wr_regl ( port , SIRFUART_INT_EN_CLR ,
uint_en - > sirfsoc_rx_done_en ) ;
wr_regl ( port , ureg - > sirfsoc_int_st_reg ,
uint_st - > sirfsoc_rx_timeout ) ;
sirfsoc_uart_start_next_rx_dma ( port ) ;
}
}
2011-11-17 23:17:04 +08:00
static irqreturn_t sirfsoc_uart_isr ( int irq , void * dev_id )
{
unsigned long intr_status ;
unsigned long cts_status ;
unsigned long flag = TTY_NORMAL ;
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) dev_id ;
struct uart_port * port = & sirfport - > port ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_fifo_status * ufifo_st = & sirfport - > uart_reg - > fifo_status ;
struct sirfsoc_int_status * uint_st = & sirfport - > uart_reg - > uart_int_st ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2011-11-17 23:17:04 +08:00
struct uart_state * state = port - > state ;
struct circ_buf * xmit = & port - > state - > xmit ;
2012-12-25 17:32:04 +08:00
spin_lock ( & port - > lock ) ;
2013-08-12 18:15:35 +08:00
intr_status = rd_regl ( port , ureg - > sirfsoc_int_st_reg ) ;
wr_regl ( port , ureg - > sirfsoc_int_st_reg , intr_status ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
intr_status & = rd_regl ( port , ureg - > sirfsoc_int_en_reg ) ;
2013-08-12 18:15:35 +08:00
if ( unlikely ( intr_status & ( SIRFUART_ERR_INT_STAT ( port , uint_st ) ) ) ) {
if ( intr_status & uint_st - > sirfsoc_rxd_brk ) {
port - > icount . brk + + ;
2011-11-17 23:17:04 +08:00
if ( uart_handle_break ( port ) )
goto recv_char ;
}
2013-08-12 18:15:35 +08:00
if ( intr_status & uint_st - > sirfsoc_rx_oflow )
2011-11-17 23:17:04 +08:00
port - > icount . overrun + + ;
2013-08-12 18:15:35 +08:00
if ( intr_status & uint_st - > sirfsoc_frm_err ) {
2011-11-17 23:17:04 +08:00
port - > icount . frame + + ;
flag = TTY_FRAME ;
}
2013-08-12 18:15:35 +08:00
if ( intr_status & uint_st - > sirfsoc_parity_err )
2011-11-17 23:17:04 +08:00
flag = TTY_PARITY ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_RESET ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_START ) ;
2011-11-17 23:17:04 +08:00
intr_status & = port - > read_status_mask ;
uart_insert_char ( port , intr_status ,
2013-08-12 18:15:35 +08:00
uint_en - > sirfsoc_rx_oflow_en , 0 , flag ) ;
2011-11-17 23:17:04 +08:00
}
recv_char :
2013-08-12 18:15:35 +08:00
if ( ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) & &
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
( intr_status & SIRFUART_CTS_INT_ST ( uint_st ) ) & &
! sirfport - > tx_dma_state ) {
2013-08-12 18:15:35 +08:00
cts_status = rd_regl ( port , ureg - > sirfsoc_afc_ctrl ) &
SIRFUART_AFC_CTS_STATUS ;
if ( cts_status ! = 0 )
cts_status = 0 ;
else
cts_status = 1 ;
uart_handle_cts_change ( port , cts_status ) ;
wake_up_interruptible ( & state - > port . delta_msr_wait ) ;
2011-11-17 23:17:04 +08:00
}
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan ) {
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
if ( intr_status & uint_st - > sirfsoc_rx_timeout )
sirfsoc_uart_handle_rx_tmo ( sirfport ) ;
if ( intr_status & uint_st - > sirfsoc_rx_done )
sirfsoc_uart_handle_rx_done ( sirfport ) ;
} else {
if ( intr_status & SIRFUART_RX_IO_INT_ST ( uint_st ) )
sirfsoc_uart_pio_rx_chars ( port ,
SIRFSOC_UART_IO_RX_MAX_CNT ) ;
}
2014-05-26 19:02:07 +08:00
spin_unlock ( & port - > lock ) ;
tty_flip_buffer_push ( & state - > port ) ;
spin_lock ( & port - > lock ) ;
2013-08-12 18:15:35 +08:00
if ( intr_status & uint_st - > sirfsoc_txfifo_empty ) {
2014-01-30 13:57:29 +08:00
if ( sirfport - > tx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfsoc_uart_tx_with_dma ( sirfport ) ;
else {
if ( uart_circ_empty ( xmit ) | | uart_tx_stopped ( port ) ) {
spin_unlock ( & port - > lock ) ;
return IRQ_HANDLED ;
} else {
sirfsoc_uart_pio_tx_chars ( sirfport ,
2011-11-17 23:17:04 +08:00
SIRFSOC_UART_IO_TX_REASONABLE_CNT ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
if ( ( uart_circ_empty ( xmit ) ) & &
2013-08-12 18:15:35 +08:00
( rd_regl ( port , ureg - > sirfsoc_tx_fifo_status ) &
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
ufifo_st - > ff_empty ( port - > line ) ) )
sirfsoc_uart_stop_tx ( port ) ;
}
2011-11-17 23:17:04 +08:00
}
}
2012-12-25 17:32:04 +08:00
spin_unlock ( & port - > lock ) ;
2014-05-26 19:02:07 +08:00
2011-11-17 23:17:04 +08:00
return IRQ_HANDLED ;
}
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
static void sirfsoc_uart_rx_dma_complete_tl ( unsigned long param )
{
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) param ;
struct uart_port * port = & sirfport - > port ;
2013-09-21 09:02:10 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
unsigned long flags ;
2014-01-03 15:44:08 +08:00
struct dma_tx_state tx_state ;
2014-05-29 11:13:43 +01:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2014-01-03 15:44:08 +08:00
while ( DMA_COMPLETE = = dmaengine_tx_status ( sirfport - > rx_dma_chan ,
sirfport - > rx_dma_items [ sirfport - > rx_completed ] . cookie , & tx_state ) ) {
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfsoc_uart_insert_rx_buf_to_tty ( sirfport ,
SIRFSOC_RX_DMA_BUF_SIZE ) ;
2013-09-21 09:02:10 +08:00
if ( rd_regl ( port , ureg - > sirfsoc_int_en_reg ) &
uint_en - > sirfsoc_rx_timeout_en )
sirfsoc_rx_submit_one_dma_desc ( port ,
sirfport - > rx_completed + + ) ;
else
sirfport - > rx_completed + + ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > rx_completed % = SIRFSOC_RX_LOOP_BUF_CNT ;
}
2014-05-26 19:02:07 +08:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
tty_flip_buffer_push ( & port - > state - > port ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
}
static void sirfsoc_uart_rx_dma_complete_callback ( void * param )
{
struct sirfsoc_uart_port * sirfport = ( struct sirfsoc_uart_port * ) param ;
2014-05-26 19:02:07 +08:00
unsigned long flags ;
spin_lock_irqsave ( & sirfport - > port . lock , flags ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > rx_issued + + ;
sirfport - > rx_issued % = SIRFSOC_RX_LOOP_BUF_CNT ;
tasklet_schedule ( & sirfport - > rx_dma_complete_tasklet ) ;
2014-05-26 19:02:07 +08:00
spin_unlock_irqrestore ( & sirfport - > port . lock , flags ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
}
/* submit rx dma task into dmaengine */
static void sirfsoc_uart_start_next_rx_dma ( struct uart_port * port )
2011-11-17 23:17:04 +08:00
{
2013-08-07 13:35:38 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
int i ;
sirfport - > rx_io_count = 0 ;
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ) &
~ SIRFUART_IO_MODE ) ;
for ( i = 0 ; i < SIRFSOC_RX_LOOP_BUF_CNT ; i + + )
sirfsoc_rx_submit_one_dma_desc ( port , i ) ;
sirfport - > rx_completed = sirfport - > rx_issued = 0 ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) |
SIRFUART_RX_DMA_INT_EN ( port , uint_en ) ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
SIRFUART_RX_DMA_INT_EN ( port , uint_en ) ) ;
}
static void sirfsoc_uart_start_rx ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
sirfport - > rx_io_count = 0 ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_RESET ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_START ) ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfsoc_uart_start_next_rx_dma ( port ) ;
else {
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
rd_regl ( port , ureg - > sirfsoc_int_en_reg ) |
SIRFUART_RX_IO_INT_EN ( port , uint_en ) ) ;
else
wr_regl ( port , ureg - > sirfsoc_int_en_reg ,
SIRFUART_RX_IO_INT_EN ( port , uint_en ) ) ;
}
2013-08-12 18:15:35 +08:00
}
static unsigned int
sirfsoc_usp_calc_sample_div ( unsigned long set_rate ,
unsigned long ioclk_rate , unsigned long * sample_reg )
{
unsigned long min_delta = ~ 0UL ;
unsigned short sample_div ;
unsigned long ioclk_div = 0 ;
unsigned long temp_delta ;
for ( sample_div = SIRF_MIN_SAMPLE_DIV ;
sample_div < = SIRF_MAX_SAMPLE_DIV ; sample_div + + ) {
temp_delta = ioclk_rate -
( ioclk_rate + ( set_rate * sample_div ) / 2 )
/ ( set_rate * sample_div ) * set_rate * sample_div ;
2013-08-07 13:35:38 +08:00
2013-08-12 18:15:35 +08:00
temp_delta = ( temp_delta > 0 ) ? temp_delta : - temp_delta ;
if ( temp_delta < min_delta ) {
ioclk_div = ( 2 * ioclk_rate /
( set_rate * sample_div ) + 1 ) / 2 - 1 ;
if ( ioclk_div > SIRF_IOCLK_DIV_MAX )
continue ;
min_delta = temp_delta ;
* sample_reg = sample_div ;
if ( ! temp_delta )
break ;
}
}
return ioclk_div ;
2011-11-17 23:17:04 +08:00
}
static unsigned int
2013-08-12 18:15:35 +08:00
sirfsoc_uart_calc_sample_div ( unsigned long baud_rate ,
unsigned long ioclk_rate , unsigned long * set_baud )
2011-11-17 23:17:04 +08:00
{
unsigned long min_delta = ~ 0UL ;
unsigned short sample_div ;
unsigned int regv = 0 ;
unsigned long ioclk_div ;
unsigned long baud_tmp ;
int temp_delta ;
for ( sample_div = SIRF_MIN_SAMPLE_DIV ;
sample_div < = SIRF_MAX_SAMPLE_DIV ; sample_div + + ) {
ioclk_div = ( ioclk_rate / ( baud_rate * ( sample_div + 1 ) ) ) - 1 ;
if ( ioclk_div > SIRF_IOCLK_DIV_MAX )
continue ;
baud_tmp = ioclk_rate / ( ( ioclk_div + 1 ) * ( sample_div + 1 ) ) ;
temp_delta = baud_tmp - baud_rate ;
temp_delta = ( temp_delta > 0 ) ? temp_delta : - temp_delta ;
if ( temp_delta < min_delta ) {
regv = regv & ( ~ SIRF_IOCLK_DIV_MASK ) ;
regv = regv | ioclk_div ;
regv = regv & ( ~ SIRF_SAMPLE_DIV_MASK ) ;
regv = regv | ( sample_div < < SIRF_SAMPLE_DIV_SHIFT ) ;
min_delta = temp_delta ;
2013-08-12 18:15:35 +08:00
* set_baud = baud_tmp ;
2011-11-17 23:17:04 +08:00
}
}
return regv ;
}
static void sirfsoc_uart_set_termios ( struct uart_port * port ,
struct ktermios * termios ,
struct ktermios * old )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_int_en * uint_en = & sirfport - > uart_reg - > uart_int_en ;
2011-11-17 23:17:04 +08:00
unsigned long config_reg = 0 ;
unsigned long baud_rate ;
2013-08-12 18:15:35 +08:00
unsigned long set_baud ;
2011-11-17 23:17:04 +08:00
unsigned long flags ;
unsigned long ic ;
unsigned int clk_div_reg = 0 ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
unsigned long txfifo_op_reg , ioclk_rate ;
2011-11-17 23:17:04 +08:00
unsigned long rx_time_out ;
int threshold_div ;
2013-08-12 18:15:35 +08:00
u32 data_bit_len , stop_bit_len , len_val ;
unsigned long sample_div_reg = 0xf ;
ioclk_rate = port - > uartclk ;
2011-11-17 23:17:04 +08:00
switch ( termios - > c_cflag & CSIZE ) {
default :
case CS8 :
2013-08-12 18:15:35 +08:00
data_bit_len = 8 ;
2011-11-17 23:17:04 +08:00
config_reg | = SIRFUART_DATA_BIT_LEN_8 ;
break ;
case CS7 :
2013-08-12 18:15:35 +08:00
data_bit_len = 7 ;
2011-11-17 23:17:04 +08:00
config_reg | = SIRFUART_DATA_BIT_LEN_7 ;
break ;
case CS6 :
2013-08-12 18:15:35 +08:00
data_bit_len = 6 ;
2011-11-17 23:17:04 +08:00
config_reg | = SIRFUART_DATA_BIT_LEN_6 ;
break ;
case CS5 :
2013-08-12 18:15:35 +08:00
data_bit_len = 5 ;
2011-11-17 23:17:04 +08:00
config_reg | = SIRFUART_DATA_BIT_LEN_5 ;
break ;
}
2013-08-12 18:15:35 +08:00
if ( termios - > c_cflag & CSTOPB ) {
2011-11-17 23:17:04 +08:00
config_reg | = SIRFUART_STOP_BIT_LEN_2 ;
2013-08-12 18:15:35 +08:00
stop_bit_len = 2 ;
} else
stop_bit_len = 1 ;
2011-11-17 23:17:04 +08:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2013-08-12 18:15:35 +08:00
port - > read_status_mask = uint_en - > sirfsoc_rx_oflow_en ;
2011-11-17 23:17:04 +08:00
port - > ignore_status_mask = 0 ;
2013-08-12 18:15:35 +08:00
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
if ( termios - > c_iflag & INPCK )
port - > read_status_mask | = uint_en - > sirfsoc_frm_err_en |
uint_en - > sirfsoc_parity_err_en ;
2013-08-15 06:52:15 +08:00
} else {
2013-08-12 18:15:35 +08:00
if ( termios - > c_iflag & INPCK )
port - > read_status_mask | = uint_en - > sirfsoc_frm_err_en ;
}
2014-06-16 08:10:41 -04:00
if ( termios - > c_iflag & ( IGNBRK | BRKINT | PARMRK ) )
2013-08-12 18:15:35 +08:00
port - > read_status_mask | = uint_en - > sirfsoc_rxd_brk_en ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
if ( termios - > c_iflag & IGNPAR )
port - > ignore_status_mask | =
uint_en - > sirfsoc_frm_err_en |
uint_en - > sirfsoc_parity_err_en ;
if ( termios - > c_cflag & PARENB ) {
if ( termios - > c_cflag & CMSPAR ) {
if ( termios - > c_cflag & PARODD )
config_reg | = SIRFUART_STICK_BIT_MARK ;
else
config_reg | = SIRFUART_STICK_BIT_SPACE ;
} else if ( termios - > c_cflag & PARODD ) {
config_reg | = SIRFUART_STICK_BIT_ODD ;
} else {
config_reg | = SIRFUART_STICK_BIT_EVEN ;
}
}
2013-08-15 06:52:15 +08:00
} else {
2013-08-12 18:15:35 +08:00
if ( termios - > c_iflag & IGNPAR )
port - > ignore_status_mask | =
uint_en - > sirfsoc_frm_err_en ;
if ( termios - > c_cflag & PARENB )
dev_warn ( port - > dev ,
" USP-UART not support parity err \n " ) ;
}
if ( termios - > c_iflag & IGNBRK ) {
2011-11-17 23:17:04 +08:00
port - > ignore_status_mask | =
2013-08-12 18:15:35 +08:00
uint_en - > sirfsoc_rxd_brk_en ;
if ( termios - > c_iflag & IGNPAR )
port - > ignore_status_mask | =
uint_en - > sirfsoc_rx_oflow_en ;
}
2011-11-17 23:17:04 +08:00
if ( ( termios - > c_cflag & CREAD ) = = 0 )
port - > ignore_status_mask | = SIRFUART_DUMMY_READ ;
/* Hardware Flow Control Settings */
if ( UART_ENABLE_MS ( port , termios - > c_cflag ) ) {
if ( ! sirfport - > ms_enabled )
sirfsoc_uart_enable_ms ( port ) ;
} else {
if ( sirfport - > ms_enabled )
sirfsoc_uart_disable_ms ( port ) ;
}
2013-08-12 18:15:35 +08:00
baud_rate = uart_get_baud_rate ( port , termios , old , 0 , 4000000 ) ;
if ( ioclk_rate = = 150000000 ) {
2013-01-16 14:49:27 +08:00
for ( ic = 0 ; ic < SIRF_BAUD_RATE_SUPPORT_NR ; ic + + )
if ( baud_rate = = baudrate_to_regv [ ic ] . baud_rate )
clk_div_reg = baudrate_to_regv [ ic ] . reg_val ;
}
2013-08-12 18:15:35 +08:00
set_baud = baud_rate ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
if ( unlikely ( clk_div_reg = = 0 ) )
clk_div_reg = sirfsoc_uart_calc_sample_div ( baud_rate ,
ioclk_rate , & set_baud ) ;
wr_regl ( port , ureg - > sirfsoc_divisor , clk_div_reg ) ;
2013-08-15 06:52:15 +08:00
} else {
2013-08-12 18:15:35 +08:00
clk_div_reg = sirfsoc_usp_calc_sample_div ( baud_rate ,
ioclk_rate , & sample_div_reg ) ;
sample_div_reg - - ;
set_baud = ( ( ioclk_rate / ( clk_div_reg + 1 ) - 1 ) /
( sample_div_reg + 1 ) ) ;
/* setting usp mode 2 */
2013-08-25 20:18:40 +08:00
len_val = ( ( 1 < < SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET ) |
( 1 < < SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET ) ) ;
len_val | = ( ( clk_div_reg & SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK )
< < SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET ) ;
wr_regl ( port , ureg - > sirfsoc_mode2 , len_val ) ;
2013-08-12 18:15:35 +08:00
}
2011-11-17 23:17:04 +08:00
if ( tty_termios_baud_rate ( termios ) )
2013-08-12 18:15:35 +08:00
tty_termios_encode_baud_rate ( termios , set_baud , set_baud ) ;
/* set receive timeout && data bits len */
rx_time_out = SIRFSOC_UART_RX_TIMEOUT ( set_baud , 20000 ) ;
rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE ( rx_time_out ) ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
txfifo_op_reg = rd_regl ( port , ureg - > sirfsoc_tx_fifo_op ) ;
2013-08-25 20:18:40 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_STOP ) ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op ,
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
( txfifo_op_reg & ~ SIRFUART_FIFO_START ) ) ;
2013-08-12 18:15:35 +08:00
if ( sirfport - > uart_reg - > uart_type = = SIRF_REAL_UART ) {
config_reg | = SIRFUART_RECV_TIMEOUT ( port , rx_time_out ) ;
wr_regl ( port , ureg - > sirfsoc_line_ctrl , config_reg ) ;
2013-08-15 06:52:15 +08:00
} else {
2013-08-12 18:15:35 +08:00
/*tx frame ctrl*/
2013-08-25 20:18:40 +08:00
len_val = ( data_bit_len - 1 ) < < SIRFSOC_USP_TX_DATA_LEN_OFFSET ;
len_val | = ( data_bit_len + 1 + stop_bit_len - 1 ) < <
SIRFSOC_USP_TX_FRAME_LEN_OFFSET ;
len_val | = ( ( data_bit_len - 1 ) < <
SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET ) ;
len_val | = ( ( ( clk_div_reg & 0xc00 ) > > 10 ) < <
SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET ) ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_frame_ctrl , len_val ) ;
/*rx frame ctrl*/
2013-08-25 20:18:40 +08:00
len_val = ( data_bit_len - 1 ) < < SIRFSOC_USP_RX_DATA_LEN_OFFSET ;
len_val | = ( data_bit_len + 1 + stop_bit_len - 1 ) < <
SIRFSOC_USP_RX_FRAME_LEN_OFFSET ;
len_val | = ( data_bit_len - 1 ) < <
SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET ;
len_val | = ( ( ( clk_div_reg & 0xf000 ) > > 12 ) < <
SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET ) ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_frame_ctrl , len_val ) ;
/*async param*/
wr_regl ( port , ureg - > sirfsoc_async_param_reg ,
( SIRFUART_RECV_TIMEOUT ( port , rx_time_out ) ) |
2013-08-25 20:18:40 +08:00
( sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK ) < <
SIRFSOC_USP_ASYNC_DIV2_OFFSET ) ;
2013-08-12 18:15:35 +08:00
}
2014-01-30 13:57:29 +08:00
if ( sirfport - > tx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl , SIRFUART_DMA_MODE ) ;
else
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl , SIRFUART_IO_MODE ) ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl , SIRFUART_DMA_MODE ) ;
else
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl , SIRFUART_IO_MODE ) ;
2011-11-17 23:17:04 +08:00
/* Reset Rx/Tx FIFO Threshold level for proper baudrate */
2013-08-12 18:15:35 +08:00
if ( set_baud < 1000000 )
2011-11-17 23:17:04 +08:00
threshold_div = 1 ;
else
threshold_div = 2 ;
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_fifo_ctrl ,
SIRFUART_FIFO_THD ( port ) / threshold_div ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_ctrl ,
SIRFUART_FIFO_THD ( port ) / threshold_div ) ;
txfifo_op_reg | = SIRFUART_FIFO_START ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , txfifo_op_reg ) ;
2013-08-12 18:15:35 +08:00
uart_update_timeout ( port , termios - > c_cflag , set_baud ) ;
2011-11-17 23:17:04 +08:00
sirfsoc_uart_start_rx ( port ) ;
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_rx_en , SIRFUART_TX_EN | SIRFUART_RX_EN ) ;
2011-11-17 23:17:04 +08:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
2014-01-03 15:44:07 +08:00
static void sirfsoc_uart_pm ( struct uart_port * port , unsigned int state ,
unsigned int oldstate )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2015-04-20 08:10:22 +00:00
if ( ! state )
2014-01-03 15:44:07 +08:00
clk_prepare_enable ( sirfport - > clk ) ;
2015-04-20 08:10:22 +00:00
else
2014-01-03 15:44:07 +08:00
clk_disable_unprepare ( sirfport - > clk ) ;
}
2011-11-17 23:17:04 +08:00
static int sirfsoc_uart_startup ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-19 11:47:52 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
2011-11-17 23:17:04 +08:00
unsigned int index = port - > line ;
int ret ;
set_irq_flags ( port - > irq , IRQF_VALID | IRQF_NOAUTOEN ) ;
ret = request_irq ( port - > irq ,
sirfsoc_uart_isr ,
0 ,
SIRFUART_PORT_NAME ,
sirfport ) ;
if ( ret ! = 0 ) {
dev_err ( port - > dev , " UART%d request IRQ line (%d) failed. \n " ,
index , port - > irq ) ;
goto irq_err ;
}
2013-08-19 11:47:52 +08:00
/* initial hardware settings */
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_tx_dma_io_ctrl ) |
SIRFUART_IO_MODE ) ;
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ,
rd_regl ( port , ureg - > sirfsoc_rx_dma_io_ctrl ) |
SIRFUART_IO_MODE ) ;
wr_regl ( port , ureg - > sirfsoc_tx_dma_io_len , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_rx_dma_io_len , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_tx_rx_en , SIRFUART_RX_EN | SIRFUART_TX_EN ) ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_USP_UART )
wr_regl ( port , ureg - > sirfsoc_mode1 ,
SIRFSOC_USP_ENDIAN_CTRL_LSBF |
SIRFSOC_USP_EN ) ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , SIRFUART_FIFO_RESET ) ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_op , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , SIRFUART_FIFO_RESET ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_op , 0 ) ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_ctrl , SIRFUART_FIFO_THD ( port ) ) ;
wr_regl ( port , ureg - > sirfsoc_rx_fifo_ctrl , SIRFUART_FIFO_THD ( port ) ) ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
wr_regl ( port , ureg - > sirfsoc_rx_fifo_level_chk ,
2014-01-30 13:57:29 +08:00
SIRFUART_RX_FIFO_CHK_SC ( port - > line , 0x4 ) |
SIRFUART_RX_FIFO_CHK_LC ( port - > line , 0xe ) |
SIRFUART_RX_FIFO_CHK_HC ( port - > line , 0x1b ) ) ;
if ( sirfport - > tx_dma_chan ) {
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > tx_dma_state = TX_DMA_IDLE ;
wr_regl ( port , ureg - > sirfsoc_tx_fifo_level_chk ,
SIRFUART_TX_FIFO_CHK_SC ( port - > line , 0x1b ) |
SIRFUART_TX_FIFO_CHK_LC ( port - > line , 0xe ) |
SIRFUART_TX_FIFO_CHK_HC ( port - > line , 0x4 ) ) ;
}
2013-08-15 06:52:15 +08:00
sirfport - > ms_enabled = false ;
if ( sirfport - > uart_reg - > uart_type = = SIRF_USP_UART & &
sirfport - > hw_flow_ctrl ) {
set_irq_flags ( gpio_to_irq ( sirfport - > cts_gpio ) ,
IRQF_VALID | IRQF_NOAUTOEN ) ;
ret = request_irq ( gpio_to_irq ( sirfport - > cts_gpio ) ,
sirfsoc_uart_usp_cts_handler , IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING , " usp_cts_irq " , sirfport ) ;
if ( ret ! = 0 ) {
dev_err ( port - > dev , " UART-USP:request gpio irq fail \n " ) ;
goto init_rx_err ;
}
}
2011-11-17 23:17:04 +08:00
enable_irq ( port - > irq ) ;
2013-08-15 06:52:15 +08:00
2013-08-19 11:47:52 +08:00
return 0 ;
2013-08-15 06:52:15 +08:00
init_rx_err :
free_irq ( port - > irq , sirfport ) ;
2011-11-17 23:17:04 +08:00
irq_err :
return ret ;
}
static void sirfsoc_uart_shutdown ( struct uart_port * port )
{
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
2015-01-03 17:02:57 +08:00
if ( ! sirfport - > is_atlas7 )
2013-08-12 18:15:35 +08:00
wr_regl ( port , ureg - > sirfsoc_int_en_reg , 0 ) ;
2013-08-07 13:35:38 +08:00
else
wr_regl ( port , SIRFUART_INT_EN_CLR , ~ 0UL ) ;
2011-11-17 23:17:04 +08:00
free_irq ( port - > irq , sirfport ) ;
2013-08-15 06:52:15 +08:00
if ( sirfport - > ms_enabled )
2011-11-17 23:17:04 +08:00
sirfsoc_uart_disable_ms ( port ) ;
2013-08-15 06:52:15 +08:00
if ( sirfport - > uart_reg - > uart_type = = SIRF_USP_UART & &
sirfport - > hw_flow_ctrl ) {
gpio_set_value ( sirfport - > rts_gpio , 1 ) ;
free_irq ( gpio_to_irq ( sirfport - > cts_gpio ) , sirfport ) ;
2011-11-17 23:17:04 +08:00
}
2014-01-30 13:57:29 +08:00
if ( sirfport - > tx_dma_chan )
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
sirfport - > tx_dma_state = TX_DMA_IDLE ;
2011-11-17 23:17:04 +08:00
}
static const char * sirfsoc_uart_type ( struct uart_port * port )
{
return port - > type = = SIRFSOC_PORT_TYPE ? SIRFUART_PORT_NAME : NULL ;
}
static int sirfsoc_uart_request_port ( struct uart_port * port )
{
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_uart_param * uart_param = & sirfport - > uart_reg - > uart_param ;
2011-11-17 23:17:04 +08:00
void * ret ;
ret = request_mem_region ( port - > mapbase ,
2013-08-12 18:15:35 +08:00
SIRFUART_MAP_SIZE , uart_param - > port_name ) ;
2011-11-17 23:17:04 +08:00
return ret ? 0 : - EBUSY ;
}
static void sirfsoc_uart_release_port ( struct uart_port * port )
{
release_mem_region ( port - > mapbase , SIRFUART_MAP_SIZE ) ;
}
static void sirfsoc_uart_config_port ( struct uart_port * port , int flags )
{
if ( flags & UART_CONFIG_TYPE ) {
port - > type = SIRFSOC_PORT_TYPE ;
sirfsoc_uart_request_port ( port ) ;
}
}
static struct uart_ops sirfsoc_uart_ops = {
. tx_empty = sirfsoc_uart_tx_empty ,
. get_mctrl = sirfsoc_uart_get_mctrl ,
. set_mctrl = sirfsoc_uart_set_mctrl ,
. stop_tx = sirfsoc_uart_stop_tx ,
. start_tx = sirfsoc_uart_start_tx ,
. stop_rx = sirfsoc_uart_stop_rx ,
. enable_ms = sirfsoc_uart_enable_ms ,
. break_ctl = sirfsoc_uart_break_ctl ,
. startup = sirfsoc_uart_startup ,
. shutdown = sirfsoc_uart_shutdown ,
. set_termios = sirfsoc_uart_set_termios ,
2014-01-03 15:44:07 +08:00
. pm = sirfsoc_uart_pm ,
2011-11-17 23:17:04 +08:00
. type = sirfsoc_uart_type ,
. release_port = sirfsoc_uart_release_port ,
. request_port = sirfsoc_uart_request_port ,
. config_port = sirfsoc_uart_config_port ,
} ;
# ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
2013-08-12 18:15:35 +08:00
static int __init
sirfsoc_uart_console_setup ( struct console * co , char * options )
2011-11-17 23:17:04 +08:00
{
unsigned int baud = 115200 ;
unsigned int bits = 8 ;
unsigned int parity = ' n ' ;
unsigned int flow = ' n ' ;
struct uart_port * port = & sirfsoc_uart_ports [ co - > index ] . port ;
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
2011-11-17 23:17:04 +08:00
if ( co - > index < 0 | | co - > index > = SIRFSOC_UART_NR )
return - EINVAL ;
if ( ! port - > mapbase )
return - ENODEV ;
2013-08-12 18:15:35 +08:00
/* enable usp in mode1 register */
if ( sirfport - > uart_reg - > uart_type = = SIRF_USP_UART )
wr_regl ( port , ureg - > sirfsoc_mode1 , SIRFSOC_USP_EN |
SIRFSOC_USP_ENDIAN_CTRL_LSBF ) ;
2011-11-17 23:17:04 +08:00
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
port - > cons = co ;
2013-08-12 18:15:35 +08:00
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
/* default console tx/rx transfer using io mode */
2014-01-30 13:57:29 +08:00
sirfport - > rx_dma_chan = NULL ;
sirfport - > tx_dma_chan = NULL ;
2011-11-17 23:17:04 +08:00
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
static void sirfsoc_uart_console_putchar ( struct uart_port * port , int ch )
{
2013-08-12 18:15:35 +08:00
struct sirfsoc_uart_port * sirfport = to_sirfport ( port ) ;
struct sirfsoc_register * ureg = & sirfport - > uart_reg - > uart_reg ;
struct sirfsoc_fifo_status * ufifo_st = & sirfport - > uart_reg - > fifo_status ;
2011-11-17 23:17:04 +08:00
while ( rd_regl ( port ,
2013-08-12 18:15:35 +08:00
ureg - > sirfsoc_tx_fifo_status ) & ufifo_st - > ff_full ( port - > line ) )
2011-11-17 23:17:04 +08:00
cpu_relax ( ) ;
2014-05-05 08:05:51 +08:00
wr_regl ( port , ureg - > sirfsoc_tx_fifo_data , ch ) ;
2011-11-17 23:17:04 +08:00
}
static void sirfsoc_uart_console_write ( struct console * co , const char * s ,
unsigned int count )
{
struct uart_port * port = & sirfsoc_uart_ports [ co - > index ] . port ;
uart_console_write ( port , s , count , sirfsoc_uart_console_putchar ) ;
}
static struct console sirfsoc_uart_console = {
. name = SIRFSOC_UART_NAME ,
. device = uart_console_device ,
. flags = CON_PRINTBUFFER ,
. index = - 1 ,
. write = sirfsoc_uart_console_write ,
. setup = sirfsoc_uart_console_setup ,
. data = & sirfsoc_uart_drv ,
} ;
static int __init sirfsoc_uart_console_init ( void )
{
register_console ( & sirfsoc_uart_console ) ;
return 0 ;
}
console_initcall ( sirfsoc_uart_console_init ) ;
# endif
static struct uart_driver sirfsoc_uart_drv = {
. owner = THIS_MODULE ,
. driver_name = SIRFUART_PORT_NAME ,
. nr = SIRFSOC_UART_NR ,
. dev_name = SIRFSOC_UART_NAME ,
. major = SIRFSOC_UART_MAJOR ,
. minor = SIRFSOC_UART_MINOR ,
# ifdef CONFIG_SERIAL_SIRFSOC_CONSOLE
. cons = & sirfsoc_uart_console ,
# else
. cons = NULL ,
# endif
} ;
2015-03-16 20:17:11 +01:00
static const struct of_device_id sirfsoc_uart_ids [ ] = {
2013-08-12 18:15:35 +08:00
{ . compatible = " sirf,prima2-uart " , . data = & sirfsoc_uart , } ,
2015-01-03 17:02:57 +08:00
{ . compatible = " sirf,atlas7-uart " , . data = & sirfsoc_uart } ,
2013-08-12 18:15:35 +08:00
{ . compatible = " sirf,prima2-usp-uart " , . data = & sirfsoc_usp } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , sirfsoc_uart_ids ) ;
2013-08-08 17:41:43 +09:00
static int sirfsoc_uart_probe ( struct platform_device * pdev )
2011-11-17 23:17:04 +08:00
{
struct sirfsoc_uart_port * sirfport ;
struct uart_port * port ;
struct resource * res ;
int ret ;
2014-01-30 13:57:29 +08:00
int i , j ;
struct dma_slave_config slv_cfg = {
. src_maxburst = 2 ,
} ;
struct dma_slave_config tx_slv_cfg = {
. dst_maxburst = 2 ,
} ;
2013-08-12 18:15:35 +08:00
const struct of_device_id * match ;
2011-11-17 23:17:04 +08:00
2013-08-12 18:15:35 +08:00
match = of_match_node ( sirfsoc_uart_ids , pdev - > dev . of_node ) ;
2011-11-17 23:17:04 +08:00
if ( of_property_read_u32 ( pdev - > dev . of_node , " cell-index " , & pdev - > id ) ) {
dev_err ( & pdev - > dev ,
" Unable to find cell-index in uart node. \n " ) ;
ret = - EFAULT ;
goto err ;
}
2013-08-12 18:15:35 +08:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " sirf,prima2-usp-uart " ) )
pdev - > id + = ( ( struct sirfsoc_uart_register * )
match - > data ) - > uart_param . register_uart_nr ;
2011-11-17 23:17:04 +08:00
sirfport = & sirfsoc_uart_ports [ pdev - > id ] ;
port = & sirfport - > port ;
port - > dev = & pdev - > dev ;
port - > private_data = sirfport ;
2013-08-12 18:15:35 +08:00
sirfport - > uart_reg = ( struct sirfsoc_uart_register * ) match - > data ;
2011-11-17 23:17:04 +08:00
2013-08-15 06:52:15 +08:00
sirfport - > hw_flow_ctrl = of_property_read_bool ( pdev - > dev . of_node ,
" sirf,uart-has-rtscts " ) ;
2014-01-30 13:57:29 +08:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " sirf,prima2-uart " ) )
2013-08-12 18:15:35 +08:00
sirfport - > uart_reg - > uart_type = SIRF_REAL_UART ;
2013-08-15 06:52:15 +08:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " sirf,prima2-usp-uart " ) ) {
2013-08-12 18:15:35 +08:00
sirfport - > uart_reg - > uart_type = SIRF_USP_UART ;
2013-08-15 06:52:15 +08:00
if ( ! sirfport - > hw_flow_ctrl )
goto usp_no_flow_control ;
if ( of_find_property ( pdev - > dev . of_node , " cts-gpios " , NULL ) )
sirfport - > cts_gpio = of_get_named_gpio (
pdev - > dev . of_node , " cts-gpios " , 0 ) ;
else
sirfport - > cts_gpio = - 1 ;
if ( of_find_property ( pdev - > dev . of_node , " rts-gpios " , NULL ) )
sirfport - > rts_gpio = of_get_named_gpio (
pdev - > dev . of_node , " rts-gpios " , 0 ) ;
else
sirfport - > rts_gpio = - 1 ;
if ( ( ! gpio_is_valid ( sirfport - > cts_gpio ) | |
! gpio_is_valid ( sirfport - > rts_gpio ) ) ) {
ret = - EINVAL ;
dev_err ( & pdev - > dev ,
2013-08-19 11:47:51 +08:00
" Usp flow control must have cts and rts gpio " ) ;
2013-08-15 06:52:15 +08:00
goto err ;
}
ret = devm_gpio_request ( & pdev - > dev , sirfport - > cts_gpio ,
2013-08-19 11:47:51 +08:00
" usp-cts-gpio " ) ;
2013-08-15 06:52:15 +08:00
if ( ret ) {
2013-08-19 11:47:51 +08:00
dev_err ( & pdev - > dev , " Unable request cts gpio " ) ;
2013-08-15 06:52:15 +08:00
goto err ;
}
gpio_direction_input ( sirfport - > cts_gpio ) ;
ret = devm_gpio_request ( & pdev - > dev , sirfport - > rts_gpio ,
2013-08-19 11:47:51 +08:00
" usp-rts-gpio " ) ;
2013-08-15 06:52:15 +08:00
if ( ret ) {
2013-08-19 11:47:51 +08:00
dev_err ( & pdev - > dev , " Unable request rts gpio " ) ;
2013-08-15 06:52:15 +08:00
goto err ;
}
gpio_direction_output ( sirfport - > rts_gpio , 1 ) ;
}
usp_no_flow_control :
2015-01-03 17:02:57 +08:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " sirf,atlas7-uart " ) )
sirfport - > is_atlas7 = true ;
2013-08-07 13:35:38 +08:00
2011-11-17 23:17:04 +08:00
if ( of_property_read_u32 ( pdev - > dev . of_node ,
" fifosize " ,
& port - > fifosize ) ) {
dev_err ( & pdev - > dev ,
" Unable to find fifosize in uart node. \n " ) ;
ret = - EFAULT ;
goto err ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " Insufficient resources. \n " ) ;
ret = - EFAULT ;
goto err ;
}
serial: sirf: add DMA support using dmaengine APIs
if we get the valid dma channels from dts, move to use dmaengine to do
rx/tx. because the dma hardware requires dma address and length to be
4bytes aligned, in this driver, we will still use PIO for non-aligned
bytes, and use dma for aligned bytes.
for rx, to keep the dmaengine always active, we use double-buffer, so
we issue two dma_desc at first, and maintain the status of both
1. dma transfer done: update in rx dma finish callback
2. dma buffer is inserted into tty: update in rx dma finish tasklet and
rx timeout tasklet
so we re-issue the dma_desc only if both 1&2 are finished.
for tx, as we know the actual length for every transfer, we don't need
the above double buffering.
Signed-off-by: Qipan Li <Qipan.Li@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2013-08-19 11:47:53 +08:00
tasklet_init ( & sirfport - > rx_dma_complete_tasklet ,
sirfsoc_uart_rx_dma_complete_tl , ( unsigned long ) sirfport ) ;
tasklet_init ( & sirfport - > rx_tmo_process_tasklet ,
sirfsoc_rx_tmo_process_tl , ( unsigned long ) sirfport ) ;
2011-11-17 23:17:04 +08:00
port - > mapbase = res - > start ;
port - > membase = devm_ioremap ( & pdev - > dev , res - > start , resource_size ( res ) ) ;
if ( ! port - > membase ) {
dev_err ( & pdev - > dev , " Cannot remap resource. \n " ) ;
ret = - ENOMEM ;
goto err ;
}
res = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( res = = NULL ) {
dev_err ( & pdev - > dev , " Insufficient resources. \n " ) ;
ret = - EFAULT ;
2012-09-01 18:33:09 +02:00
goto err ;
2011-11-17 23:17:04 +08:00
}
port - > irq = res - > start ;
2015-04-20 08:10:23 +00:00
sirfport - > clk = devm_clk_get ( & pdev - > dev , NULL ) ;
2013-01-16 14:49:27 +08:00
if ( IS_ERR ( sirfport - > clk ) ) {
ret = PTR_ERR ( sirfport - > clk ) ;
2013-08-15 06:52:14 +08:00
goto err ;
2013-01-16 14:49:27 +08:00
}
port - > uartclk = clk_get_rate ( sirfport - > clk ) ;
2011-11-17 23:17:04 +08:00
port - > ops = & sirfsoc_uart_ops ;
spin_lock_init ( & port - > lock ) ;
platform_set_drvdata ( pdev , sirfport ) ;
ret = uart_add_one_port ( & sirfsoc_uart_drv , port ) ;
if ( ret ! = 0 ) {
dev_err ( & pdev - > dev , " Cannot add UART port(%d). \n " , pdev - > id ) ;
2015-04-20 08:10:23 +00:00
goto err ;
2011-11-17 23:17:04 +08:00
}
2014-01-30 13:57:29 +08:00
sirfport - > rx_dma_chan = dma_request_slave_channel ( port - > dev , " rx " ) ;
for ( i = 0 ; sirfport - > rx_dma_chan & & i < SIRFSOC_RX_LOOP_BUF_CNT ; i + + ) {
sirfport - > rx_dma_items [ i ] . xmit . buf =
dma_alloc_coherent ( port - > dev , SIRFSOC_RX_DMA_BUF_SIZE ,
& sirfport - > rx_dma_items [ i ] . dma_addr , GFP_KERNEL ) ;
if ( ! sirfport - > rx_dma_items [ i ] . xmit . buf ) {
dev_err ( port - > dev , " Uart alloc bufa failed \n " ) ;
ret = - ENOMEM ;
goto alloc_coherent_err ;
}
sirfport - > rx_dma_items [ i ] . xmit . head =
sirfport - > rx_dma_items [ i ] . xmit . tail = 0 ;
}
if ( sirfport - > rx_dma_chan )
dmaengine_slave_config ( sirfport - > rx_dma_chan , & slv_cfg ) ;
sirfport - > tx_dma_chan = dma_request_slave_channel ( port - > dev , " tx " ) ;
if ( sirfport - > tx_dma_chan )
dmaengine_slave_config ( sirfport - > tx_dma_chan , & tx_slv_cfg ) ;
2011-11-17 23:17:04 +08:00
2014-01-30 13:57:29 +08:00
return 0 ;
alloc_coherent_err :
for ( j = 0 ; j < i ; j + + )
dma_free_coherent ( port - > dev , SIRFSOC_RX_DMA_BUF_SIZE ,
sirfport - > rx_dma_items [ j ] . xmit . buf ,
sirfport - > rx_dma_items [ j ] . dma_addr ) ;
dma_release_channel ( sirfport - > rx_dma_chan ) ;
2011-11-17 23:17:04 +08:00
err :
return ret ;
}
static int sirfsoc_uart_remove ( struct platform_device * pdev )
{
struct sirfsoc_uart_port * sirfport = platform_get_drvdata ( pdev ) ;
struct uart_port * port = & sirfport - > port ;
uart_remove_one_port ( & sirfsoc_uart_drv , port ) ;
2014-01-30 13:57:29 +08:00
if ( sirfport - > rx_dma_chan ) {
int i ;
dmaengine_terminate_all ( sirfport - > rx_dma_chan ) ;
dma_release_channel ( sirfport - > rx_dma_chan ) ;
for ( i = 0 ; i < SIRFSOC_RX_LOOP_BUF_CNT ; i + + )
dma_free_coherent ( port - > dev , SIRFSOC_RX_DMA_BUF_SIZE ,
sirfport - > rx_dma_items [ i ] . xmit . buf ,
sirfport - > rx_dma_items [ i ] . dma_addr ) ;
}
if ( sirfport - > tx_dma_chan ) {
dmaengine_terminate_all ( sirfport - > tx_dma_chan ) ;
dma_release_channel ( sirfport - > tx_dma_chan ) ;
}
2011-11-17 23:17:04 +08:00
return 0 ;
}
2014-01-03 15:44:06 +08:00
# ifdef CONFIG_PM_SLEEP
2011-11-17 23:17:04 +08:00
static int
2014-01-03 15:44:06 +08:00
sirfsoc_uart_suspend ( struct device * pdev )
2011-11-17 23:17:04 +08:00
{
2014-01-03 15:44:06 +08:00
struct sirfsoc_uart_port * sirfport = dev_get_drvdata ( pdev ) ;
2011-11-17 23:17:04 +08:00
struct uart_port * port = & sirfport - > port ;
uart_suspend_port ( & sirfsoc_uart_drv , port ) ;
return 0 ;
}
2014-01-03 15:44:06 +08:00
static int sirfsoc_uart_resume ( struct device * pdev )
2011-11-17 23:17:04 +08:00
{
2014-01-03 15:44:06 +08:00
struct sirfsoc_uart_port * sirfport = dev_get_drvdata ( pdev ) ;
2011-11-17 23:17:04 +08:00
struct uart_port * port = & sirfport - > port ;
uart_resume_port ( & sirfsoc_uart_drv , port ) ;
return 0 ;
}
2014-01-03 15:44:06 +08:00
# endif
static const struct dev_pm_ops sirfsoc_uart_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( sirfsoc_uart_suspend , sirfsoc_uart_resume )
} ;
2011-11-17 23:17:04 +08:00
static struct platform_driver sirfsoc_uart_driver = {
. probe = sirfsoc_uart_probe ,
2012-11-19 13:21:34 -05:00
. remove = sirfsoc_uart_remove ,
2011-11-17 23:17:04 +08:00
. driver = {
. name = SIRFUART_PORT_NAME ,
. of_match_table = sirfsoc_uart_ids ,
2014-01-03 15:44:06 +08:00
. pm = & sirfsoc_uart_pm_ops ,
2011-11-17 23:17:04 +08:00
} ,
} ;
static int __init sirfsoc_uart_init ( void )
{
int ret = 0 ;
ret = uart_register_driver ( & sirfsoc_uart_drv ) ;
if ( ret )
goto out ;
ret = platform_driver_register ( & sirfsoc_uart_driver ) ;
if ( ret )
uart_unregister_driver ( & sirfsoc_uart_drv ) ;
out :
return ret ;
}
module_init ( sirfsoc_uart_init ) ;
static void __exit sirfsoc_uart_exit ( void )
{
platform_driver_unregister ( & sirfsoc_uart_driver ) ;
uart_unregister_driver ( & sirfsoc_uart_drv ) ;
}
module_exit ( sirfsoc_uart_exit ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Bin Shi <Bin.Shi@csr.com>, Rong Wang<Rong.Wang@csr.com> " ) ;
MODULE_DESCRIPTION ( " CSR SiRFprimaII Uart Driver " ) ;