2017-11-06 18:11:51 +01:00
// SPDX-License-Identifier: GPL-2.0
2016-08-17 19:20:27 +03:00
/*
* 8250 _lpss . c - Driver for UART on Intel Braswell and various other Intel SoCs
*
* Copyright ( C ) 2016 Intel Corporation
* Author : Andy Shevchenko < andriy . shevchenko @ linux . intel . com >
*/
# include <linux/bitops.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/rational.h>
# include <linux/dmaengine.h>
2016-08-17 19:20:30 +03:00
# include <linux/dma/dw.h>
2016-08-17 19:20:27 +03:00
2019-08-06 12:43:18 +03:00
# include "8250_dwlib.h"
2016-08-17 19:20:27 +03:00
2016-08-17 19:20:28 +03:00
# define PCI_DEVICE_ID_INTEL_QRK_UARTx 0x0936
2016-08-17 19:20:27 +03:00
# define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a
# define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c
# define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a
# define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c
2019-08-06 12:43:22 +03:00
# define PCI_DEVICE_ID_INTEL_EHL_UART0 0x4b96
# define PCI_DEVICE_ID_INTEL_EHL_UART1 0x4b97
# define PCI_DEVICE_ID_INTEL_EHL_UART2 0x4b98
# define PCI_DEVICE_ID_INTEL_EHL_UART3 0x4b99
# define PCI_DEVICE_ID_INTEL_EHL_UART4 0x4b9a
# define PCI_DEVICE_ID_INTEL_EHL_UART5 0x4b9b
2016-08-17 19:20:27 +03:00
# define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3
# define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4
/* Intel LPSS specific registers */
# define BYT_PRV_CLK 0x800
# define BYT_PRV_CLK_EN BIT(0)
# define BYT_PRV_CLK_M_VAL_SHIFT 1
# define BYT_PRV_CLK_N_VAL_SHIFT 16
# define BYT_PRV_CLK_UPDATE BIT(31)
# define BYT_TX_OVF_INT 0x820
# define BYT_TX_OVF_INT_MASK BIT(1)
struct lpss8250 ;
struct lpss8250_board {
unsigned long freq ;
unsigned int base_baud ;
int ( * setup ) ( struct lpss8250 * , struct uart_port * p ) ;
2016-08-17 19:20:30 +03:00
void ( * exit ) ( struct lpss8250 * ) ;
2016-08-17 19:20:27 +03:00
} ;
struct lpss8250 {
2019-08-06 12:43:18 +03:00
struct dw8250_port_data data ;
2016-08-17 19:20:27 +03:00
struct lpss8250_board * board ;
/* DMA parameters */
2016-08-17 19:20:30 +03:00
struct dw_dma_chip dma_chip ;
2016-08-17 19:20:27 +03:00
struct dw_dma_slave dma_param ;
u8 dma_maxburst ;
} ;
2019-08-06 12:43:18 +03:00
static inline struct lpss8250 * to_lpss8250 ( struct dw8250_port_data * data )
{
return container_of ( data , struct lpss8250 , data ) ;
}
2016-08-17 19:20:27 +03:00
static void byt_set_termios ( struct uart_port * p , struct ktermios * termios ,
struct ktermios * old )
{
unsigned int baud = tty_termios_baud_rate ( termios ) ;
2019-08-06 12:43:18 +03:00
struct lpss8250 * lpss = to_lpss8250 ( p - > private_data ) ;
2016-08-17 19:20:27 +03:00
unsigned long fref = lpss - > board - > freq , fuart = baud * 16 ;
unsigned long w = BIT ( 15 ) - 1 ;
unsigned long m , n ;
u32 reg ;
/* Gracefully handle the B0 case: fall back to B9600 */
fuart = fuart ? fuart : 9600 * 16 ;
/* Get Fuart closer to Fref */
fuart * = rounddown_pow_of_two ( fref / fuart ) ;
/*
* For baud rates 0.5 M , 1 M , 1.5 M , 2 M , 2.5 M , 3 M , 3.5 M and 4 M the
* dividers must be adjusted .
*
* uartclk = ( m / n ) * 100 MHz , where m < = n
*/
rational_best_approximation ( fuart , fref , w , w , & m , & n ) ;
p - > uartclk = fuart ;
/* Reset the clock */
reg = ( m < < BYT_PRV_CLK_M_VAL_SHIFT ) | ( n < < BYT_PRV_CLK_N_VAL_SHIFT ) ;
writel ( reg , p - > membase + BYT_PRV_CLK ) ;
reg | = BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE ;
writel ( reg , p - > membase + BYT_PRV_CLK ) ;
p - > status & = ~ UPSTAT_AUTOCTS ;
if ( termios - > c_cflag & CRTSCTS )
p - > status | = UPSTAT_AUTOCTS ;
serial8250_do_set_termios ( p , termios , old ) ;
}
static unsigned int byt_get_mctrl ( struct uart_port * port )
{
unsigned int ret = serial8250_do_get_mctrl ( port ) ;
/* Force DCD and DSR signals to permanently be reported as active */
ret | = TIOCM_CAR | TIOCM_DSR ;
return ret ;
}
static int byt_serial_setup ( struct lpss8250 * lpss , struct uart_port * port )
{
struct dw_dma_slave * param = & lpss - > dma_param ;
struct pci_dev * pdev = to_pci_dev ( port - > dev ) ;
unsigned int dma_devfn = PCI_DEVFN ( PCI_SLOT ( pdev - > devfn ) , 0 ) ;
struct pci_dev * dma_dev = pci_get_slot ( pdev - > bus , dma_devfn ) ;
switch ( pdev - > device ) {
case PCI_DEVICE_ID_INTEL_BYT_UART1 :
case PCI_DEVICE_ID_INTEL_BSW_UART1 :
case PCI_DEVICE_ID_INTEL_BDW_UART1 :
param - > src_id = 3 ;
param - > dst_id = 2 ;
break ;
case PCI_DEVICE_ID_INTEL_BYT_UART2 :
case PCI_DEVICE_ID_INTEL_BSW_UART2 :
case PCI_DEVICE_ID_INTEL_BDW_UART2 :
param - > src_id = 5 ;
param - > dst_id = 4 ;
break ;
default :
return - EINVAL ;
}
param - > dma_dev = & dma_dev - > dev ;
param - > m_master = 0 ;
param - > p_master = 1 ;
lpss - > dma_maxburst = 16 ;
port - > set_termios = byt_set_termios ;
port - > get_mctrl = byt_get_mctrl ;
/* Disable TX counter interrupts */
writel ( BYT_TX_OVF_INT_MASK , port - > membase + BYT_TX_OVF_INT ) ;
return 0 ;
}
2020-03-05 15:08:22 +02:00
static int ehl_serial_setup ( struct lpss8250 * lpss , struct uart_port * port )
{
return 0 ;
}
2016-08-17 19:20:30 +03:00
# ifdef CONFIG_SERIAL_8250_DMA
static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
. nr_channels = 2 ,
. chan_allocation_order = CHAN_ALLOCATION_ASCENDING ,
. chan_priority = CHAN_PRIORITY_ASCENDING ,
. block_size = 4095 ,
. nr_masters = 1 ,
. data_width = { 4 } ,
2016-11-25 17:59:07 +03:00
. multi_block = { 0 } ,
2016-08-17 19:20:30 +03:00
} ;
static void qrk_serial_setup_dma ( struct lpss8250 * lpss , struct uart_port * port )
{
2019-08-06 12:43:18 +03:00
struct uart_8250_dma * dma = & lpss - > data . dma ;
2016-08-17 19:20:30 +03:00
struct dw_dma_chip * chip = & lpss - > dma_chip ;
struct dw_dma_slave * param = & lpss - > dma_param ;
struct pci_dev * pdev = to_pci_dev ( port - > dev ) ;
int ret ;
2019-07-19 12:48:45 -05:00
chip - > pdata = & qrk_serial_dma_pdata ;
2016-08-17 19:20:30 +03:00
chip - > dev = & pdev - > dev ;
2019-08-06 12:43:20 +03:00
chip - > id = pdev - > devfn ;
2016-10-21 19:19:15 +03:00
chip - > irq = pci_irq_vector ( pdev , 0 ) ;
2016-08-17 19:20:30 +03:00
chip - > regs = pci_ioremap_bar ( pdev , 1 ) ;
2019-07-19 12:48:45 -05:00
if ( ! chip - > regs )
return ;
2016-08-17 19:20:30 +03:00
/* Falling back to PIO mode if DMA probing fails */
ret = dw_dma_probe ( chip ) ;
if ( ret )
return ;
2016-10-10 11:27:19 +03:00
pci_try_set_mwi ( pdev ) ;
2016-10-10 11:27:18 +03:00
2016-08-17 19:20:30 +03:00
/* Special DMA address for UART */
dma - > rx_dma_addr = 0xfffff000 ;
dma - > tx_dma_addr = 0xfffff000 ;
param - > dma_dev = & pdev - > dev ;
param - > src_id = 0 ;
param - > dst_id = 1 ;
param - > hs_polarity = true ;
lpss - > dma_maxburst = 8 ;
}
static void qrk_serial_exit_dma ( struct lpss8250 * lpss )
{
2019-07-19 12:48:45 -05:00
struct dw_dma_chip * chip = & lpss - > dma_chip ;
2016-08-17 19:20:30 +03:00
struct dw_dma_slave * param = & lpss - > dma_param ;
if ( ! param - > dma_dev )
return ;
2019-07-19 12:48:45 -05:00
dw_dma_remove ( chip ) ;
pci_iounmap ( to_pci_dev ( chip - > dev ) , chip - > regs ) ;
2016-08-17 19:20:30 +03:00
}
# else /* CONFIG_SERIAL_8250_DMA */
static void qrk_serial_setup_dma ( struct lpss8250 * lpss , struct uart_port * port ) { }
static void qrk_serial_exit_dma ( struct lpss8250 * lpss ) { }
# endif /* !CONFIG_SERIAL_8250_DMA */
2016-08-17 19:20:29 +03:00
static int qrk_serial_setup ( struct lpss8250 * lpss , struct uart_port * port )
{
2016-08-17 19:20:30 +03:00
qrk_serial_setup_dma ( lpss , port ) ;
2016-08-17 19:20:29 +03:00
return 0 ;
}
2016-08-17 19:20:30 +03:00
static void qrk_serial_exit ( struct lpss8250 * lpss )
{
qrk_serial_exit_dma ( lpss ) ;
}
2016-08-17 19:20:27 +03:00
static bool lpss8250_dma_filter ( struct dma_chan * chan , void * param )
{
struct dw_dma_slave * dws = param ;
if ( dws - > dma_dev ! = chan - > device - > dev )
return false ;
chan - > private = dws ;
return true ;
}
static int lpss8250_dma_setup ( struct lpss8250 * lpss , struct uart_8250_port * port )
{
2019-08-06 12:43:18 +03:00
struct uart_8250_dma * dma = & lpss - > data . dma ;
2016-08-17 19:20:27 +03:00
struct dw_dma_slave * rx_param , * tx_param ;
struct device * dev = port - > port . dev ;
2016-08-17 19:20:28 +03:00
if ( ! lpss - > dma_param . dma_dev )
return 0 ;
2016-08-17 19:20:27 +03:00
rx_param = devm_kzalloc ( dev , sizeof ( * rx_param ) , GFP_KERNEL ) ;
if ( ! rx_param )
return - ENOMEM ;
tx_param = devm_kzalloc ( dev , sizeof ( * tx_param ) , GFP_KERNEL ) ;
if ( ! tx_param )
return - ENOMEM ;
* rx_param = lpss - > dma_param ;
dma - > rxconf . src_maxburst = lpss - > dma_maxburst ;
* tx_param = lpss - > dma_param ;
dma - > txconf . dst_maxburst = lpss - > dma_maxburst ;
dma - > fn = lpss8250_dma_filter ;
dma - > rx_param = rx_param ;
dma - > tx_param = tx_param ;
port - > dma = dma ;
return 0 ;
}
static int lpss8250_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
{
struct uart_8250_port uart ;
struct lpss8250 * lpss ;
int ret ;
ret = pcim_enable_device ( pdev ) ;
if ( ret )
return ret ;
2019-10-01 14:58:25 +03:00
pci_set_master ( pdev ) ;
2016-08-17 19:20:27 +03:00
lpss = devm_kzalloc ( & pdev - > dev , sizeof ( * lpss ) , GFP_KERNEL ) ;
if ( ! lpss )
return - ENOMEM ;
2019-10-01 14:58:25 +03:00
ret = pci_alloc_irq_vectors ( pdev , 1 , 1 , PCI_IRQ_ALL_TYPES ) ;
if ( ret < 0 )
return ret ;
2016-08-17 19:20:27 +03:00
lpss - > board = ( struct lpss8250_board * ) id - > driver_data ;
memset ( & uart , 0 , sizeof ( struct uart_8250_port ) ) ;
uart . port . dev = & pdev - > dev ;
2019-10-01 14:58:25 +03:00
uart . port . irq = pci_irq_vector ( pdev , 0 ) ;
2019-08-06 12:43:18 +03:00
uart . port . private_data = & lpss - > data ;
2016-08-17 19:20:27 +03:00
uart . port . type = PORT_16550A ;
uart . port . iotype = UPIO_MEM ;
uart . port . regshift = 2 ;
uart . port . uartclk = lpss - > board - > base_baud * 16 ;
uart . port . flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE ;
uart . capabilities = UART_CAP_FIFO | UART_CAP_AFE ;
uart . port . mapbase = pci_resource_start ( pdev , 0 ) ;
uart . port . membase = pcim_iomap ( pdev , 0 , 0 ) ;
if ( ! uart . port . membase )
return - ENOMEM ;
ret = lpss - > board - > setup ( lpss , & uart . port ) ;
if ( ret )
return ret ;
2019-08-06 12:43:19 +03:00
dw8250_setup_port ( & uart . port ) ;
2016-08-17 19:20:27 +03:00
ret = lpss8250_dma_setup ( lpss , & uart ) ;
if ( ret )
2016-08-17 19:20:30 +03:00
goto err_exit ;
2016-08-17 19:20:27 +03:00
ret = serial8250_register_8250_port ( & uart ) ;
if ( ret < 0 )
2016-08-17 19:20:30 +03:00
goto err_exit ;
2016-08-17 19:20:27 +03:00
2019-08-06 12:43:18 +03:00
lpss - > data . line = ret ;
2016-08-17 19:20:27 +03:00
pci_set_drvdata ( pdev , lpss ) ;
return 0 ;
2016-08-17 19:20:30 +03:00
err_exit :
if ( lpss - > board - > exit )
lpss - > board - > exit ( lpss ) ;
2019-10-01 14:58:25 +03:00
pci_free_irq_vectors ( pdev ) ;
2016-08-17 19:20:30 +03:00
return ret ;
2016-08-17 19:20:27 +03:00
}
static void lpss8250_remove ( struct pci_dev * pdev )
{
struct lpss8250 * lpss = pci_get_drvdata ( pdev ) ;
2019-08-06 12:43:18 +03:00
serial8250_unregister_port ( lpss - > data . line ) ;
2017-01-05 23:46:20 +02:00
2016-08-17 19:20:30 +03:00
if ( lpss - > board - > exit )
lpss - > board - > exit ( lpss ) ;
2019-10-01 14:58:25 +03:00
pci_free_irq_vectors ( pdev ) ;
2016-08-17 19:20:27 +03:00
}
static const struct lpss8250_board byt_board = {
. freq = 100000000 ,
. base_baud = 2764800 ,
. setup = byt_serial_setup ,
} ;
2019-08-06 12:43:22 +03:00
static const struct lpss8250_board ehl_board = {
. freq = 200000000 ,
. base_baud = 12500000 ,
2020-03-05 15:08:22 +02:00
. setup = ehl_serial_setup ,
2019-08-06 12:43:22 +03:00
} ;
2016-08-17 19:20:28 +03:00
static const struct lpss8250_board qrk_board = {
. freq = 44236800 ,
. base_baud = 2764800 ,
2016-08-17 19:20:29 +03:00
. setup = qrk_serial_setup ,
2016-08-17 19:20:30 +03:00
. exit = qrk_serial_exit ,
2016-08-17 19:20:28 +03:00
} ;
2016-08-17 19:20:27 +03:00
static const struct pci_device_id pci_ids [ ] = {
2019-08-06 12:43:21 +03:00
{ PCI_DEVICE_DATA ( INTEL , QRK_UARTx , & qrk_board ) } ,
2019-08-06 12:43:22 +03:00
{ PCI_DEVICE_DATA ( INTEL , EHL_UART0 , & ehl_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , EHL_UART1 , & ehl_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , EHL_UART2 , & ehl_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , EHL_UART3 , & ehl_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , EHL_UART4 , & ehl_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , EHL_UART5 , & ehl_board ) } ,
2019-08-06 12:43:21 +03:00
{ PCI_DEVICE_DATA ( INTEL , BYT_UART1 , & byt_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , BYT_UART2 , & byt_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , BSW_UART1 , & byt_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , BSW_UART2 , & byt_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , BDW_UART1 , & byt_board ) } ,
{ PCI_DEVICE_DATA ( INTEL , BDW_UART2 , & byt_board ) } ,
{ }
2016-08-17 19:20:27 +03:00
} ;
MODULE_DEVICE_TABLE ( pci , pci_ids ) ;
static struct pci_driver lpss8250_pci_driver = {
. name = " 8250_lpss " ,
. id_table = pci_ids ,
. probe = lpss8250_probe ,
. remove = lpss8250_remove ,
} ;
module_pci_driver ( lpss8250_pci_driver ) ;
MODULE_AUTHOR ( " Intel Corporation " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Intel LPSS UART driver " ) ;