2011-04-30 08:07:43 +04:00
/*
2014-04-05 04:23:43 +04:00
* Cadence UART driver ( found in Xilinx Zynq )
2011-04-30 08:07:43 +04:00
*
2014-04-05 04:23:39 +04:00
* 2011 - 2014 ( C ) Xilinx Inc .
2011-04-30 08:07:43 +04:00
*
* This program is free software ; you can redistribute it
* and / or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation ;
* either version 2 of the License , or ( at your option ) any
* later version .
2014-04-05 04:23:43 +04:00
*
* This driver has originally been pushed by Xilinx using a Zynq - branding . This
* still shows in the naming of this file , the kconfig symbols and some symbols
* in the code .
2011-04-30 08:07:43 +04:00
*/
2013-10-18 01:08:06 +04:00
# if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
# define SUPPORT_SYSRQ
# endif
2011-04-30 08:07:43 +04:00
# include <linux/platform_device.h>
2011-09-01 18:20:57 +04:00
# include <linux/serial.h>
2013-10-18 01:08:06 +04:00
# include <linux/console.h>
2011-04-30 08:07:43 +04:00
# include <linux/serial_core.h>
2013-05-13 21:46:38 +04:00
# include <linux/slab.h>
2011-09-01 18:20:57 +04:00
# include <linux/tty.h>
# include <linux/tty_flip.h>
2013-01-21 22:57:41 +04:00
# include <linux/clk.h>
2011-04-30 08:07:43 +04:00
# include <linux/irq.h>
# include <linux/io.h>
# include <linux/of.h>
2011-05-28 00:14:23 +04:00
# include <linux/module.h>
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
# define CDNS_UART_TTY_NAME "ttyPS"
# define CDNS_UART_NAME "xuartps"
# define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
# define CDNS_UART_MINOR 0 /* works best with devtmpfs */
# define CDNS_UART_NR_PORTS 2
# define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
2015-03-12 00:39:25 +03:00
# define CDNS_UART_REGISTER_SPACE 0x1000
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:08 +04:00
/* Rx Trigger level */
static int rx_trigger_level = 56 ;
module_param ( rx_trigger_level , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( rx_trigger_level , " Rx trigger level, 1-63 bytes " ) ;
/* Rx Timeout */
static int rx_timeout = 10 ;
module_param ( rx_timeout , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( rx_timeout , " Rx timeout, 1-255 " ) ;
2014-04-05 04:23:39 +04:00
/* Register offsets for the UART. */
2016-01-12 04:41:40 +03:00
# define CDNS_UART_CR 0x00 /* Control Register */
# define CDNS_UART_MR 0x04 /* Mode Register */
# define CDNS_UART_IER 0x08 /* Interrupt Enable */
# define CDNS_UART_IDR 0x0C /* Interrupt Disable */
# define CDNS_UART_IMR 0x10 /* Interrupt Mask */
# define CDNS_UART_ISR 0x14 /* Interrupt Status */
# define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
2016-09-15 12:15:29 +03:00
# define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
2016-01-12 04:41:40 +03:00
# define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
# define CDNS_UART_MODEMCR 0x24 /* Modem Control */
# define CDNS_UART_MODEMSR 0x28 /* Modem Status */
# define CDNS_UART_SR 0x2C /* Channel Status */
# define CDNS_UART_FIFO 0x30 /* FIFO */
# define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */
# define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */
# define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
# define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
# define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
2016-09-15 12:15:29 +03:00
# define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
2014-04-05 04:23:39 +04:00
/* Control Register Bit Definitions */
2014-04-05 04:23:43 +04:00
# define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
# define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */
# define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */
# define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */
# define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */
# define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */
# define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
# define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
# define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
2016-09-15 12:15:29 +03:00
# define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */
# define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */
# define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:39 +04:00
/*
* Mode Register :
2011-04-30 08:07:43 +04:00
* The mode register ( MR ) defines the mode of transfer as well as the data
* format . If this register is modified during transmission or reception ,
* data validity cannot be guaranteed .
*/
2014-04-05 04:23:43 +04:00
# define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */
# define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */
# define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */
2017-01-23 15:26:08 +03:00
# define CDNS_UART_MR_CHMODE_MASK 0x00000300 /* Mask for mode bits */
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
# define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */
# define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
# define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
# define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */
# define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */
# define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */
# define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
# define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */
# define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */
# define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:39 +04:00
/*
* Interrupt Registers :
2011-04-30 08:07:43 +04:00
* Interrupt control logic uses the interrupt enable register ( IER ) and the
* interrupt disable register ( IDR ) to set the value of the bits in the
* interrupt mask register ( IMR ) . The IMR determines whether to pass an
* interrupt to the interrupt status register ( ISR ) .
* Writing a 1 to IER Enables an interrupt , writing a 1 to IDR disables an
* interrupt . IMR and ISR are read only , and IER and IDR are write only .
* Reading either IER or IDR returns 0x00 .
* All four registers have the same bit definitions .
*/
2014-04-05 04:23:43 +04:00
# define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */
# define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */
# define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */
# define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */
# define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */
# define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */
# define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */
# define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */
# define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */
# define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
# define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
2011-04-30 08:07:43 +04:00
2016-09-21 17:01:18 +03:00
/*
* Do not enable parity error interrupt for the following
* reason : When parity error interrupt is enabled , each Rx
* parity error always results in 2 events . The first one
* being parity error interrupt and the second one with a
* proper Rx interrupt with the incoming data . Disabling
* parity error interrupt ensures better handling of parity
* error events . With this change , for a parity error case , we
* get a Rx interrupt with parity error set in ISR register
* and we still handle parity errors in the desired way .
*/
# define CDNS_UART_RX_IRQS (CDNS_UART_IXR_FRAMING | \
CDNS_UART_IXR_OVERRUN | \
CDNS_UART_IXR_RXTRIG | \
2016-01-12 04:41:37 +03:00
CDNS_UART_IXR_TOUT )
2013-10-18 01:08:06 +04:00
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
2016-09-15 12:15:29 +03:00
# define CDNS_UART_IXR_BRK 0x00002000
2013-10-18 01:08:06 +04:00
2016-09-15 12:15:29 +03:00
# define CDNS_UART_RXBS_SUPPORT BIT(1)
2014-11-05 15:35:16 +03:00
/*
* Modem Control register :
* The read / write Modem Control register controls the interface with the modem
* or data set , or a peripheral device emulating a modem .
*/
# define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */
# define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */
# define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */
2014-04-05 04:23:39 +04:00
/*
* Channel Status Register :
2011-04-30 08:07:43 +04:00
* The channel status register ( CSR ) is provided to enable the control logic
* to monitor the status of bits in the channel interrupt status register ,
* even if these are masked out by the interrupt mask register .
*/
2014-04-05 04:23:43 +04:00
# define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */
# define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
# define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
# define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:10 +04:00
/* baud dividers min/max values */
2014-04-05 04:23:43 +04:00
# define CDNS_UART_BDIV_MIN 4
# define CDNS_UART_BDIV_MAX 255
# define CDNS_UART_CD_MAX 65535
2013-10-18 01:08:10 +04:00
2013-05-13 21:46:38 +04:00
/**
2014-04-05 04:23:43 +04:00
* struct cdns_uart - device data
2014-04-05 04:23:37 +04:00
* @ port : Pointer to the UART port
2014-04-05 04:23:43 +04:00
* @ uartclk : Reference clock
* @ pclk : APB clock
2014-04-05 04:23:37 +04:00
* @ baud : Current baud rate
* @ clk_rate_change_nb : Notifier block for clock changes
2013-05-13 21:46:38 +04:00
*/
2014-04-05 04:23:43 +04:00
struct cdns_uart {
2013-10-18 01:08:11 +04:00
struct uart_port * port ;
2014-04-05 04:23:43 +04:00
struct clk * uartclk ;
struct clk * pclk ;
2013-10-18 01:08:11 +04:00
unsigned int baud ;
struct notifier_block clk_rate_change_nb ;
2016-09-15 12:15:29 +03:00
u32 quirks ;
} ;
struct cdns_platform_data {
u32 quirks ;
2013-05-13 21:46:38 +04:00
} ;
2014-04-05 04:23:43 +04:00
# define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb ) ;
2013-05-13 21:46:38 +04:00
2016-09-22 18:58:14 +03:00
/**
* cdns_uart_handle_rx - Handle the received bytes along with Rx errors .
* @ dev_id : Id of the UART port
* @ isrstatus : The interrupt status register value as read
* Return : None
*/
static void cdns_uart_handle_rx ( void * dev_id , unsigned int isrstatus )
2011-04-30 08:07:43 +04:00
{
2016-09-22 18:58:14 +03:00
struct uart_port * port = ( struct uart_port * ) dev_id ;
2016-09-15 12:15:29 +03:00
struct cdns_uart * cdns_uart = port - > private_data ;
2016-09-22 18:58:14 +03:00
unsigned int data ;
2016-09-15 12:15:29 +03:00
unsigned int rxbs_status = 0 ;
unsigned int status_mask ;
2016-09-22 18:58:14 +03:00
unsigned int framerrprocessed = 0 ;
char status = TTY_NORMAL ;
bool is_rxbs_support ;
2016-09-15 12:15:29 +03:00
is_rxbs_support = cdns_uart - > quirks & CDNS_UART_RXBS_SUPPORT ;
2016-09-22 18:58:14 +03:00
while ( ( readl ( port - > membase + CDNS_UART_SR ) &
CDNS_UART_SR_RXEMPTY ) ! = CDNS_UART_SR_RXEMPTY ) {
2016-09-15 12:15:29 +03:00
if ( is_rxbs_support )
rxbs_status = readl ( port - > membase + CDNS_UART_RXBS ) ;
2016-01-12 04:41:40 +03:00
data = readl ( port - > membase + CDNS_UART_FIFO ) ;
2016-09-22 18:58:14 +03:00
port - > icount . rx + + ;
/*
* There is no hardware break detection in Zynq , so we interpret
* framing error with all - zeros data as a break sequence .
* Most of the time , there ' s another non - zero byte at the
* end of the sequence .
*/
if ( ! is_rxbs_support & & ( isrstatus & CDNS_UART_IXR_FRAMING ) ) {
if ( ! data ) {
port - > read_status_mask | = CDNS_UART_IXR_BRK ;
framerrprocessed = 1 ;
2016-01-12 04:41:38 +03:00
continue ;
2016-09-22 18:58:14 +03:00
}
2016-01-12 04:41:38 +03:00
}
2016-09-15 12:15:29 +03:00
if ( is_rxbs_support & & ( rxbs_status & CDNS_UART_RXBS_BRK ) ) {
port - > icount . brk + + ;
status = TTY_BREAK ;
if ( uart_handle_break ( port ) )
continue ;
}
2013-10-18 01:08:06 +04:00
2016-09-22 18:58:14 +03:00
isrstatus & = port - > read_status_mask ;
isrstatus & = ~ port - > ignore_status_mask ;
status_mask = port - > read_status_mask ;
status_mask & = ~ port - > ignore_status_mask ;
2016-09-22 18:58:15 +03:00
if ( data & &
( port - > read_status_mask & CDNS_UART_IXR_BRK ) ) {
port - > read_status_mask & = ~ CDNS_UART_IXR_BRK ;
port - > icount . brk + + ;
if ( uart_handle_break ( port ) )
2016-09-22 18:58:14 +03:00
continue ;
2016-09-22 18:58:15 +03:00
}
2011-04-30 08:07:43 +04:00
2016-09-22 18:58:15 +03:00
if ( uart_handle_sysrq_char ( port , data ) )
continue ;
if ( is_rxbs_support ) {
if ( ( rxbs_status & CDNS_UART_RXBS_PARITY )
& & ( status_mask & CDNS_UART_IXR_PARITY ) ) {
port - > icount . parity + + ;
status = TTY_PARITY ;
}
if ( ( rxbs_status & CDNS_UART_RXBS_FRAMING )
& & ( status_mask & CDNS_UART_IXR_PARITY ) ) {
port - > icount . frame + + ;
status = TTY_FRAME ;
2016-09-15 12:15:29 +03:00
}
2016-09-22 18:58:15 +03:00
} else {
if ( isrstatus & CDNS_UART_IXR_PARITY ) {
port - > icount . parity + + ;
status = TTY_PARITY ;
2016-09-15 12:15:29 +03:00
}
2016-09-22 18:58:15 +03:00
if ( ( isrstatus & CDNS_UART_IXR_FRAMING ) & &
! framerrprocessed ) {
port - > icount . frame + + ;
status = TTY_FRAME ;
}
}
if ( isrstatus & CDNS_UART_IXR_OVERRUN ) {
port - > icount . overrun + + ;
tty_insert_flip_char ( & port - > state - > port , 0 ,
TTY_OVERRUN ) ;
2011-04-30 08:07:43 +04:00
}
2016-09-22 18:58:15 +03:00
tty_insert_flip_char ( & port - > state - > port , data , status ) ;
isrstatus = 0 ;
2011-04-30 08:07:43 +04:00
}
2016-09-22 18:58:14 +03:00
spin_unlock ( & port - > lock ) ;
2016-01-12 04:41:38 +03:00
tty_flip_buffer_push ( & port - > state - > port ) ;
2016-09-22 18:58:14 +03:00
spin_lock ( & port - > lock ) ;
2015-12-26 13:43:56 +03:00
}
2016-09-22 18:58:14 +03:00
/**
* cdns_uart_handle_tx - Handle the bytes to be Txed .
* @ dev_id : Id of the UART port
* Return : None
*/
static void cdns_uart_handle_tx ( void * dev_id )
2016-01-12 04:41:41 +03:00
{
2016-09-22 18:58:14 +03:00
struct uart_port * port = ( struct uart_port * ) dev_id ;
2016-01-12 04:41:41 +03:00
unsigned int numbytes ;
if ( uart_circ_empty ( & port - > state - > xmit ) ) {
writel ( CDNS_UART_IXR_TXEMPTY , port - > membase + CDNS_UART_IDR ) ;
2016-09-22 18:58:14 +03:00
} else {
numbytes = port - > fifosize ;
while ( numbytes & & ! uart_circ_empty ( & port - > state - > xmit ) & &
! ( readl ( port - > membase + CDNS_UART_SR ) & CDNS_UART_SR_TXFULL ) ) {
/*
* Get the data from the UART circular buffer
* and write it to the cdns_uart ' s TX_FIFO
* register .
*/
writel (
port - > state - > xmit . buf [ port - > state - > xmit .
tail ] , port - > membase + CDNS_UART_FIFO ) ;
port - > icount . tx + + ;
/*
* Adjust the tail of the UART buffer and wrap
* the buffer if it reaches limit .
*/
port - > state - > xmit . tail =
( port - > state - > xmit . tail + 1 ) &
( UART_XMIT_SIZE - 1 ) ;
numbytes - - ;
}
2016-01-12 04:41:41 +03:00
2016-09-22 18:58:14 +03:00
if ( uart_circ_chars_pending (
& port - > state - > xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( port ) ;
2016-01-12 04:41:41 +03:00
}
}
2015-12-26 13:43:56 +03:00
/**
* cdns_uart_isr - Interrupt handler
* @ irq : Irq number
* @ dev_id : Id of the port
*
* Return : IRQHANDLED
*/
static irqreturn_t cdns_uart_isr ( int irq , void * dev_id )
{
struct uart_port * port = ( struct uart_port * ) dev_id ;
2016-01-12 04:41:41 +03:00
unsigned int isrstatus ;
2015-12-26 13:43:56 +03:00
2016-09-22 18:58:14 +03:00
spin_lock ( & port - > lock ) ;
2015-12-26 13:43:56 +03:00
/* Read the interrupt status register to determine which
2016-09-22 18:58:14 +03:00
* interrupt ( s ) is / are active and clear them .
2015-12-26 13:43:56 +03:00
*/
2016-01-12 04:41:40 +03:00
isrstatus = readl ( port - > membase + CDNS_UART_ISR ) ;
writel ( isrstatus , port - > membase + CDNS_UART_ISR ) ;
2011-04-30 08:07:43 +04:00
2016-09-22 18:58:14 +03:00
if ( isrstatus & CDNS_UART_IXR_TXEMPTY ) {
cdns_uart_handle_tx ( dev_id ) ;
isrstatus & = ~ CDNS_UART_IXR_TXEMPTY ;
}
if ( isrstatus & CDNS_UART_IXR_MASK )
cdns_uart_handle_rx ( dev_id , isrstatus ) ;
2011-04-30 08:07:43 +04:00
2016-09-22 18:58:14 +03:00
spin_unlock ( & port - > lock ) ;
2011-04-30 08:07:43 +04:00
return IRQ_HANDLED ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_calc_baud_divs - Calculate baud rate divisors
2013-10-18 01:08:10 +04:00
* @ clk : UART module input clock
* @ baud : Desired baud rate
* @ rbdiv : BDIV value ( return value )
* @ rcd : CD value ( return value )
* @ div8 : Value for clk_sel bit in mod ( return value )
2014-04-05 04:23:37 +04:00
* Return : baud rate , requested baud when possible , or actual baud when there
2013-10-18 01:08:10 +04:00
* was too much error , zero if no valid divisors are found .
*
* Formula to obtain baud rate is
* baud_tx / rx rate = clk / CD * ( BDIV + 1 )
* input_clk = ( Uart User Defined Clock or Apb Clock )
* depends on UCLKEN in MR Reg
* clk = input_clk or input_clk / 8 ;
* depends on CLKS in MR reg
* CD and BDIV depends on values in
* baud rate generate register
* baud rate clock divisor register
*/
2014-04-05 04:23:43 +04:00
static unsigned int cdns_uart_calc_baud_divs ( unsigned int clk ,
unsigned int baud , u32 * rbdiv , u32 * rcd , int * div8 )
2011-04-30 08:07:43 +04:00
{
2013-10-18 01:08:10 +04:00
u32 cd , bdiv ;
unsigned int calc_baud ;
unsigned int bestbaud = 0 ;
2011-04-30 08:07:43 +04:00
unsigned int bauderror ;
2013-10-18 01:08:10 +04:00
unsigned int besterror = ~ 0 ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
if ( baud < clk / ( ( CDNS_UART_BDIV_MAX + 1 ) * CDNS_UART_CD_MAX ) ) {
2013-10-18 01:08:10 +04:00
* div8 = 1 ;
clk / = 8 ;
} else {
* div8 = 0 ;
}
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
for ( bdiv = CDNS_UART_BDIV_MIN ; bdiv < = CDNS_UART_BDIV_MAX ; bdiv + + ) {
2013-10-18 01:08:10 +04:00
cd = DIV_ROUND_CLOSEST ( clk , baud * ( bdiv + 1 ) ) ;
2014-04-05 04:23:43 +04:00
if ( cd < 1 | | cd > CDNS_UART_CD_MAX )
2011-04-30 08:07:43 +04:00
continue ;
2013-10-18 01:08:10 +04:00
calc_baud = clk / ( cd * ( bdiv + 1 ) ) ;
2011-04-30 08:07:43 +04:00
if ( baud > calc_baud )
bauderror = baud - calc_baud ;
else
bauderror = calc_baud - baud ;
2013-10-18 01:08:10 +04:00
if ( besterror > bauderror ) {
* rbdiv = bdiv ;
* rcd = cd ;
bestbaud = calc_baud ;
besterror = bauderror ;
2011-04-30 08:07:43 +04:00
}
}
2013-10-18 01:08:10 +04:00
/* use the values when percent error is acceptable */
if ( ( ( besterror * 100 ) / baud ) < 3 )
bestbaud = baud ;
return bestbaud ;
}
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:10 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_set_baud_rate - Calculate and set the baud rate
2013-10-18 01:08:10 +04:00
* @ port : Handle to the uart port structure
* @ baud : Baud rate to set
2014-04-05 04:23:37 +04:00
* Return : baud rate , requested baud when possible , or actual baud when there
2013-10-18 01:08:10 +04:00
* was too much error , zero if no valid divisors are found .
*/
2014-04-05 04:23:43 +04:00
static unsigned int cdns_uart_set_baud_rate ( struct uart_port * port ,
2013-10-18 01:08:10 +04:00
unsigned int baud )
{
unsigned int calc_baud ;
2013-10-22 03:40:59 +04:00
u32 cd = 0 , bdiv = 0 ;
2013-10-18 01:08:10 +04:00
u32 mreg ;
int div8 ;
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart = port - > private_data ;
2013-10-18 01:08:10 +04:00
2014-04-05 04:23:43 +04:00
calc_baud = cdns_uart_calc_baud_divs ( port - > uartclk , baud , & bdiv , & cd ,
2013-10-18 01:08:10 +04:00
& div8 ) ;
/* Write new divisors to hardware */
2016-01-12 04:41:40 +03:00
mreg = readl ( port - > membase + CDNS_UART_MR ) ;
2013-10-18 01:08:10 +04:00
if ( div8 )
2014-04-05 04:23:43 +04:00
mreg | = CDNS_UART_MR_CLKSEL ;
2013-10-18 01:08:10 +04:00
else
2014-04-05 04:23:43 +04:00
mreg & = ~ CDNS_UART_MR_CLKSEL ;
2016-01-12 04:41:40 +03:00
writel ( mreg , port - > membase + CDNS_UART_MR ) ;
writel ( cd , port - > membase + CDNS_UART_BAUDGEN ) ;
writel ( bdiv , port - > membase + CDNS_UART_BAUDDIV ) ;
2014-04-05 04:23:43 +04:00
cdns_uart - > baud = baud ;
2011-04-30 08:07:43 +04:00
return calc_baud ;
}
2013-10-22 03:41:01 +04:00
# ifdef CONFIG_COMMON_CLK
2013-10-18 01:08:11 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_clk_notitifer_cb - Clock notifier callback
2013-10-18 01:08:11 +04:00
* @ nb : Notifier block
* @ event : Notify event
* @ data : Notifier data
2014-04-05 04:23:39 +04:00
* Return : NOTIFY_OK or NOTIFY_DONE on success , NOTIFY_BAD on error .
2013-10-18 01:08:11 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_clk_notifier_cb ( struct notifier_block * nb ,
2013-10-18 01:08:11 +04:00
unsigned long event , void * data )
{
u32 ctrl_reg ;
struct uart_port * port ;
int locked = 0 ;
struct clk_notifier_data * ndata = data ;
unsigned long flags = 0 ;
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart = to_cdns_uart ( nb ) ;
2013-10-18 01:08:11 +04:00
2014-04-05 04:23:43 +04:00
port = cdns_uart - > port ;
2013-10-18 01:08:11 +04:00
if ( port - > suspended )
return NOTIFY_OK ;
switch ( event ) {
case PRE_RATE_CHANGE :
{
2014-04-05 04:23:39 +04:00
u32 bdiv , cd ;
2013-10-18 01:08:11 +04:00
int div8 ;
/*
* Find out if current baud - rate can be achieved with new clock
* frequency .
*/
2014-04-05 04:23:43 +04:00
if ( ! cdns_uart_calc_baud_divs ( ndata - > new_rate , cdns_uart - > baud ,
2014-04-05 04:23:40 +04:00
& bdiv , & cd , & div8 ) ) {
dev_warn ( port - > dev , " clock rate change rejected \n " ) ;
2013-10-18 01:08:11 +04:00
return NOTIFY_BAD ;
2014-04-05 04:23:40 +04:00
}
2013-10-18 01:08:11 +04:00
2014-04-05 04:23:43 +04:00
spin_lock_irqsave ( & cdns_uart - > port - > lock , flags ) ;
2013-10-18 01:08:11 +04:00
/* Disable the TX and RX to set baud rate */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg | = CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:11 +04:00
2014-04-05 04:23:43 +04:00
spin_unlock_irqrestore ( & cdns_uart - > port - > lock , flags ) ;
2013-10-18 01:08:11 +04:00
return NOTIFY_OK ;
}
case POST_RATE_CHANGE :
/*
* Set clk dividers to generate correct baud with new clock
* frequency .
*/
2014-04-05 04:23:43 +04:00
spin_lock_irqsave ( & cdns_uart - > port - > lock , flags ) ;
2013-10-18 01:08:11 +04:00
locked = 1 ;
port - > uartclk = ndata - > new_rate ;
2014-04-05 04:23:43 +04:00
cdns_uart - > baud = cdns_uart_set_baud_rate ( cdns_uart - > port ,
cdns_uart - > baud ) ;
2013-10-18 01:08:11 +04:00
/* fall through */
case ABORT_RATE_CHANGE :
if ( ! locked )
2014-04-05 04:23:43 +04:00
spin_lock_irqsave ( & cdns_uart - > port - > lock , flags ) ;
2013-10-18 01:08:11 +04:00
/* Set TX/RX Reset */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg | = CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:11 +04:00
2016-01-12 04:41:40 +03:00
while ( readl ( port - > membase + CDNS_UART_CR ) &
2014-04-05 04:23:43 +04:00
( CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ) )
2013-10-18 01:08:11 +04:00
cpu_relax ( ) ;
/*
* Clear the RX disable and TX disable bits and then set the TX
* enable bit and RX enable bit to enable the transmitter and
* receiver .
*/
2016-01-12 04:41:40 +03:00
writel ( rx_timeout , port - > membase + CDNS_UART_RXTOUT ) ;
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg & = ~ ( CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ) ;
ctrl_reg | = CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:11 +04:00
2014-04-05 04:23:43 +04:00
spin_unlock_irqrestore ( & cdns_uart - > port - > lock , flags ) ;
2013-10-18 01:08:11 +04:00
return NOTIFY_OK ;
default :
return NOTIFY_DONE ;
}
}
2013-10-22 03:41:01 +04:00
# endif
2013-10-18 01:08:11 +04:00
2011-04-30 08:07:43 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_start_tx - Start transmitting bytes
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_start_tx ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2016-01-12 04:41:41 +03:00
unsigned int status ;
2011-04-30 08:07:43 +04:00
2015-12-26 13:43:51 +03:00
if ( uart_tx_stopped ( port ) )
2011-04-30 08:07:43 +04:00
return ;
2015-12-26 13:43:49 +03:00
/*
* Set the TX enable bit and clear the TX disable bit to enable the
2011-04-30 08:07:43 +04:00
* transmitter .
*/
2016-01-12 04:41:40 +03:00
status = readl ( port - > membase + CDNS_UART_CR ) ;
2015-12-26 13:43:49 +03:00
status & = ~ CDNS_UART_CR_TX_DIS ;
status | = CDNS_UART_CR_TX_EN ;
2016-01-12 04:41:40 +03:00
writel ( status , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
2015-12-26 13:43:51 +03:00
if ( uart_circ_empty ( & port - > state - > xmit ) )
return ;
2016-01-12 04:41:41 +03:00
cdns_uart_handle_tx ( port ) ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:40 +03:00
writel ( CDNS_UART_IXR_TXEMPTY , port - > membase + CDNS_UART_ISR ) ;
2011-04-30 08:07:43 +04:00
/* Enable the TX Empty interrupt */
2016-01-12 04:41:40 +03:00
writel ( CDNS_UART_IXR_TXEMPTY , port - > membase + CDNS_UART_IER ) ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_stop_tx - Stop TX
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_stop_tx ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
unsigned int regval ;
2016-01-12 04:41:40 +03:00
regval = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
regval | = CDNS_UART_CR_TX_DIS ;
2011-04-30 08:07:43 +04:00
/* Disable the transmitter */
2016-01-12 04:41:40 +03:00
writel ( regval , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_stop_rx - Stop RX
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_stop_rx ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
unsigned int regval ;
2016-01-12 04:41:37 +03:00
/* Disable RX IRQs */
2016-01-12 04:41:40 +03:00
writel ( CDNS_UART_RX_IRQS , port - > membase + CDNS_UART_IDR ) ;
2016-01-12 04:41:37 +03:00
/* Disable the receiver */
2016-01-12 04:41:40 +03:00
regval = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
regval | = CDNS_UART_CR_RX_DIS ;
2016-01-12 04:41:40 +03:00
writel ( regval , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_tx_empty - Check whether TX is empty
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
*
2014-04-05 04:23:37 +04:00
* Return : TIOCSER_TEMT on success , 0 otherwise
*/
2014-04-05 04:23:43 +04:00
static unsigned int cdns_uart_tx_empty ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
unsigned int status ;
2016-01-12 04:41:40 +03:00
status = readl ( port - > membase + CDNS_UART_SR ) &
2015-03-13 00:11:59 +03:00
CDNS_UART_SR_TXEMPTY ;
2011-04-30 08:07:43 +04:00
return status ? TIOCSER_TEMT : 0 ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_break_ctl - Based on the input ctl we have to start or stop
2011-04-30 08:07:43 +04:00
* transmitting char breaks
* @ port : Handle to the uart port structure
* @ ctl : Value based on which start or stop decision is taken
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_break_ctl ( struct uart_port * port , int ctl )
2011-04-30 08:07:43 +04:00
{
unsigned int status ;
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
2016-01-12 04:41:40 +03:00
status = readl ( port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
if ( ctl = = - 1 )
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_CR_STARTBRK | status ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
else {
2014-04-05 04:23:43 +04:00
if ( ( status & CDNS_UART_CR_STOPBRK ) = = 0 )
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_CR_STOPBRK | status ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
}
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_set_termios - termios operations , handling data length , parity ,
2011-04-30 08:07:43 +04:00
* stop bits , flow control , baud rate
* @ port : Handle to the uart port structure
* @ termios : Handle to the input termios structure
* @ old : Values of the previously saved termios structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_set_termios ( struct uart_port * port ,
2011-04-30 08:07:43 +04:00
struct ktermios * termios , struct ktermios * old )
{
unsigned int cval = 0 ;
2013-10-18 01:08:10 +04:00
unsigned int baud , minbaud , maxbaud ;
2011-04-30 08:07:43 +04:00
unsigned long flags ;
unsigned int ctrl_reg , mode_reg ;
spin_lock_irqsave ( & port - > lock , flags ) ;
2015-01-16 15:49:25 +03:00
/* Wait for the transmit FIFO to empty before making changes */
2016-01-12 04:41:40 +03:00
if ( ! ( readl ( port - > membase + CDNS_UART_CR ) &
2015-03-13 00:11:59 +03:00
CDNS_UART_CR_TX_DIS ) ) {
2016-01-12 04:41:40 +03:00
while ( ! ( readl ( port - > membase + CDNS_UART_SR ) &
2015-01-16 15:49:25 +03:00
CDNS_UART_SR_TXEMPTY ) ) {
cpu_relax ( ) ;
}
2011-04-30 08:07:43 +04:00
}
/* Disable the TX and RX to set baud rate */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg | = CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:10 +04:00
/*
* Min baud rate = 6 bps and Max Baud Rate is 10 Mbps for 100 Mhz clk
* min and max baud should be calculated here based on port - > uartclk .
* this way we get a valid baud and can safely call set_baud ( )
*/
2014-04-05 04:23:43 +04:00
minbaud = port - > uartclk /
( ( CDNS_UART_BDIV_MAX + 1 ) * CDNS_UART_CD_MAX * 8 ) ;
maxbaud = port - > uartclk / ( CDNS_UART_BDIV_MIN + 1 ) ;
2013-10-18 01:08:10 +04:00
baud = uart_get_baud_rate ( port , termios , old , minbaud , maxbaud ) ;
2014-04-05 04:23:43 +04:00
baud = cdns_uart_set_baud_rate ( port , baud ) ;
2011-04-30 08:07:43 +04:00
if ( tty_termios_baud_rate ( termios ) )
tty_termios_encode_baud_rate ( termios , baud , baud ) ;
2014-04-05 04:23:39 +04:00
/* Update the per-port timeout. */
2011-04-30 08:07:43 +04:00
uart_update_timeout ( port , termios - > c_cflag , baud ) ;
/* Set TX/RX Reset */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg | = CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
2016-09-15 12:15:31 +03:00
while ( readl ( port - > membase + CDNS_UART_CR ) &
( CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ) )
cpu_relax ( ) ;
2014-04-05 04:23:39 +04:00
/*
* Clear the RX disable and TX disable bits and then set the TX enable
2011-04-30 08:07:43 +04:00
* bit and RX enable bit to enable the transmitter and receiver .
*/
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg & = ~ ( CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ) ;
ctrl_reg | = CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:40 +03:00
writel ( rx_timeout , port - > membase + CDNS_UART_RXTOUT ) ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
port - > read_status_mask = CDNS_UART_IXR_TXEMPTY | CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_TOUT ;
2011-04-30 08:07:43 +04:00
port - > ignore_status_mask = 0 ;
if ( termios - > c_iflag & INPCK )
2014-04-05 04:23:43 +04:00
port - > read_status_mask | = CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING ;
2011-04-30 08:07:43 +04:00
if ( termios - > c_iflag & IGNPAR )
2014-04-05 04:23:43 +04:00
port - > ignore_status_mask | = CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN ;
2011-04-30 08:07:43 +04:00
/* ignore all characters if CREAD is not set */
if ( ( termios - > c_cflag & CREAD ) = = 0 )
2014-04-05 04:23:43 +04:00
port - > ignore_status_mask | = CDNS_UART_IXR_RXTRIG |
CDNS_UART_IXR_TOUT | CDNS_UART_IXR_PARITY |
CDNS_UART_IXR_FRAMING | CDNS_UART_IXR_OVERRUN ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:40 +03:00
mode_reg = readl ( port - > membase + CDNS_UART_MR ) ;
2011-04-30 08:07:43 +04:00
/* Handling Data Size */
switch ( termios - > c_cflag & CSIZE ) {
case CS6 :
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_CHARLEN_6_BIT ;
2011-04-30 08:07:43 +04:00
break ;
case CS7 :
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_CHARLEN_7_BIT ;
2011-04-30 08:07:43 +04:00
break ;
default :
case CS8 :
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_CHARLEN_8_BIT ;
2011-04-30 08:07:43 +04:00
termios - > c_cflag & = ~ CSIZE ;
termios - > c_cflag | = CS8 ;
break ;
}
/* Handling Parity and Stop Bits length */
if ( termios - > c_cflag & CSTOPB )
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_STOPMODE_2_BIT ; /* 2 STOP bits */
2011-04-30 08:07:43 +04:00
else
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_STOPMODE_1_BIT ; /* 1 STOP bit */
2011-04-30 08:07:43 +04:00
if ( termios - > c_cflag & PARENB ) {
/* Mark or Space parity */
if ( termios - > c_cflag & CMSPAR ) {
if ( termios - > c_cflag & PARODD )
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_PARITY_MARK ;
2011-04-30 08:07:43 +04:00
else
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_PARITY_SPACE ;
2013-10-18 01:08:10 +04:00
} else {
if ( termios - > c_cflag & PARODD )
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_PARITY_ODD ;
2011-04-30 08:07:43 +04:00
else
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_PARITY_EVEN ;
2013-10-18 01:08:10 +04:00
}
} else {
2014-04-05 04:23:43 +04:00
cval | = CDNS_UART_MR_PARITY_NONE ;
2013-10-18 01:08:10 +04:00
}
cval | = mode_reg & 1 ;
2016-01-12 04:41:40 +03:00
writel ( cval , port - > membase + CDNS_UART_MR ) ;
2011-04-30 08:07:43 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_startup - Called when an application opens a cdns_uart port
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_startup ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2016-09-15 12:15:29 +03:00
struct cdns_uart * cdns_uart = port - > private_data ;
bool is_brk_support ;
2016-01-12 04:41:36 +03:00
int ret ;
2015-12-26 13:43:53 +03:00
unsigned long flags ;
2016-01-12 04:41:36 +03:00
unsigned int status = 0 ;
2011-04-30 08:07:43 +04:00
2016-09-15 12:15:29 +03:00
is_brk_support = cdns_uart - > quirks & CDNS_UART_RXBS_SUPPORT ;
2015-12-26 13:43:53 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2011-04-30 08:07:43 +04:00
/* Disable the TX and RX */
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
/* Set the Control Register with TX/RX Enable, TX/RX Reset,
* no break chars .
*/
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
2016-09-15 12:15:31 +03:00
while ( readl ( port - > membase + CDNS_UART_CR ) &
( CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ) )
cpu_relax ( ) ;
2015-12-26 13:43:53 +03:00
/*
* Clear the RX disable bit and then set the RX enable bit to enable
* the receiver .
2011-04-30 08:07:43 +04:00
*/
2016-01-12 04:41:40 +03:00
status = readl ( port - > membase + CDNS_UART_CR ) ;
2015-12-26 13:43:53 +03:00
status & = CDNS_UART_CR_RX_DIS ;
status | = CDNS_UART_CR_RX_EN ;
2016-01-12 04:41:40 +03:00
writel ( status , port - > membase + CDNS_UART_CR ) ;
2011-04-30 08:07:43 +04:00
/* Set the Mode Register with normal mode,8 data bits,1 stop bit,
* no parity .
*/
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_MR_CHMODE_NORM | CDNS_UART_MR_STOPMODE_1_BIT
2014-04-05 04:23:43 +04:00
| CDNS_UART_MR_PARITY_NONE | CDNS_UART_MR_CHARLEN_8_BIT ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_MR ) ;
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:08 +04:00
/*
* Set the RX FIFO Trigger level to use most of the FIFO , but it
* can be tuned with a module parameter
*/
2016-01-12 04:41:40 +03:00
writel ( rx_trigger_level , port - > membase + CDNS_UART_RXWM ) ;
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:08 +04:00
/*
* Receive Timeout register is enabled but it
* can be tuned with a module parameter
*/
2016-01-12 04:41:40 +03:00
writel ( rx_timeout , port - > membase + CDNS_UART_RXTOUT ) ;
2011-04-30 08:07:43 +04:00
2013-03-22 21:49:27 +04:00
/* Clear out any pending interrupts before enabling them */
2016-01-12 04:41:40 +03:00
writel ( readl ( port - > membase + CDNS_UART_ISR ) ,
port - > membase + CDNS_UART_ISR ) ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:36 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
ret = request_irq ( port - > irq , cdns_uart_isr , 0 , CDNS_UART_NAME , port ) ;
if ( ret ) {
dev_err ( port - > dev , " request_irq '%d' failed with %d \n " ,
port - > irq , ret ) ;
return ret ;
}
2011-04-30 08:07:43 +04:00
/* Set the Interrupt Registers with desired interrupts */
2016-09-15 12:15:29 +03:00
if ( is_brk_support )
writel ( CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK ,
port - > membase + CDNS_UART_IER ) ;
else
writel ( CDNS_UART_RX_IRQS , port - > membase + CDNS_UART_IER ) ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:36 +03:00
return 0 ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_shutdown - Called when an application closes a cdns_uart port
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_shutdown ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
int status ;
2015-12-26 13:43:55 +03:00
unsigned long flags ;
spin_lock_irqsave ( & port - > lock , flags ) ;
2011-04-30 08:07:43 +04:00
/* Disable interrupts */
2016-01-12 04:41:40 +03:00
status = readl ( port - > membase + CDNS_UART_IMR ) ;
writel ( status , port - > membase + CDNS_UART_IDR ) ;
writel ( 0xffffffff , port - > membase + CDNS_UART_ISR ) ;
2011-04-30 08:07:43 +04:00
/* Disable the TX and RX */
2015-03-13 00:11:59 +03:00
writel ( CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ,
2016-01-12 04:41:40 +03:00
port - > membase + CDNS_UART_CR ) ;
2015-12-26 13:43:55 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2011-04-30 08:07:43 +04:00
free_irq ( port - > irq , port ) ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_type - Set UART type to cdns_uart port
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
*
2014-04-05 04:23:37 +04:00
* Return : string on success , NULL otherwise
*/
2014-04-05 04:23:43 +04:00
static const char * cdns_uart_type ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
return port - > type = = PORT_XUARTPS ? CDNS_UART_NAME : NULL ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_verify_port - Verify the port params
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
* @ ser : Handle to the structure whose members are compared
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise .
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_verify_port ( struct uart_port * port ,
2011-04-30 08:07:43 +04:00
struct serial_struct * ser )
{
if ( ser - > type ! = PORT_UNKNOWN & & ser - > type ! = PORT_XUARTPS )
return - EINVAL ;
if ( port - > irq ! = ser - > irq )
return - EINVAL ;
if ( ser - > io_type ! = UPIO_MEM )
return - EINVAL ;
if ( port - > iobase ! = ser - > port )
return - EINVAL ;
if ( ser - > hub6 ! = 0 )
return - EINVAL ;
return 0 ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_request_port - Claim the memory region attached to cdns_uart port ,
* called when the driver adds a cdns_uart port via
2011-04-30 08:07:43 +04:00
* uart_add_one_port ( )
* @ port : Handle to the uart port structure
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise .
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_request_port ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
if ( ! request_mem_region ( port - > mapbase , CDNS_UART_REGISTER_SPACE ,
CDNS_UART_NAME ) ) {
2011-04-30 08:07:43 +04:00
return - ENOMEM ;
}
2014-04-05 04:23:43 +04:00
port - > membase = ioremap ( port - > mapbase , CDNS_UART_REGISTER_SPACE ) ;
2011-04-30 08:07:43 +04:00
if ( ! port - > membase ) {
dev_err ( port - > dev , " Unable to map registers \n " ) ;
2014-04-05 04:23:43 +04:00
release_mem_region ( port - > mapbase , CDNS_UART_REGISTER_SPACE ) ;
2011-04-30 08:07:43 +04:00
return - ENOMEM ;
}
return 0 ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_release_port - Release UART port
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:39 +04:00
*
2014-04-05 04:23:43 +04:00
* Release the memory region attached to a cdns_uart port . Called when the
* driver removes a cdns_uart port via uart_remove_one_port ( ) .
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_release_port ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
release_mem_region ( port - > mapbase , CDNS_UART_REGISTER_SPACE ) ;
2011-04-30 08:07:43 +04:00
iounmap ( port - > membase ) ;
port - > membase = NULL ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_config_port - Configure UART port
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
* @ flags : If any
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_config_port ( struct uart_port * port , int flags )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
if ( flags & UART_CONFIG_TYPE & & cdns_uart_request_port ( port ) = = 0 )
2011-04-30 08:07:43 +04:00
port - > type = PORT_XUARTPS ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_get_mctrl - Get the modem control state
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
*
2014-04-05 04:23:37 +04:00
* Return : the modem control state
*/
2014-04-05 04:23:43 +04:00
static unsigned int cdns_uart_get_mctrl ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR ;
}
2014-04-05 04:23:43 +04:00
static void cdns_uart_set_mctrl ( struct uart_port * port , unsigned int mctrl )
2011-04-30 08:07:43 +04:00
{
2014-11-05 15:35:16 +03:00
u32 val ;
2017-01-23 15:26:08 +03:00
u32 mode_reg ;
2014-11-05 15:35:16 +03:00
2016-01-12 04:41:40 +03:00
val = readl ( port - > membase + CDNS_UART_MODEMCR ) ;
2017-01-23 15:26:08 +03:00
mode_reg = readl ( port - > membase + CDNS_UART_MR ) ;
2014-11-05 15:35:16 +03:00
val & = ~ ( CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR ) ;
2017-01-23 15:26:08 +03:00
mode_reg & = ~ CDNS_UART_MR_CHMODE_MASK ;
2014-11-05 15:35:16 +03:00
if ( mctrl & TIOCM_RTS )
val | = CDNS_UART_MODEMCR_RTS ;
if ( mctrl & TIOCM_DTR )
val | = CDNS_UART_MODEMCR_DTR ;
2017-01-23 15:26:08 +03:00
if ( mctrl & TIOCM_LOOP )
mode_reg | = CDNS_UART_MR_CHMODE_L_LOOP ;
else
mode_reg | = CDNS_UART_MR_CHMODE_NORM ;
2014-11-05 15:35:16 +03:00
2016-01-12 04:41:40 +03:00
writel ( val , port - > membase + CDNS_UART_MODEMCR ) ;
2017-01-23 15:26:08 +03:00
writel ( mode_reg , port - > membase + CDNS_UART_MR ) ;
2011-04-30 08:07:43 +04:00
}
2013-10-18 01:08:07 +04:00
# ifdef CONFIG_CONSOLE_POLL
2014-04-05 04:23:43 +04:00
static int cdns_uart_poll_get_char ( struct uart_port * port )
2013-10-18 01:08:07 +04:00
{
int c ;
2015-12-26 13:43:50 +03:00
unsigned long flags ;
2013-10-18 01:08:07 +04:00
2015-12-26 13:43:50 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2013-10-18 01:08:07 +04:00
/* Check if FIFO is empty */
2016-01-12 04:41:40 +03:00
if ( readl ( port - > membase + CDNS_UART_SR ) & CDNS_UART_SR_RXEMPTY )
2013-10-18 01:08:07 +04:00
c = NO_POLL_CHAR ;
else /* Read a character */
2016-01-12 04:41:40 +03:00
c = ( unsigned char ) readl ( port - > membase + CDNS_UART_FIFO ) ;
2013-10-18 01:08:07 +04:00
2015-12-26 13:43:50 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2013-10-18 01:08:07 +04:00
return c ;
}
2014-04-05 04:23:43 +04:00
static void cdns_uart_poll_put_char ( struct uart_port * port , unsigned char c )
2013-10-18 01:08:07 +04:00
{
2015-12-26 13:43:50 +03:00
unsigned long flags ;
2013-10-18 01:08:07 +04:00
2015-12-26 13:43:50 +03:00
spin_lock_irqsave ( & port - > lock , flags ) ;
2013-10-18 01:08:07 +04:00
/* Wait until FIFO is empty */
2016-01-12 04:41:40 +03:00
while ( ! ( readl ( port - > membase + CDNS_UART_SR ) & CDNS_UART_SR_TXEMPTY ) )
2013-10-18 01:08:07 +04:00
cpu_relax ( ) ;
/* Write a character */
2016-01-12 04:41:40 +03:00
writel ( c , port - > membase + CDNS_UART_FIFO ) ;
2013-10-18 01:08:07 +04:00
/* Wait until FIFO is empty */
2016-01-12 04:41:40 +03:00
while ( ! ( readl ( port - > membase + CDNS_UART_SR ) & CDNS_UART_SR_TXEMPTY ) )
2013-10-18 01:08:07 +04:00
cpu_relax ( ) ;
2015-12-26 13:43:50 +03:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
2013-10-18 01:08:07 +04:00
return ;
}
# endif
2016-05-27 12:35:19 +03:00
static void cdns_uart_pm ( struct uart_port * port , unsigned int state ,
unsigned int oldstate )
{
struct cdns_uart * cdns_uart = port - > private_data ;
switch ( state ) {
case UART_PM_STATE_OFF :
clk_disable ( cdns_uart - > uartclk ) ;
clk_disable ( cdns_uart - > pclk ) ;
break ;
default :
clk_enable ( cdns_uart - > pclk ) ;
clk_enable ( cdns_uart - > uartclk ) ;
break ;
}
}
2016-09-01 20:51:36 +03:00
static const struct uart_ops cdns_uart_ops = {
2014-04-05 04:23:43 +04:00
. set_mctrl = cdns_uart_set_mctrl ,
. get_mctrl = cdns_uart_get_mctrl ,
. start_tx = cdns_uart_start_tx ,
. stop_tx = cdns_uart_stop_tx ,
. stop_rx = cdns_uart_stop_rx ,
. tx_empty = cdns_uart_tx_empty ,
. break_ctl = cdns_uart_break_ctl ,
. set_termios = cdns_uart_set_termios ,
. startup = cdns_uart_startup ,
. shutdown = cdns_uart_shutdown ,
2016-05-27 12:35:19 +03:00
. pm = cdns_uart_pm ,
2014-04-05 04:23:43 +04:00
. type = cdns_uart_type ,
. verify_port = cdns_uart_verify_port ,
. request_port = cdns_uart_request_port ,
. release_port = cdns_uart_release_port ,
. config_port = cdns_uart_config_port ,
2013-10-18 01:08:07 +04:00
# ifdef CONFIG_CONSOLE_POLL
2014-04-05 04:23:43 +04:00
. poll_get_char = cdns_uart_poll_get_char ,
. poll_put_char = cdns_uart_poll_put_char ,
2013-10-18 01:08:07 +04:00
# endif
2011-04-30 08:07:43 +04:00
} ;
2015-03-12 00:39:26 +03:00
static struct uart_port cdns_uart_port [ CDNS_UART_NR_PORTS ] ;
2011-04-30 08:07:43 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_get_port - Configure the port from platform device resource info
2014-04-05 04:23:38 +04:00
* @ id : Port id
*
2014-04-05 04:23:37 +04:00
* Return : a pointer to a uart_port or NULL for failure
*/
2014-04-05 04:23:43 +04:00
static struct uart_port * cdns_uart_get_port ( int id )
2011-04-30 08:07:43 +04:00
{
struct uart_port * port ;
2014-04-05 04:23:38 +04:00
/* Try the given port id if failed use default method */
2014-04-05 04:23:43 +04:00
if ( cdns_uart_port [ id ] . mapbase ! = 0 ) {
2014-04-05 04:23:38 +04:00
/* Find the next unused port */
2014-04-05 04:23:43 +04:00
for ( id = 0 ; id < CDNS_UART_NR_PORTS ; id + + )
if ( cdns_uart_port [ id ] . mapbase = = 0 )
2014-04-05 04:23:38 +04:00
break ;
}
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
if ( id > = CDNS_UART_NR_PORTS )
2011-04-30 08:07:43 +04:00
return NULL ;
2014-04-05 04:23:43 +04:00
port = & cdns_uart_port [ id ] ;
2011-04-30 08:07:43 +04:00
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init ( & port - > lock ) ;
port - > membase = NULL ;
port - > irq = 0 ;
port - > type = PORT_UNKNOWN ;
port - > iotype = UPIO_MEM32 ;
port - > flags = UPF_BOOT_AUTOCONF ;
2014-04-05 04:23:43 +04:00
port - > ops = & cdns_uart_ops ;
port - > fifosize = CDNS_UART_FIFO_SIZE ;
2011-04-30 08:07:43 +04:00
port - > line = id ;
port - > dev = NULL ;
return port ;
}
# ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_console_wait_tx - Wait for the TX to be full
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_console_wait_tx ( struct uart_port * port )
2011-04-30 08:07:43 +04:00
{
2016-01-12 04:41:40 +03:00
while ( ! ( readl ( port - > membase + CDNS_UART_SR ) & CDNS_UART_SR_TXEMPTY ) )
2011-04-30 08:07:43 +04:00
barrier ( ) ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_console_putchar - write the character to the FIFO buffer
2011-04-30 08:07:43 +04:00
* @ port : Handle to the uart port structure
* @ ch : Character to be written
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_console_putchar ( struct uart_port * port , int ch )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
cdns_uart_console_wait_tx ( port ) ;
2016-01-12 04:41:40 +03:00
writel ( ch , port - > membase + CDNS_UART_FIFO ) ;
2011-04-30 08:07:43 +04:00
}
2015-05-07 12:55:40 +03:00
static void __init cdns_early_write ( struct console * con , const char * s ,
unsigned n )
2014-09-10 14:43:02 +04:00
{
struct earlycon_device * dev = con - > data ;
uart_console_write ( & dev - > port , s , n , cdns_uart_console_putchar ) ;
}
static int __init cdns_early_console_setup ( struct earlycon_device * device ,
const char * opt )
{
2016-09-22 18:58:16 +03:00
struct uart_port * port = & device - > port ;
if ( ! port - > membase )
2014-09-10 14:43:02 +04:00
return - ENODEV ;
2016-09-22 18:58:16 +03:00
/* initialise control register */
writel ( CDNS_UART_CR_TX_EN | CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ,
port - > membase + CDNS_UART_CR ) ;
/* only set baud if specified on command line - otherwise
* assume it has been initialized by a boot loader .
*/
if ( device - > baud ) {
u32 cd = 0 , bdiv = 0 ;
u32 mr ;
int div8 ;
cdns_uart_calc_baud_divs ( port - > uartclk , device - > baud ,
& bdiv , & cd , & div8 ) ;
mr = CDNS_UART_MR_PARITY_NONE ;
if ( div8 )
mr | = CDNS_UART_MR_CLKSEL ;
writel ( mr , port - > membase + CDNS_UART_MR ) ;
writel ( cd , port - > membase + CDNS_UART_BAUDGEN ) ;
writel ( bdiv , port - > membase + CDNS_UART_BAUDDIV ) ;
}
2014-09-10 14:43:02 +04:00
device - > con - > write = cdns_early_write ;
return 0 ;
}
2016-02-18 10:57:20 +03:00
OF_EARLYCON_DECLARE ( cdns , " xlnx,xuartps " , cdns_early_console_setup ) ;
OF_EARLYCON_DECLARE ( cdns , " cdns,uart-r1p8 " , cdns_early_console_setup ) ;
OF_EARLYCON_DECLARE ( cdns , " cdns,uart-r1p12 " , cdns_early_console_setup ) ;
2016-10-12 10:47:27 +03:00
OF_EARLYCON_DECLARE ( cdns , " xlnx,zynqmp-uart " , cdns_early_console_setup ) ;
2014-09-10 14:43:02 +04:00
2011-04-30 08:07:43 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_console_write - perform write operation
2014-04-05 04:23:37 +04:00
* @ co : Console handle
2011-04-30 08:07:43 +04:00
* @ s : Pointer to character array
* @ count : No of characters
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static void cdns_uart_console_write ( struct console * co , const char * s ,
2011-04-30 08:07:43 +04:00
unsigned int count )
{
2014-04-05 04:23:43 +04:00
struct uart_port * port = & cdns_uart_port [ co - > index ] ;
2011-04-30 08:07:43 +04:00
unsigned long flags ;
2013-10-18 01:08:09 +04:00
unsigned int imr , ctrl ;
2011-04-30 08:07:43 +04:00
int locked = 1 ;
2016-01-12 04:41:39 +03:00
if ( port - > sysrq )
locked = 0 ;
else if ( oops_in_progress )
2011-04-30 08:07:43 +04:00
locked = spin_trylock_irqsave ( & port - > lock , flags ) ;
else
spin_lock_irqsave ( & port - > lock , flags ) ;
/* save and disable interrupt */
2016-01-12 04:41:40 +03:00
imr = readl ( port - > membase + CDNS_UART_IMR ) ;
writel ( imr , port - > membase + CDNS_UART_IDR ) ;
2011-04-30 08:07:43 +04:00
2013-10-18 01:08:09 +04:00
/*
* Make sure that the tx part is enabled . Set the TX enable bit and
* clear the TX disable bit to enable the transmitter .
*/
2016-01-12 04:41:40 +03:00
ctrl = readl ( port - > membase + CDNS_UART_CR ) ;
2015-12-26 13:43:49 +03:00
ctrl & = ~ CDNS_UART_CR_TX_DIS ;
ctrl | = CDNS_UART_CR_TX_EN ;
2016-01-12 04:41:40 +03:00
writel ( ctrl , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:09 +04:00
2014-04-05 04:23:43 +04:00
uart_console_write ( port , s , count , cdns_uart_console_putchar ) ;
cdns_uart_console_wait_tx ( port ) ;
2011-04-30 08:07:43 +04:00
2016-01-12 04:41:40 +03:00
writel ( ctrl , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:09 +04:00
2014-04-05 04:23:42 +04:00
/* restore interrupt state */
2016-01-12 04:41:40 +03:00
writel ( imr , port - > membase + CDNS_UART_IER ) ;
2011-04-30 08:07:43 +04:00
if ( locked )
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_console_setup - Initialize the uart to default config
2011-04-30 08:07:43 +04:00
* @ co : Console handle
* @ options : Initial settings of uart
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise .
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int __init cdns_uart_console_setup ( struct console * co , char * options )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
struct uart_port * port = & cdns_uart_port [ co - > index ] ;
2011-04-30 08:07:43 +04:00
int baud = 9600 ;
int bits = 8 ;
int parity = ' n ' ;
int flow = ' n ' ;
2014-04-05 04:23:43 +04:00
if ( co - > index < 0 | | co - > index > = CDNS_UART_NR_PORTS )
2011-04-30 08:07:43 +04:00
return - EINVAL ;
2015-03-12 00:39:28 +03:00
if ( ! port - > membase ) {
2015-02-25 02:13:57 +03:00
pr_debug ( " console on " CDNS_UART_TTY_NAME " %i not present \n " ,
co - > index ) ;
2011-04-30 08:07:43 +04:00
return - ENODEV ;
}
if ( options )
uart_parse_options ( options , & baud , & parity , & bits , & flow ) ;
return uart_set_options ( port , co , baud , parity , bits , flow ) ;
}
2014-04-05 04:23:43 +04:00
static struct uart_driver cdns_uart_uart_driver ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
static struct console cdns_uart_console = {
. name = CDNS_UART_TTY_NAME ,
. write = cdns_uart_console_write ,
2011-04-30 08:07:43 +04:00
. device = uart_console_device ,
2014-04-05 04:23:43 +04:00
. setup = cdns_uart_console_setup ,
2011-04-30 08:07:43 +04:00
. flags = CON_PRINTBUFFER ,
. index = - 1 , /* Specified on the cmdline (e.g. console=ttyPS ) */
2014-04-05 04:23:43 +04:00
. data = & cdns_uart_uart_driver ,
2011-04-30 08:07:43 +04:00
} ;
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_console_init - Initialization call
2011-04-30 08:07:43 +04:00
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int __init cdns_uart_console_init ( void )
2011-04-30 08:07:43 +04:00
{
2014-04-05 04:23:43 +04:00
register_console ( & cdns_uart_console ) ;
2011-04-30 08:07:43 +04:00
return 0 ;
}
2014-04-05 04:23:43 +04:00
console_initcall ( cdns_uart_console_init ) ;
2011-04-30 08:07:43 +04:00
# endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
2014-04-05 04:23:43 +04:00
static struct uart_driver cdns_uart_uart_driver = {
2014-04-05 04:23:39 +04:00
. owner = THIS_MODULE ,
2014-04-05 04:23:43 +04:00
. driver_name = CDNS_UART_NAME ,
. dev_name = CDNS_UART_TTY_NAME ,
. major = CDNS_UART_MAJOR ,
. minor = CDNS_UART_MINOR ,
. nr = CDNS_UART_NR_PORTS ,
2013-10-22 03:41:00 +04:00
# ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
2014-04-05 04:23:43 +04:00
. cons = & cdns_uart_console ,
2013-10-22 03:41:00 +04:00
# endif
} ;
2013-10-18 01:08:12 +04:00
# ifdef CONFIG_PM_SLEEP
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_suspend - suspend event
2013-10-18 01:08:12 +04:00
* @ device : Pointer to the device structure
*
2014-04-05 04:23:37 +04:00
* Return : 0
2013-10-18 01:08:12 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_suspend ( struct device * device )
2013-10-18 01:08:12 +04:00
{
struct uart_port * port = dev_get_drvdata ( device ) ;
struct tty_struct * tty ;
struct device * tty_dev ;
int may_wake = 0 ;
/* Get the tty which could be NULL so don't assume it's valid */
tty = tty_port_tty_get ( & port - > state - > port ) ;
if ( tty ) {
tty_dev = tty - > dev ;
may_wake = device_may_wakeup ( tty_dev ) ;
tty_kref_put ( tty ) ;
}
/*
* Call the API provided in serial_core . c file which handles
* the suspend .
*/
2014-04-05 04:23:43 +04:00
uart_suspend_port ( & cdns_uart_uart_driver , port ) ;
2013-10-18 01:08:12 +04:00
if ( console_suspend_enabled & & ! may_wake ) {
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart = port - > private_data ;
2013-10-18 01:08:12 +04:00
2014-04-05 04:23:43 +04:00
clk_disable ( cdns_uart - > uartclk ) ;
clk_disable ( cdns_uart - > pclk ) ;
2013-10-18 01:08:12 +04:00
} else {
unsigned long flags = 0 ;
spin_lock_irqsave ( & port - > lock , flags ) ;
/* Empty the receive FIFO 1st before making changes */
2016-01-12 04:41:40 +03:00
while ( ! ( readl ( port - > membase + CDNS_UART_SR ) &
2014-04-05 04:23:43 +04:00
CDNS_UART_SR_RXEMPTY ) )
2016-01-12 04:41:40 +03:00
readl ( port - > membase + CDNS_UART_FIFO ) ;
2013-10-18 01:08:12 +04:00
/* set RX trigger level to 1 */
2016-01-12 04:41:40 +03:00
writel ( 1 , port - > membase + CDNS_UART_RXWM ) ;
2013-10-18 01:08:12 +04:00
/* disable RX timeout interrups */
2016-01-12 04:41:40 +03:00
writel ( CDNS_UART_IXR_TOUT , port - > membase + CDNS_UART_IDR ) ;
2013-10-18 01:08:12 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
return 0 ;
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_resume - Resume after a previous suspend
2013-10-18 01:08:12 +04:00
* @ device : Pointer to the device structure
*
2014-04-05 04:23:37 +04:00
* Return : 0
2013-10-18 01:08:12 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_resume ( struct device * device )
2013-10-18 01:08:12 +04:00
{
struct uart_port * port = dev_get_drvdata ( device ) ;
unsigned long flags = 0 ;
u32 ctrl_reg ;
struct tty_struct * tty ;
struct device * tty_dev ;
int may_wake = 0 ;
/* Get the tty which could be NULL so don't assume it's valid */
tty = tty_port_tty_get ( & port - > state - > port ) ;
if ( tty ) {
tty_dev = tty - > dev ;
may_wake = device_may_wakeup ( tty_dev ) ;
tty_kref_put ( tty ) ;
}
if ( console_suspend_enabled & & ! may_wake ) {
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart = port - > private_data ;
2013-10-18 01:08:12 +04:00
2014-04-05 04:23:43 +04:00
clk_enable ( cdns_uart - > pclk ) ;
clk_enable ( cdns_uart - > uartclk ) ;
2013-10-18 01:08:12 +04:00
spin_lock_irqsave ( & port - > lock , flags ) ;
/* Set TX/RX Reset */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg | = CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
while ( readl ( port - > membase + CDNS_UART_CR ) &
2014-04-05 04:23:43 +04:00
( CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST ) )
2013-10-18 01:08:12 +04:00
cpu_relax ( ) ;
/* restore rx timeout value */
2016-01-12 04:41:40 +03:00
writel ( rx_timeout , port - > membase + CDNS_UART_RXTOUT ) ;
2013-10-18 01:08:12 +04:00
/* Enable Tx/Rx */
2016-01-12 04:41:40 +03:00
ctrl_reg = readl ( port - > membase + CDNS_UART_CR ) ;
2014-04-05 04:23:43 +04:00
ctrl_reg & = ~ ( CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS ) ;
ctrl_reg | = CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN ;
2016-01-12 04:41:40 +03:00
writel ( ctrl_reg , port - > membase + CDNS_UART_CR ) ;
2013-10-18 01:08:12 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
} else {
spin_lock_irqsave ( & port - > lock , flags ) ;
/* restore original rx trigger level */
2016-01-12 04:41:40 +03:00
writel ( rx_trigger_level , port - > membase + CDNS_UART_RXWM ) ;
2013-10-18 01:08:12 +04:00
/* enable RX timeout interrupt */
2016-01-12 04:41:40 +03:00
writel ( CDNS_UART_IXR_TOUT , port - > membase + CDNS_UART_IER ) ;
2013-10-18 01:08:12 +04:00
spin_unlock_irqrestore ( & port - > lock , flags ) ;
}
2014-04-05 04:23:43 +04:00
return uart_resume_port ( & cdns_uart_uart_driver , port ) ;
2013-10-18 01:08:12 +04:00
}
# endif /* ! CONFIG_PM_SLEEP */
2014-04-05 04:23:43 +04:00
static SIMPLE_DEV_PM_OPS ( cdns_uart_dev_pm_ops , cdns_uart_suspend ,
cdns_uart_resume ) ;
2013-10-18 01:08:12 +04:00
2016-09-15 12:15:29 +03:00
static const struct cdns_platform_data zynqmp_uart_def = {
. quirks = CDNS_UART_RXBS_SUPPORT , } ;
/* Match table for of_platform binding */
static const struct of_device_id cdns_uart_of_match [ ] = {
{ . compatible = " xlnx,xuartps " , } ,
{ . compatible = " cdns,uart-r1p8 " , } ,
{ . compatible = " cdns,uart-r1p12 " , . data = & zynqmp_uart_def } ,
2016-10-12 10:47:27 +03:00
{ . compatible = " xlnx,zynqmp-uart " , . data = & zynqmp_uart_def } ,
2016-09-15 12:15:29 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , cdns_uart_of_match ) ;
2011-04-30 08:07:43 +04:00
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_probe - Platform driver probe
2011-04-30 08:07:43 +04:00
* @ pdev : Pointer to the platform device structure
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_probe ( struct platform_device * pdev )
2011-04-30 08:07:43 +04:00
{
2015-04-13 17:34:21 +03:00
int rc , id , irq ;
2011-04-30 08:07:43 +04:00
struct uart_port * port ;
2015-04-13 17:34:21 +03:00
struct resource * res ;
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart_data ;
2016-09-15 12:15:29 +03:00
const struct of_device_id * match ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
cdns_uart_data = devm_kzalloc ( & pdev - > dev , sizeof ( * cdns_uart_data ) ,
2013-10-18 01:08:05 +04:00
GFP_KERNEL ) ;
2014-04-05 04:23:43 +04:00
if ( ! cdns_uart_data )
2013-05-13 21:46:38 +04:00
return - ENOMEM ;
2016-09-15 12:15:29 +03:00
match = of_match_node ( cdns_uart_of_match , pdev - > dev . of_node ) ;
if ( match & & match - > data ) {
const struct cdns_platform_data * data = match - > data ;
cdns_uart_data - > quirks = data - > quirks ;
}
2014-04-05 04:23:43 +04:00
cdns_uart_data - > pclk = devm_clk_get ( & pdev - > dev , " pclk " ) ;
if ( IS_ERR ( cdns_uart_data - > pclk ) ) {
cdns_uart_data - > pclk = devm_clk_get ( & pdev - > dev , " aper_clk " ) ;
if ( ! IS_ERR ( cdns_uart_data - > pclk ) )
dev_err ( & pdev - > dev , " clock name 'aper_clk' is deprecated. \n " ) ;
}
if ( IS_ERR ( cdns_uart_data - > pclk ) ) {
dev_err ( & pdev - > dev , " pclk clock not found. \n " ) ;
return PTR_ERR ( cdns_uart_data - > pclk ) ;
}
cdns_uart_data - > uartclk = devm_clk_get ( & pdev - > dev , " uart_clk " ) ;
if ( IS_ERR ( cdns_uart_data - > uartclk ) ) {
cdns_uart_data - > uartclk = devm_clk_get ( & pdev - > dev , " ref_clk " ) ;
if ( ! IS_ERR ( cdns_uart_data - > uartclk ) )
dev_err ( & pdev - > dev , " clock name 'ref_clk' is deprecated. \n " ) ;
2013-05-13 21:46:38 +04:00
}
2014-04-05 04:23:43 +04:00
if ( IS_ERR ( cdns_uart_data - > uartclk ) ) {
dev_err ( & pdev - > dev , " uart_clk clock not found. \n " ) ;
return PTR_ERR ( cdns_uart_data - > uartclk ) ;
2013-01-21 22:57:41 +04:00
}
2016-05-27 12:35:19 +03:00
rc = clk_prepare ( cdns_uart_data - > pclk ) ;
2013-05-13 21:46:38 +04:00
if ( rc ) {
2014-04-05 04:23:43 +04:00
dev_err ( & pdev - > dev , " Unable to enable pclk clock. \n " ) ;
2013-10-18 01:08:05 +04:00
return rc ;
2013-05-13 21:46:38 +04:00
}
2016-05-27 12:35:19 +03:00
rc = clk_prepare ( cdns_uart_data - > uartclk ) ;
2013-01-21 22:57:41 +04:00
if ( rc ) {
2013-05-13 21:46:38 +04:00
dev_err ( & pdev - > dev , " Unable to enable device clock. \n " ) ;
2014-04-05 04:23:43 +04:00
goto err_out_clk_dis_pclk ;
2011-04-30 08:07:43 +04:00
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-05-13 21:46:38 +04:00
if ( ! res ) {
rc = - ENODEV ;
goto err_out_clk_disable ;
}
2011-04-30 08:07:43 +04:00
2015-04-13 17:34:21 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < = 0 ) {
rc = - ENXIO ;
2013-05-13 21:46:38 +04:00
goto err_out_clk_disable ;
}
2011-04-30 08:07:43 +04:00
2013-10-22 03:41:01 +04:00
# ifdef CONFIG_COMMON_CLK
2014-04-05 04:23:43 +04:00
cdns_uart_data - > clk_rate_change_nb . notifier_call =
cdns_uart_clk_notifier_cb ;
if ( clk_notifier_register ( cdns_uart_data - > uartclk ,
& cdns_uart_data - > clk_rate_change_nb ) )
2013-10-18 01:08:11 +04:00
dev_warn ( & pdev - > dev , " Unable to register clock notifier. \n " ) ;
2013-10-22 03:41:01 +04:00
# endif
2014-04-05 04:23:38 +04:00
/* Look for a serialN alias */
id = of_alias_get_id ( pdev - > dev . of_node , " serial " ) ;
if ( id < 0 )
id = 0 ;
2013-10-18 01:08:11 +04:00
2011-04-30 08:07:43 +04:00
/* Initialize the port structure */
2014-04-05 04:23:43 +04:00
port = cdns_uart_get_port ( id ) ;
2011-04-30 08:07:43 +04:00
if ( ! port ) {
dev_err ( & pdev - > dev , " Cannot get uart_port structure \n " ) ;
2013-05-13 21:46:38 +04:00
rc = - ENODEV ;
2013-10-18 01:08:11 +04:00
goto err_out_notif_unreg ;
2011-04-30 08:07:43 +04:00
}
2013-05-13 21:46:38 +04:00
2016-01-12 04:41:38 +03:00
/*
* Register the port .
* This function also registers this device with the tty layer
* and triggers invocation of the config_port ( ) entry point .
*/
port - > mapbase = res - > start ;
port - > irq = irq ;
port - > dev = & pdev - > dev ;
port - > uartclk = clk_get_rate ( cdns_uart_data - > uartclk ) ;
port - > private_data = cdns_uart_data ;
cdns_uart_data - > port = port ;
platform_set_drvdata ( pdev , port ) ;
rc = uart_add_one_port ( & cdns_uart_uart_driver , port ) ;
if ( rc ) {
dev_err ( & pdev - > dev ,
" uart_add_one_port() failed; err=%i \n " , rc ) ;
goto err_out_notif_unreg ;
}
return 0 ;
2013-10-18 01:08:11 +04:00
err_out_notif_unreg :
2013-10-22 03:41:01 +04:00
# ifdef CONFIG_COMMON_CLK
2014-04-05 04:23:43 +04:00
clk_notifier_unregister ( cdns_uart_data - > uartclk ,
& cdns_uart_data - > clk_rate_change_nb ) ;
2013-10-22 03:41:01 +04:00
# endif
2013-05-13 21:46:38 +04:00
err_out_clk_disable :
2016-05-27 12:35:19 +03:00
clk_unprepare ( cdns_uart_data - > uartclk ) ;
2014-04-05 04:23:43 +04:00
err_out_clk_dis_pclk :
2016-05-27 12:35:19 +03:00
clk_unprepare ( cdns_uart_data - > pclk ) ;
2013-05-13 21:46:38 +04:00
return rc ;
2011-04-30 08:07:43 +04:00
}
/**
2014-04-05 04:23:43 +04:00
* cdns_uart_remove - called when the platform driver is unregistered
2011-04-30 08:07:43 +04:00
* @ pdev : Pointer to the platform device structure
*
2014-04-05 04:23:39 +04:00
* Return : 0 on success , negative errno otherwise
2014-04-05 04:23:37 +04:00
*/
2014-04-05 04:23:43 +04:00
static int cdns_uart_remove ( struct platform_device * pdev )
2011-04-30 08:07:43 +04:00
{
2013-05-23 14:39:36 +04:00
struct uart_port * port = platform_get_drvdata ( pdev ) ;
2014-04-05 04:23:43 +04:00
struct cdns_uart * cdns_uart_data = port - > private_data ;
2013-01-21 22:57:41 +04:00
int rc ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
/* Remove the cdns_uart port from the serial core */
2013-10-22 03:41:01 +04:00
# ifdef CONFIG_COMMON_CLK
2014-04-05 04:23:43 +04:00
clk_notifier_unregister ( cdns_uart_data - > uartclk ,
& cdns_uart_data - > clk_rate_change_nb ) ;
2013-10-22 03:41:01 +04:00
# endif
2014-04-05 04:23:43 +04:00
rc = uart_remove_one_port ( & cdns_uart_uart_driver , port ) ;
2013-01-21 22:57:41 +04:00
port - > mapbase = 0 ;
2016-05-27 12:35:19 +03:00
clk_unprepare ( cdns_uart_data - > uartclk ) ;
clk_unprepare ( cdns_uart_data - > pclk ) ;
2011-04-30 08:07:43 +04:00
return rc ;
}
2014-04-05 04:23:43 +04:00
static struct platform_driver cdns_uart_platform_driver = {
. probe = cdns_uart_probe ,
. remove = cdns_uart_remove ,
2011-04-30 08:07:43 +04:00
. driver = {
2014-04-05 04:23:43 +04:00
. name = CDNS_UART_NAME ,
. of_match_table = cdns_uart_of_match ,
. pm = & cdns_uart_dev_pm_ops ,
2011-04-30 08:07:43 +04:00
} ,
} ;
2014-04-05 04:23:43 +04:00
static int __init cdns_uart_init ( void )
2011-04-30 08:07:43 +04:00
{
int retval = 0 ;
2014-04-05 04:23:43 +04:00
/* Register the cdns_uart driver with the serial core */
retval = uart_register_driver ( & cdns_uart_uart_driver ) ;
2011-04-30 08:07:43 +04:00
if ( retval )
return retval ;
/* Register the platform driver */
2014-04-05 04:23:43 +04:00
retval = platform_driver_register ( & cdns_uart_platform_driver ) ;
2011-04-30 08:07:43 +04:00
if ( retval )
2014-04-05 04:23:43 +04:00
uart_unregister_driver ( & cdns_uart_uart_driver ) ;
2011-04-30 08:07:43 +04:00
return retval ;
}
2014-04-05 04:23:43 +04:00
static void __exit cdns_uart_exit ( void )
2011-04-30 08:07:43 +04:00
{
/* Unregister the platform driver */
2014-04-05 04:23:43 +04:00
platform_driver_unregister ( & cdns_uart_platform_driver ) ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
/* Unregister the cdns_uart driver */
uart_unregister_driver ( & cdns_uart_uart_driver ) ;
2011-04-30 08:07:43 +04:00
}
2014-04-05 04:23:43 +04:00
module_init ( cdns_uart_init ) ;
module_exit ( cdns_uart_exit ) ;
2011-04-30 08:07:43 +04:00
2014-04-05 04:23:43 +04:00
MODULE_DESCRIPTION ( " Driver for Cadence UART " ) ;
2011-04-30 08:07:43 +04:00
MODULE_AUTHOR ( " Xilinx Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;