mirror of
https://github.com/torvalds/linux.git
synced 2024-12-15 23:51:46 +00:00
serial: 8250_dw: switch to use 8250_dwlib library
Since we have a common library module for Synopsys DesignWare UART, let us use it. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20190806094322.64987-4-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
136e0ab99b
commit
4d5675c3b1
@ -27,66 +27,36 @@
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "8250.h"
|
||||
#include "8250_dwlib.h"
|
||||
|
||||
/* Offsets for the DesignWare specific registers */
|
||||
#define DW_UART_USR 0x1f /* UART Status Register */
|
||||
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
|
||||
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
|
||||
#define DW_UART_UCV 0xf8 /* UART Component Version */
|
||||
|
||||
/* Component Parameter Register bits */
|
||||
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
|
||||
#define DW_UART_CPR_AFCE_MODE (1 << 4)
|
||||
#define DW_UART_CPR_THRE_MODE (1 << 5)
|
||||
#define DW_UART_CPR_SIR_MODE (1 << 6)
|
||||
#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
|
||||
#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
|
||||
#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
|
||||
#define DW_UART_CPR_FIFO_STAT (1 << 10)
|
||||
#define DW_UART_CPR_SHADOW (1 << 11)
|
||||
#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
|
||||
#define DW_UART_CPR_DMA_EXTRA (1 << 13)
|
||||
#define DW_UART_CPR_FIFO_MODE (0xff << 16)
|
||||
/* Helper for fifo size calculation */
|
||||
#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
|
||||
|
||||
/* DesignWare specific register fields */
|
||||
#define DW_UART_MCR_SIRE BIT(6)
|
||||
|
||||
struct dw8250_data {
|
||||
struct dw8250_port_data data;
|
||||
|
||||
u8 usr_reg;
|
||||
u8 dlf_size;
|
||||
int line;
|
||||
int msr_mask_on;
|
||||
int msr_mask_off;
|
||||
struct clk *clk;
|
||||
struct clk *pclk;
|
||||
struct reset_control *rst;
|
||||
struct uart_8250_dma dma;
|
||||
|
||||
unsigned int skip_autocfg:1;
|
||||
unsigned int uart_16550_compatible:1;
|
||||
};
|
||||
|
||||
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
|
||||
static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
|
||||
{
|
||||
if (p->iotype == UPIO_MEM32BE)
|
||||
return ioread32be(p->membase + offset);
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg)
|
||||
{
|
||||
if (p->iotype == UPIO_MEM32BE)
|
||||
iowrite32be(reg, p->membase + offset);
|
||||
else
|
||||
writel(reg, p->membase + offset);
|
||||
return container_of(data, struct dw8250_data, data);
|
||||
}
|
||||
|
||||
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
/* Override any modem control signals if needed */
|
||||
if (offset == UART_MSR) {
|
||||
@ -160,7 +130,7 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
|
||||
|
||||
static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
/* Allow the TX to drain before we reconfigure */
|
||||
if (offset == UART_LCR)
|
||||
@ -175,7 +145,7 @@ static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
|
||||
@ -202,7 +172,7 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
|
||||
|
||||
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
value &= 0xff;
|
||||
__raw_writeq(value, p->membase + (offset << p->regshift));
|
||||
@ -216,7 +186,7 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
|
||||
|
||||
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
writel(value, p->membase + (offset << p->regshift));
|
||||
|
||||
@ -233,7 +203,7 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
|
||||
static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
iowrite32be(value, p->membase + (offset << p->regshift));
|
||||
|
||||
@ -252,7 +222,7 @@ static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
|
||||
static int dw8250_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
unsigned int iir = p->serial_in(p, UART_IIR);
|
||||
unsigned int status;
|
||||
unsigned long flags;
|
||||
@ -306,7 +276,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
struct dw8250_data *d = p->private_data;
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
long rate;
|
||||
int ret;
|
||||
|
||||
@ -368,37 +338,6 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
||||
return param == chan->device->dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* divisor = div(I) + div(F)
|
||||
* "I" means integer, "F" means fractional
|
||||
* quot = div(I) = clk / (16 * baud)
|
||||
* frac = div(F) * 2^dlf_size
|
||||
*
|
||||
* let rem = clk % (16 * baud)
|
||||
* we have: div(F) * (16 * baud) = rem
|
||||
* so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud)
|
||||
*/
|
||||
static unsigned int dw8250_get_divisor(struct uart_port *p,
|
||||
unsigned int baud,
|
||||
unsigned int *frac)
|
||||
{
|
||||
unsigned int quot, rem, base_baud = baud * 16;
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
quot = p->uartclk / base_baud;
|
||||
rem = p->uartclk % base_baud;
|
||||
*frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud);
|
||||
|
||||
return quot;
|
||||
}
|
||||
|
||||
static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
|
||||
unsigned int quot, unsigned int quot_frac)
|
||||
{
|
||||
dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
|
||||
serial8250_do_set_divisor(p, baud, quot, quot_frac);
|
||||
}
|
||||
|
||||
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||
{
|
||||
if (p->dev->of_node) {
|
||||
@ -437,59 +376,12 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||
/* Platforms with iDMA 64-bit */
|
||||
if (platform_get_resource_byname(to_platform_device(p->dev),
|
||||
IORESOURCE_MEM, "lpss_priv")) {
|
||||
data->dma.rx_param = p->dev->parent;
|
||||
data->dma.tx_param = p->dev->parent;
|
||||
data->dma.fn = dw8250_idma_filter;
|
||||
data->data.dma.rx_param = p->dev->parent;
|
||||
data->data.dma.tx_param = p->dev->parent;
|
||||
data->data.dma.fn = dw8250_idma_filter;
|
||||
}
|
||||
}
|
||||
|
||||
static void dw8250_setup_port(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* If the Component Version Register returns zero, we know that
|
||||
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
||||
*/
|
||||
reg = dw8250_readl_ext(p, DW_UART_UCV);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
|
||||
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
||||
|
||||
dw8250_writel_ext(p, DW_UART_DLF, ~0U);
|
||||
reg = dw8250_readl_ext(p, DW_UART_DLF);
|
||||
dw8250_writel_ext(p, DW_UART_DLF, 0);
|
||||
|
||||
if (reg) {
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
d->dlf_size = fls(reg);
|
||||
p->get_divisor = dw8250_get_divisor;
|
||||
p->set_divisor = dw8250_set_divisor;
|
||||
}
|
||||
|
||||
reg = dw8250_readl_ext(p, DW_UART_CPR);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
/* Select the type based on fifo */
|
||||
if (reg & DW_UART_CPR_FIFO_MODE) {
|
||||
p->type = PORT_16550A;
|
||||
p->flags |= UPF_FIXED_TYPE;
|
||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||
up->capabilities = UART_CAP_FIFO;
|
||||
}
|
||||
|
||||
if (reg & DW_UART_CPR_AFCE_MODE)
|
||||
up->capabilities |= UART_CAP_AFE;
|
||||
|
||||
if (reg & DW_UART_CPR_SIR_MODE)
|
||||
up->capabilities |= UART_CAP_IRDA;
|
||||
}
|
||||
|
||||
static int dw8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {}, *up = &uart;
|
||||
@ -534,9 +426,9 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->dma.fn = dw8250_fallback_dma_filter;
|
||||
data->data.dma.fn = dw8250_fallback_dma_filter;
|
||||
data->usr_reg = DW_UART_USR;
|
||||
p->private_data = data;
|
||||
p->private_data = &data->data;
|
||||
|
||||
data->uart_16550_compatible = device_property_read_bool(dev,
|
||||
"snps,uart-16550-compatible");
|
||||
@ -632,14 +524,14 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||
|
||||
/* If we have a valid fifosize, try hooking up DMA */
|
||||
if (p->fifosize) {
|
||||
data->dma.rxconf.src_maxburst = p->fifosize / 4;
|
||||
data->dma.txconf.dst_maxburst = p->fifosize / 4;
|
||||
up->dma = &data->dma;
|
||||
data->data.dma.rxconf.src_maxburst = p->fifosize / 4;
|
||||
data->data.dma.txconf.dst_maxburst = p->fifosize / 4;
|
||||
up->dma = &data->data.dma;
|
||||
}
|
||||
|
||||
data->line = serial8250_register_8250_port(up);
|
||||
if (data->line < 0) {
|
||||
err = data->line;
|
||||
data->data.line = serial8250_register_8250_port(up);
|
||||
if (data->data.line < 0) {
|
||||
err = data->data.line;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
@ -671,7 +563,7 @@ static int dw8250_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
serial8250_unregister_port(data->data.line);
|
||||
|
||||
reset_control_assert(data->rst);
|
||||
|
||||
@ -692,7 +584,7 @@ static int dw8250_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_suspend_port(data->line);
|
||||
serial8250_suspend_port(data->data.line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -701,7 +593,7 @@ static int dw8250_resume(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_resume_port(data->line);
|
||||
serial8250_resume_port(data->data.line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -357,6 +357,7 @@ config SERIAL_8250_FSL
|
||||
config SERIAL_8250_DW
|
||||
tristate "Support for Synopsys DesignWare 8250 quirks"
|
||||
depends on SERIAL_8250
|
||||
select SERIAL_8250_DWLIB
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present in the Synopsys DesignWare APB UART.
|
||||
|
Loading…
Reference in New Issue
Block a user