TTY/Serial patches for 4.9-rc1

Here is the big TTY and Serial patch set for 4.9-rc1.
 
 It also includes some drivers/dma/ changes, as those were needed by some
 serial drivers, and they were all acked by the DMA maintainer.  Also in
 here is the long-suffering ACPI SPCR patchset, which was passed around
 from maintainer to maintainer like a hot-potato.  Seems I was the
 sucker^Wlucky one.  All of those patches have been acked by the various
 subsystem maintainers as well.
 
 All of this has been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iFYEABECABYFAlfyNjEPHGdyZWdAa3JvYWguY29tAAoJEDFH1A3bLfspwIcAn2uN
 qCD8xQJ0Cs61hD1nUzhNygG8AJ94I4zz/fPGpyh/CtJfLQwtUdLhNA==
 =Rken
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty and serial updates from Greg KH:
 "Here is the big tty and serial patch set for 4.9-rc1.

  It also includes some drivers/dma/ changes, as those were needed by
  some serial drivers, and they were all acked by the DMA maintainer.

  Also in here is the long-suffering ACPI SPCR patchset, which was
  passed around from maintainer to maintainer like a hot-potato. Seems I
  was the sucker^Wlucky one. All of those patches have been acked by the
  various subsystem maintainers as well.

  All of this has been in linux-next with no reported issues"

* tag 'tty-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (111 commits)
  Revert "serial: pl011: add console matching function"
  MAINTAINERS: update entry for atmel_serial driver
  serial: pl011: add console matching function
  ARM64: ACPI: enable ACPI_SPCR_TABLE
  ACPI: parse SPCR and enable matching console
  of/serial: move earlycon early_param handling to serial
  Revert "drivers/tty: Explicitly pass current to show_stack"
  tty: amba-pl011: Don't complain on -EPROBE_DEFER when no irq
  nios2: dts: 10m50: Add tx-threshold parameter
  serial: 8250: Set Altera 16550 TX FIFO Threshold
  serial: 8250: of: Load TX FIFO Threshold from DT
  Documentation: dt: serial: Add TX FIFO threshold parameter
  drivers/tty: Explicitly pass current to show_stack
  serial: imx: Fix DCD reading
  serial: stm32: mark symbols static where possible
  serial: xuartps: Add some register initialisation to cdns_early_console_setup()
  serial: xuartps: Removed unwanted checks while reading the error conditions
  serial: xuartps: Rewrite the interrupt handling logic
  serial: stm32: use mapbase instead of membase for DMA
  tty/serial: atmel: fix fractional baud rate computation
  ...
This commit is contained in:
Linus Torvalds 2016-10-03 20:11:49 -07:00
Родитель 9929780e86 08bf215900
Коммит e6dce825fb
69 изменённых файлов: 2624 добавлений и 1283 удалений

Просмотреть файл

@ -42,6 +42,8 @@ Optional properties:
- auto-flow-control: one way to enable automatic flow control support. The - auto-flow-control: one way to enable automatic flow control support. The
driver is allowed to detect support for the capability even without this driver is allowed to detect support for the capability even without this
property. property.
- tx-threshold: Specify the TX FIFO low water indication for parts with
programmable TX FIFO thresholds.
Note: Note:
* fsl,ns16550: * fsl,ns16550:

Просмотреть файл

@ -0,0 +1,46 @@
* STMicroelectronics STM32 USART
Required properties:
- compatible: Can be either "st,stm32-usart", "st,stm32-uart",
"st,stm32f7-usart" or "st,stm32f7-uart" depending on whether
the device supports synchronous mode and is compatible with
stm32(f4) or stm32f7.
- reg: The address and length of the peripheral registers space
- interrupts: The interrupt line of the USART instance
- clocks: The input clock of the USART instance
Optional properties:
- pinctrl: The reference on the pins configuration
- st,hw-flow-ctrl: bool flag to enable hardware flow control.
- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt
- dma-names: "rx" and/or "tx"
Examples:
usart4: serial@40004c00 {
compatible = "st,stm32-uart";
reg = <0x40004c00 0x400>;
interrupts = <52>;
clocks = <&clk_pclk1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart4>;
};
usart2: serial@40004400 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40004400 0x400>;
interrupts = <38>;
clocks = <&clk_pclk1>;
st,hw-flow-ctrl;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>;
};
usart1: serial@40011000 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40011000 0x400>;
interrupts = <37>;
clocks = <&rcc 0 164>;
dmas = <&dma2 2 4 0x414 0x0>,
<&dma2 7 4 0x414 0x0>;
dma-names = "rx", "tx";
};

Просмотреть файл

@ -1054,11 +1054,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
determined by the stdout-path property in device determined by the stdout-path property in device
tree's chosen node. tree's chosen node.
cdns,<addr> cdns,<addr>[,options]
Start an early, polled-mode console on a cadence serial Start an early, polled-mode console on a Cadence
port at the specified address. The cadence serial port (xuartps) serial port at the specified address. Only
must already be setup and configured. Options are not supported option is baud rate. If baud rate is not
yet supported. specified, the serial port must already be setup and
configured.
uart[8250],io,<addr>[,options] uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options] uart[8250],mmio,<addr>[,options]

Просмотреть файл

@ -2121,11 +2121,6 @@ M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained S: Maintained
F: drivers/mmc/host/atmel-mci.c F: drivers/mmc/host/atmel-mci.c
ATMEL AT91 / AT32 SERIAL DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported
F: drivers/tty/serial/atmel_serial.c
ATMEL AT91 SAMA5D2-Compatible Shutdown Controller ATMEL AT91 SAMA5D2-Compatible Shutdown Controller
M: Nicolas Ferre <nicolas.ferre@atmel.com> M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported S: Supported
@ -7774,6 +7769,12 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git
S: Supported S: Supported
F: arch/microblaze/ F: arch/microblaze/
MICROCHIP / ATMEL AT91 / AT32 SERIAL DRIVER
M: Richard Genoud <richard.genoud@gmail.com>
S: Maintained
F: drivers/tty/serial/atmel_serial.c
F: include/linux/atmel_serial.h
MICROSOFT SURFACE PRO 3 BUTTON DRIVER MICROSOFT SURFACE PRO 3 BUTTON DRIVER
M: Chen Yu <yu.c.chen@intel.com> M: Chen Yu <yu.c.chen@intel.com>
L: platform-driver-x86@vger.kernel.org L: platform-driver-x86@vger.kernel.org

Просмотреть файл

@ -4,6 +4,7 @@ config ARM64
select ACPI_GENERIC_GSI if ACPI select ACPI_GENERIC_GSI if ACPI
select ACPI_REDUCED_HARDWARE_ONLY if ACPI select ACPI_REDUCED_HARDWARE_ONLY if ACPI
select ACPI_MCFG if ACPI select ACPI_MCFG if ACPI
select ACPI_SPCR_TABLE if ACPI
select ARCH_CLOCKSOURCE_DATA select ARCH_CLOCKSOURCE_DATA
select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_DEVMEM_IS_ALLOWED
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI

Просмотреть файл

@ -24,6 +24,7 @@
#include <linux/memblock.h> #include <linux/memblock.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/serial_core.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/cpu_ops.h> #include <asm/cpu_ops.h>
@ -206,7 +207,7 @@ void __init acpi_boot_table_init(void)
if (param_acpi_off || if (param_acpi_off ||
(!param_acpi_on && !param_acpi_force && (!param_acpi_on && !param_acpi_force &&
of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) of_scan_flat_dt(dt_scan_depth1_nodes, NULL)))
return; goto done;
/* /*
* ACPI is disabled at this point. Enable it in order to parse * ACPI is disabled at this point. Enable it in order to parse
@ -226,6 +227,14 @@ void __init acpi_boot_table_init(void)
if (!param_acpi_force) if (!param_acpi_force)
disable_acpi(); disable_acpi();
} }
done:
if (acpi_disabled) {
if (earlycon_init_is_deferred)
early_init_dt_scan_chosen_stdout();
} else {
parse_spcr(earlycon_init_is_deferred);
}
} }
#ifdef CONFIG_ACPI_APEI #ifdef CONFIG_ACPI_APEI

Просмотреть файл

@ -83,6 +83,7 @@
fifo-size = <32>; fifo-size = <32>;
reg-io-width = <4>; reg-io-width = <4>;
reg-shift = <2>; reg-shift = <2>;
tx-threshold = <16>;
}; };
sysid: sysid@18001528 { sysid: sysid@18001528 {

Просмотреть файл

@ -77,6 +77,9 @@ config ACPI_DEBUGGER_USER
endif endif
config ACPI_SPCR_TABLE
bool
config ACPI_SLEEP config ACPI_SLEEP
bool bool
depends on SUSPEND || HIBERNATION depends on SUSPEND || HIBERNATION

Просмотреть файл

@ -82,6 +82,7 @@ obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o
obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o
obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o
# processor has its own "processor." module_param namespace # processor has its own "processor." module_param namespace

111
drivers/acpi/spcr.c Normal file
Просмотреть файл

@ -0,0 +1,111 @@
/*
* Copyright (c) 2012, Intel Corporation
* Copyright (c) 2015, Red Hat, Inc.
* Copyright (c) 2015, 2016 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#define pr_fmt(fmt) "ACPI: SPCR: " fmt
#include <linux/acpi.h>
#include <linux/console.h>
#include <linux/kernel.h>
#include <linux/serial_core.h>
/**
* parse_spcr() - parse ACPI SPCR table and add preferred console
*
* @earlycon: set up earlycon for the console specified by the table
*
* For the architectures with support for ACPI, CONFIG_ACPI_SPCR_TABLE may be
* defined to parse ACPI SPCR table. As a result of the parsing preferred
* console is registered and if @earlycon is true, earlycon is set up.
*
* When CONFIG_ACPI_SPCR_TABLE is defined, this function should be called
* from arch inintialization code as soon as the DT/ACPI decision is made.
*
*/
int __init parse_spcr(bool earlycon)
{
static char opts[64];
struct acpi_table_spcr *table;
acpi_size table_size;
acpi_status status;
char *uart;
char *iotype;
int baud_rate;
int err;
if (acpi_disabled)
return -ENODEV;
status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0,
(struct acpi_table_header **)&table,
&table_size);
if (ACPI_FAILURE(status))
return -ENOENT;
if (table->header.revision < 2) {
err = -ENOENT;
pr_err("wrong table version\n");
goto done;
}
iotype = table->serial_port.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ?
"mmio" : "io";
switch (table->interface_type) {
case ACPI_DBG2_ARM_SBSA_32BIT:
iotype = "mmio32";
/* fall through */
case ACPI_DBG2_ARM_PL011:
case ACPI_DBG2_ARM_SBSA_GENERIC:
case ACPI_DBG2_BCM2835:
uart = "pl011";
break;
case ACPI_DBG2_16550_COMPATIBLE:
case ACPI_DBG2_16550_SUBSET:
uart = "uart";
break;
default:
err = -ENOENT;
goto done;
}
switch (table->baud_rate) {
case 3:
baud_rate = 9600;
break;
case 4:
baud_rate = 19200;
break;
case 6:
baud_rate = 57600;
break;
case 7:
baud_rate = 115200;
break;
default:
err = -ENOENT;
goto done;
}
snprintf(opts, sizeof(opts), "%s,%s,0x%llx,%d", uart, iotype,
table->serial_port.address, baud_rate);
pr_info("console: %s\n", opts);
if (earlycon)
setup_earlycon(opts);
err = add_preferred_console(uart, 0, opts + strlen(uart) + 1);
done:
early_acpi_os_unmap_memory((void __iomem *)table, table_size);
return err;
}

Просмотреть файл

@ -46,9 +46,9 @@
u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \ u8 _dmsize = _is_slave ? _sconfig->dst_maxburst : \
DW_DMA_MSIZE_16; \ DW_DMA_MSIZE_16; \
u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ? \ u8 _dms = (_dwc->direction == DMA_MEM_TO_DEV) ? \
_dwc->p_master : _dwc->m_master; \ _dwc->dws.p_master : _dwc->dws.m_master; \
u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ? \ u8 _sms = (_dwc->direction == DMA_DEV_TO_MEM) ? \
_dwc->p_master : _dwc->m_master; \ _dwc->dws.p_master : _dwc->dws.m_master; \
\ \
(DWC_CTLL_DST_MSIZE(_dmsize) \ (DWC_CTLL_DST_MSIZE(_dmsize) \
| DWC_CTLL_SRC_MSIZE(_smsize) \ | DWC_CTLL_SRC_MSIZE(_smsize) \
@ -143,12 +143,16 @@ static void dwc_initialize(struct dw_dma_chan *dwc)
struct dw_dma *dw = to_dw_dma(dwc->chan.device); struct dw_dma *dw = to_dw_dma(dwc->chan.device);
u32 cfghi = DWC_CFGH_FIFO_MODE; u32 cfghi = DWC_CFGH_FIFO_MODE;
u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority); u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
bool hs_polarity = dwc->dws.hs_polarity;
if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags)) if (test_bit(DW_DMA_IS_INITIALIZED, &dwc->flags))
return; return;
cfghi |= DWC_CFGH_DST_PER(dwc->dst_id); cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
cfghi |= DWC_CFGH_SRC_PER(dwc->src_id); cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
/* Set polarity of handshake interface */
cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_LO, cfglo);
channel_writel(dwc, CFG_HI, cfghi); channel_writel(dwc, CFG_HI, cfghi);
@ -209,7 +213,7 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
{ {
struct dw_dma *dw = to_dw_dma(dwc->chan.device); struct dw_dma *dw = to_dw_dma(dwc->chan.device);
u8 lms = DWC_LLP_LMS(dwc->m_master); u8 lms = DWC_LLP_LMS(dwc->dws.m_master);
unsigned long was_soft_llp; unsigned long was_soft_llp;
/* ASSERT: channel is idle */ /* ASSERT: channel is idle */
@ -662,7 +666,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
struct dw_desc *prev; struct dw_desc *prev;
size_t xfer_count; size_t xfer_count;
size_t offset; size_t offset;
u8 m_master = dwc->m_master; u8 m_master = dwc->dws.m_master;
unsigned int src_width; unsigned int src_width;
unsigned int dst_width; unsigned int dst_width;
unsigned int data_width = dw->pdata->data_width[m_master]; unsigned int data_width = dw->pdata->data_width[m_master];
@ -740,7 +744,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct dw_desc *prev; struct dw_desc *prev;
struct dw_desc *first; struct dw_desc *first;
u32 ctllo; u32 ctllo;
u8 m_master = dwc->m_master; u8 m_master = dwc->dws.m_master;
u8 lms = DWC_LLP_LMS(m_master); u8 lms = DWC_LLP_LMS(m_master);
dma_addr_t reg; dma_addr_t reg;
unsigned int reg_width; unsigned int reg_width;
@ -895,12 +899,7 @@ bool dw_dma_filter(struct dma_chan *chan, void *param)
return false; return false;
/* We have to copy data since dws can be temporary storage */ /* We have to copy data since dws can be temporary storage */
memcpy(&dwc->dws, dws, sizeof(struct dw_dma_slave));
dwc->src_id = dws->src_id;
dwc->dst_id = dws->dst_id;
dwc->m_master = dws->m_master;
dwc->p_master = dws->p_master;
return true; return true;
} }
@ -1167,11 +1166,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&dwc->lock, flags); spin_lock_irqsave(&dwc->lock, flags);
/* Clear custom channel configuration */ /* Clear custom channel configuration */
dwc->src_id = 0; memset(&dwc->dws, 0, sizeof(struct dw_dma_slave));
dwc->dst_id = 0;
dwc->m_master = 0;
dwc->p_master = 0;
clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags); clear_bit(DW_DMA_IS_INITIALIZED, &dwc->flags);
@ -1264,7 +1259,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
struct dw_cyclic_desc *retval = NULL; struct dw_cyclic_desc *retval = NULL;
struct dw_desc *desc; struct dw_desc *desc;
struct dw_desc *last = NULL; struct dw_desc *last = NULL;
u8 lms = DWC_LLP_LMS(dwc->m_master); u8 lms = DWC_LLP_LMS(dwc->dws.m_master);
unsigned long was_cyclic; unsigned long was_cyclic;
unsigned int reg_width; unsigned int reg_width;
unsigned int periods; unsigned int periods;
@ -1576,11 +1571,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
(dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0; (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0;
} else { } else {
dwc->block_size = pdata->block_size; dwc->block_size = pdata->block_size;
dwc->nollp = pdata->is_nollp;
/* Check if channel supports multi block transfer */
channel_writel(dwc, LLP, DWC_LLP_LOC(0xffffffff));
dwc->nollp = DWC_LLP_LOC(channel_readl(dwc, LLP)) == 0;
channel_writel(dwc, LLP, 0);
} }
} }

Просмотреть файл

@ -245,10 +245,7 @@ struct dw_dma_chan {
bool nollp; bool nollp;
/* custom slave configuration */ /* custom slave configuration */
u8 src_id; struct dw_dma_slave dws;
u8 dst_id;
u8 m_master;
u8 p_master;
/* configuration passed via .device_config */ /* configuration passed via .device_config */
struct dma_slave_config dma_sconfig; struct dma_slave_config dma_sconfig;

Просмотреть файл

@ -200,10 +200,9 @@ EXPORT_SYMBOL_GPL(hsu_dma_get_status);
* is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0. * is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0.
* *
* Return: * Return:
* IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise. * 0 for invalid channel number, 1 otherwise.
*/ */
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status)
u32 status)
{ {
struct hsu_dma_chan *hsuc; struct hsu_dma_chan *hsuc;
struct hsu_dma_desc *desc; struct hsu_dma_desc *desc;
@ -211,7 +210,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
/* Sanity check */ /* Sanity check */
if (nr >= chip->hsu->nr_channels) if (nr >= chip->hsu->nr_channels)
return IRQ_NONE; return 0;
hsuc = &chip->hsu->chan[nr]; hsuc = &chip->hsu->chan[nr];
@ -230,7 +229,7 @@ irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
} }
spin_unlock_irqrestore(&hsuc->vchan.lock, flags); spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
return IRQ_HANDLED; return 1;
} }
EXPORT_SYMBOL_GPL(hsu_dma_do_irq); EXPORT_SYMBOL_GPL(hsu_dma_do_irq);

Просмотреть файл

@ -29,7 +29,7 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
u32 dmaisr; u32 dmaisr;
u32 status; u32 status;
unsigned short i; unsigned short i;
irqreturn_t ret = IRQ_NONE; int ret = 0;
int err; int err;
dmaisr = readl(chip->regs + HSU_PCI_DMAISR); dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
@ -37,14 +37,14 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
if (dmaisr & 0x1) { if (dmaisr & 0x1) {
err = hsu_dma_get_status(chip, i, &status); err = hsu_dma_get_status(chip, i, &status);
if (err > 0) if (err > 0)
ret |= IRQ_HANDLED; ret |= 1;
else if (err == 0) else if (err == 0)
ret |= hsu_dma_do_irq(chip, i, status); ret |= hsu_dma_do_irq(chip, i, status);
} }
dmaisr >>= 1; dmaisr >>= 1;
} }
return ret; return IRQ_RETVAL(ret);
} }
static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)

Просмотреть файл

@ -648,15 +648,11 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
writel_relaxed(val, sdma->regs + chnenbl); writel_relaxed(val, sdma->regs + chnenbl);
} }
static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
{
if (sdmac->desc.callback)
sdmac->desc.callback(sdmac->desc.callback_param);
}
static void sdma_update_channel_loop(struct sdma_channel *sdmac) static void sdma_update_channel_loop(struct sdma_channel *sdmac)
{ {
struct sdma_buffer_descriptor *bd; struct sdma_buffer_descriptor *bd;
int error = 0;
enum dma_status old_status = sdmac->status;
/* /*
* loop mode. Iterate over descriptors, re-setup them and * loop mode. Iterate over descriptors, re-setup them and
@ -668,17 +664,42 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
if (bd->mode.status & BD_DONE) if (bd->mode.status & BD_DONE)
break; break;
if (bd->mode.status & BD_RROR) if (bd->mode.status & BD_RROR) {
bd->mode.status &= ~BD_RROR;
sdmac->status = DMA_ERROR; sdmac->status = DMA_ERROR;
error = -EIO;
}
/*
* We use bd->mode.count to calculate the residue, since contains
* the number of bytes present in the current buffer descriptor.
*/
sdmac->chn_real_count = bd->mode.count;
bd->mode.status |= BD_DONE; bd->mode.status |= BD_DONE;
bd->mode.count = sdmac->period_len;
/*
* The callback is called from the interrupt context in order
* to reduce latency and to avoid the risk of altering the
* SDMA transaction status by the time the client tasklet is
* executed.
*/
if (sdmac->desc.callback)
sdmac->desc.callback(sdmac->desc.callback_param);
sdmac->buf_tail++; sdmac->buf_tail++;
sdmac->buf_tail %= sdmac->num_bd; sdmac->buf_tail %= sdmac->num_bd;
if (error)
sdmac->status = old_status;
} }
} }
static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac) static void mxc_sdma_handle_channel_normal(unsigned long data)
{ {
struct sdma_channel *sdmac = (struct sdma_channel *) data;
struct sdma_buffer_descriptor *bd; struct sdma_buffer_descriptor *bd;
int i, error = 0; int i, error = 0;
@ -705,16 +726,6 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
sdmac->desc.callback(sdmac->desc.callback_param); sdmac->desc.callback(sdmac->desc.callback_param);
} }
static void sdma_tasklet(unsigned long data)
{
struct sdma_channel *sdmac = (struct sdma_channel *) data;
if (sdmac->flags & IMX_DMA_SG_LOOP)
sdma_handle_channel_loop(sdmac);
else
mxc_sdma_handle_channel_normal(sdmac);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id) static irqreturn_t sdma_int_handler(int irq, void *dev_id)
{ {
struct sdma_engine *sdma = dev_id; struct sdma_engine *sdma = dev_id;
@ -731,7 +742,7 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
if (sdmac->flags & IMX_DMA_SG_LOOP) if (sdmac->flags & IMX_DMA_SG_LOOP)
sdma_update_channel_loop(sdmac); sdma_update_channel_loop(sdmac);
else
tasklet_schedule(&sdmac->tasklet); tasklet_schedule(&sdmac->tasklet);
__clear_bit(channel, &stat); __clear_bit(channel, &stat);
@ -1353,7 +1364,8 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
u32 residue; u32 residue;
if (sdmac->flags & IMX_DMA_SG_LOOP) if (sdmac->flags & IMX_DMA_SG_LOOP)
residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; residue = (sdmac->num_bd - sdmac->buf_tail) *
sdmac->period_len - sdmac->chn_real_count;
else else
residue = sdmac->chn_count - sdmac->chn_real_count; residue = sdmac->chn_count - sdmac->chn_real_count;
@ -1732,7 +1744,7 @@ static int sdma_probe(struct platform_device *pdev)
dma_cookie_init(&sdmac->chan); dma_cookie_init(&sdmac->chan);
sdmac->channel = i; sdmac->channel = i;
tasklet_init(&sdmac->tasklet, sdma_tasklet, tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
(unsigned long) sdmac); (unsigned long) sdmac);
/* /*
* Add the channel to the DMAC list. Do not add channel 0 though * Add the channel to the DMAC list. Do not add channel 0 though

Просмотреть файл

@ -924,7 +924,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
#ifdef CONFIG_SERIAL_EARLYCON #ifdef CONFIG_SERIAL_EARLYCON
static int __init early_init_dt_scan_chosen_serial(void) int __init early_init_dt_scan_chosen_stdout(void)
{ {
int offset; int offset;
const char *p, *q, *options = NULL; const char *p, *q, *options = NULL;
@ -968,15 +968,6 @@ static int __init early_init_dt_scan_chosen_serial(void)
} }
return -ENODEV; return -ENODEV;
} }
static int __init setup_of_earlycon(char *buf)
{
if (buf)
return 0;
return early_init_dt_scan_chosen_serial();
}
early_param("earlycon", setup_of_earlycon);
#endif #endif
/** /**

Просмотреть файл

@ -800,7 +800,7 @@ out_free_file:
return retval; return retval;
} }
static struct file_operations ptmx_fops; static struct file_operations ptmx_fops __ro_after_init;
static void __init unix98_pty_init(void) static void __init unix98_pty_init(void)
{ {

Просмотреть файл

@ -31,6 +31,11 @@ struct uart_8250_dma {
struct dma_chan *rxchan; struct dma_chan *rxchan;
struct dma_chan *txchan; struct dma_chan *txchan;
/* Device address base for DMA operations */
phys_addr_t rx_dma_addr;
phys_addr_t tx_dma_addr;
/* DMA address of the buffer in memory */
dma_addr_t rx_addr; dma_addr_t rx_addr;
dma_addr_t tx_addr; dma_addr_t tx_addr;

Просмотреть файл

@ -639,7 +639,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
{ {
char match[] = "uart"; /* 8250-specific earlycon name */ char match[] = "uart"; /* 8250-specific earlycon name */
unsigned char iotype; unsigned char iotype;
unsigned long addr; resource_size_t addr;
int i; int i;
if (strncmp(name, match, 4) != 0) if (strncmp(name, match, 4) != 0)

Просмотреть файл

@ -142,7 +142,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
if (dma->rx_running) { if (dma->rx_running) {
dmaengine_pause(dma->rxchan); dmaengine_pause(dma->rxchan);
__dma_rx_complete(p); __dma_rx_complete(p);
dmaengine_terminate_all(dma->rxchan); dmaengine_terminate_async(dma->rxchan);
} }
} }
EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush); EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
@ -150,6 +150,10 @@ EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
int serial8250_request_dma(struct uart_8250_port *p) int serial8250_request_dma(struct uart_8250_port *p)
{ {
struct uart_8250_dma *dma = p->dma; struct uart_8250_dma *dma = p->dma;
phys_addr_t rx_dma_addr = dma->rx_dma_addr ?
dma->rx_dma_addr : p->port.mapbase;
phys_addr_t tx_dma_addr = dma->tx_dma_addr ?
dma->tx_dma_addr : p->port.mapbase;
dma_cap_mask_t mask; dma_cap_mask_t mask;
struct dma_slave_caps caps; struct dma_slave_caps caps;
int ret; int ret;
@ -157,11 +161,11 @@ int serial8250_request_dma(struct uart_8250_port *p)
/* Default slave configuration parameters */ /* Default slave configuration parameters */
dma->rxconf.direction = DMA_DEV_TO_MEM; dma->rxconf.direction = DMA_DEV_TO_MEM;
dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->rxconf.src_addr = p->port.mapbase + UART_RX; dma->rxconf.src_addr = rx_dma_addr + UART_RX;
dma->txconf.direction = DMA_MEM_TO_DEV; dma->txconf.direction = DMA_MEM_TO_DEV;
dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma->txconf.dst_addr = p->port.mapbase + UART_TX; dma->txconf.dst_addr = tx_dma_addr + UART_TX;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
@ -247,14 +251,14 @@ void serial8250_release_dma(struct uart_8250_port *p)
return; return;
/* Release RX resources */ /* Release RX resources */
dmaengine_terminate_all(dma->rxchan); dmaengine_terminate_sync(dma->rxchan);
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf, dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
dma->rx_addr); dma->rx_addr);
dma_release_channel(dma->rxchan); dma_release_channel(dma->rxchan);
dma->rxchan = NULL; dma->rxchan = NULL;
/* Release TX resources */ /* Release TX resources */
dmaengine_terminate_all(dma->txchan); dmaengine_terminate_sync(dma->txchan);
dma_unmap_single(dma->txchan->device->dev, dma->tx_addr, dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
UART_XMIT_SIZE, DMA_TO_DEVICE); UART_XMIT_SIZE, DMA_TO_DEVICE);
dma_release_channel(dma->txchan); dma_release_channel(dma->txchan);

Просмотреть файл

@ -365,18 +365,19 @@ static int dw8250_probe(struct platform_device *pdev)
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0); int irq = platform_get_irq(pdev, 0);
struct uart_port *p = &uart.port; struct uart_port *p = &uart.port;
struct device *dev = &pdev->dev;
struct dw8250_data *data; struct dw8250_data *data;
int err; int err;
u32 val; u32 val;
if (!regs) { if (!regs) {
dev_err(&pdev->dev, "no registers defined\n"); dev_err(dev, "no registers defined\n");
return -EINVAL; return -EINVAL;
} }
if (irq < 0) { if (irq < 0) {
if (irq != -EPROBE_DEFER) if (irq != -EPROBE_DEFER)
dev_err(&pdev->dev, "cannot get irq\n"); dev_err(dev, "cannot get irq\n");
return irq; return irq;
} }
@ -387,16 +388,16 @@ static int dw8250_probe(struct platform_device *pdev)
p->pm = dw8250_do_pm; p->pm = dw8250_do_pm;
p->type = PORT_8250; p->type = PORT_8250;
p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
p->dev = &pdev->dev; p->dev = dev;
p->iotype = UPIO_MEM; p->iotype = UPIO_MEM;
p->serial_in = dw8250_serial_in; p->serial_in = dw8250_serial_in;
p->serial_out = dw8250_serial_out; p->serial_out = dw8250_serial_out;
p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!p->membase) if (!p->membase)
return -ENOMEM; return -ENOMEM;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
@ -404,57 +405,57 @@ static int dw8250_probe(struct platform_device *pdev)
data->usr_reg = DW_UART_USR; data->usr_reg = DW_UART_USR;
p->private_data = data; p->private_data = data;
data->uart_16550_compatible = device_property_read_bool(p->dev, data->uart_16550_compatible = device_property_read_bool(dev,
"snps,uart-16550-compatible"); "snps,uart-16550-compatible");
err = device_property_read_u32(p->dev, "reg-shift", &val); err = device_property_read_u32(dev, "reg-shift", &val);
if (!err) if (!err)
p->regshift = val; p->regshift = val;
err = device_property_read_u32(p->dev, "reg-io-width", &val); err = device_property_read_u32(dev, "reg-io-width", &val);
if (!err && val == 4) { if (!err && val == 4) {
p->iotype = UPIO_MEM32; p->iotype = UPIO_MEM32;
p->serial_in = dw8250_serial_in32; p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32; p->serial_out = dw8250_serial_out32;
} }
if (device_property_read_bool(p->dev, "dcd-override")) { if (device_property_read_bool(dev, "dcd-override")) {
/* Always report DCD as active */ /* Always report DCD as active */
data->msr_mask_on |= UART_MSR_DCD; data->msr_mask_on |= UART_MSR_DCD;
data->msr_mask_off |= UART_MSR_DDCD; data->msr_mask_off |= UART_MSR_DDCD;
} }
if (device_property_read_bool(p->dev, "dsr-override")) { if (device_property_read_bool(dev, "dsr-override")) {
/* Always report DSR as active */ /* Always report DSR as active */
data->msr_mask_on |= UART_MSR_DSR; data->msr_mask_on |= UART_MSR_DSR;
data->msr_mask_off |= UART_MSR_DDSR; data->msr_mask_off |= UART_MSR_DDSR;
} }
if (device_property_read_bool(p->dev, "cts-override")) { if (device_property_read_bool(dev, "cts-override")) {
/* Always report CTS as active */ /* Always report CTS as active */
data->msr_mask_on |= UART_MSR_CTS; data->msr_mask_on |= UART_MSR_CTS;
data->msr_mask_off |= UART_MSR_DCTS; data->msr_mask_off |= UART_MSR_DCTS;
} }
if (device_property_read_bool(p->dev, "ri-override")) { if (device_property_read_bool(dev, "ri-override")) {
/* Always report Ring indicator as inactive */ /* Always report Ring indicator as inactive */
data->msr_mask_off |= UART_MSR_RI; data->msr_mask_off |= UART_MSR_RI;
data->msr_mask_off |= UART_MSR_TERI; data->msr_mask_off |= UART_MSR_TERI;
} }
/* Always ask for fixed clock rate from a property. */ /* Always ask for fixed clock rate from a property. */
device_property_read_u32(p->dev, "clock-frequency", &p->uartclk); device_property_read_u32(dev, "clock-frequency", &p->uartclk);
/* If there is separate baudclk, get the rate from it. */ /* If there is separate baudclk, get the rate from it. */
data->clk = devm_clk_get(&pdev->dev, "baudclk"); data->clk = devm_clk_get(dev, "baudclk");
if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER) if (IS_ERR(data->clk) && PTR_ERR(data->clk) != -EPROBE_DEFER)
data->clk = devm_clk_get(&pdev->dev, NULL); data->clk = devm_clk_get(dev, NULL);
if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER)
return -EPROBE_DEFER; return -EPROBE_DEFER;
if (!IS_ERR_OR_NULL(data->clk)) { if (!IS_ERR_OR_NULL(data->clk)) {
err = clk_prepare_enable(data->clk); err = clk_prepare_enable(data->clk);
if (err) if (err)
dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", dev_warn(dev, "could not enable optional baudclk: %d\n",
err); err);
else else
p->uartclk = clk_get_rate(data->clk); p->uartclk = clk_get_rate(data->clk);
@ -462,24 +463,24 @@ static int dw8250_probe(struct platform_device *pdev)
/* If no clock rate is defined, fail. */ /* If no clock rate is defined, fail. */
if (!p->uartclk) { if (!p->uartclk) {
dev_err(&pdev->dev, "clock rate not defined\n"); dev_err(dev, "clock rate not defined\n");
return -EINVAL; return -EINVAL;
} }
data->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); data->pclk = devm_clk_get(dev, "apb_pclk");
if (IS_ERR(data->clk) && PTR_ERR(data->clk) == -EPROBE_DEFER) { if (IS_ERR(data->pclk) && PTR_ERR(data->pclk) == -EPROBE_DEFER) {
err = -EPROBE_DEFER; err = -EPROBE_DEFER;
goto err_clk; goto err_clk;
} }
if (!IS_ERR(data->pclk)) { if (!IS_ERR(data->pclk)) {
err = clk_prepare_enable(data->pclk); err = clk_prepare_enable(data->pclk);
if (err) { if (err) {
dev_err(&pdev->dev, "could not enable apb_pclk\n"); dev_err(dev, "could not enable apb_pclk\n");
goto err_clk; goto err_clk;
} }
} }
data->rst = devm_reset_control_get_optional(&pdev->dev, NULL); data->rst = devm_reset_control_get_optional(dev, NULL);
if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) { if (IS_ERR(data->rst) && PTR_ERR(data->rst) == -EPROBE_DEFER) {
err = -EPROBE_DEFER; err = -EPROBE_DEFER;
goto err_pclk; goto err_pclk;
@ -511,8 +512,8 @@ static int dw8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(dev);
return 0; return 0;
@ -624,6 +625,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "APMC0D08", 0}, { "APMC0D08", 0},
{ "AMD0020", 0 }, { "AMD0020", 0 },
{ "AMDI0020", 0 }, { "AMDI0020", 0 },
{ "HISI0031", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);

Просмотреть файл

@ -0,0 +1,378 @@
/*
* 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>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/rational.h>
#include <linux/dmaengine.h>
#include <linux/dma/dw.h>
#include "8250.h"
#define PCI_DEVICE_ID_INTEL_QRK_UARTx 0x0936
#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
#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);
void (*exit)(struct lpss8250 *);
};
struct lpss8250 {
int line;
struct lpss8250_board *board;
/* DMA parameters */
struct uart_8250_dma dma;
struct dw_dma_chip dma_chip;
struct dw_dma_slave dma_param;
u8 dma_maxburst;
};
static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
struct lpss8250 *lpss = p->private_data;
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.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M 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 uart_8250_port *up = up_to_u8250p(port);
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;
/* TODO: Detect FIFO size automaticaly for DesignWare 8250 */
port->fifosize = 64;
up->tx_loadsz = 64;
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;
}
#ifdef CONFIG_SERIAL_8250_DMA
static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
.nr_channels = 2,
.is_private = true,
.is_nollp = true,
.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
.chan_priority = CHAN_PRIORITY_ASCENDING,
.block_size = 4095,
.nr_masters = 1,
.data_width = {4},
};
static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port)
{
struct uart_8250_dma *dma = &lpss->dma;
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;
chip->dev = &pdev->dev;
chip->irq = pdev->irq;
chip->regs = pci_ioremap_bar(pdev, 1);
chip->pdata = &qrk_serial_dma_pdata;
/* Falling back to PIO mode if DMA probing fails */
ret = dw_dma_probe(chip);
if (ret)
return;
/* 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)
{
struct dw_dma_slave *param = &lpss->dma_param;
if (!param->dma_dev)
return;
dw_dma_remove(&lpss->dma_chip);
}
#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 */
static int qrk_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
{
struct pci_dev *pdev = to_pci_dev(port->dev);
int ret;
ret = pci_alloc_irq_vectors(pdev, 1, 1, 0);
if (ret < 0)
return ret;
port->irq = pci_irq_vector(pdev, 0);
qrk_serial_setup_dma(lpss, port);
return 0;
}
static void qrk_serial_exit(struct lpss8250 *lpss)
{
qrk_serial_exit_dma(lpss);
}
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)
{
struct uart_8250_dma *dma = &lpss->dma;
struct dw_dma_slave *rx_param, *tx_param;
struct device *dev = port->port.dev;
if (!lpss->dma_param.dma_dev)
return 0;
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;
pci_set_master(pdev);
lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL);
if (!lpss)
return -ENOMEM;
lpss->board = (struct lpss8250_board *)id->driver_data;
memset(&uart, 0, sizeof(struct uart_8250_port));
uart.port.dev = &pdev->dev;
uart.port.irq = pdev->irq;
uart.port.private_data = lpss;
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;
ret = lpss8250_dma_setup(lpss, &uart);
if (ret)
goto err_exit;
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
goto err_exit;
lpss->line = ret;
pci_set_drvdata(pdev, lpss);
return 0;
err_exit:
if (lpss->board->exit)
lpss->board->exit(lpss);
return ret;
}
static void lpss8250_remove(struct pci_dev *pdev)
{
struct lpss8250 *lpss = pci_get_drvdata(pdev);
if (lpss->board->exit)
lpss->board->exit(lpss);
serial8250_unregister_port(lpss->line);
}
static const struct lpss8250_board byt_board = {
.freq = 100000000,
.base_baud = 2764800,
.setup = byt_serial_setup,
};
static const struct lpss8250_board qrk_board = {
.freq = 44236800,
.base_baud = 2764800,
.setup = qrk_serial_setup,
.exit = qrk_serial_exit,
};
#define LPSS_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
static const struct pci_device_id pci_ids[] = {
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_QRK_UARTx, qrk_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART1, byt_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BYT_UART2, byt_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART1, byt_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BSW_UART2, byt_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART1, byt_board),
LPSS_DEVICE(PCI_DEVICE_ID_INTEL_BDW_UART2, byt_board),
{ },
};
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");

Просмотреть файл

@ -99,27 +99,27 @@ static int dnv_handle_irq(struct uart_port *p)
struct uart_8250_port *up = up_to_u8250p(p); struct uart_8250_port *up = up_to_u8250p(p);
unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
u32 status; u32 status;
int ret = IRQ_NONE; int ret = 0;
int err; int err;
if (fisr & BIT(2)) { if (fisr & BIT(2)) {
err = hsu_dma_get_status(&mid->dma_chip, 1, &status); err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
if (err > 0) { if (err > 0) {
serial8250_rx_dma_flush(up); serial8250_rx_dma_flush(up);
ret |= IRQ_HANDLED; ret |= 1;
} else if (err == 0) } else if (err == 0)
ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status); ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
} }
if (fisr & BIT(1)) { if (fisr & BIT(1)) {
err = hsu_dma_get_status(&mid->dma_chip, 0, &status); err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
if (err > 0) if (err > 0)
ret |= IRQ_HANDLED; ret |= 1;
else if (err == 0) else if (err == 0)
ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status); ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
} }
if (fisr & BIT(0)) if (fisr & BIT(0))
ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
return ret; return IRQ_RETVAL(ret);
} }
#define DNV_DMA_CHAN_OFFSET 0x80 #define DNV_DMA_CHAN_OFFSET 0x80

Просмотреть файл

@ -62,7 +62,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
baud = uart_get_baud_rate(port, termios, old, baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 0xffff, port->uartclk / 16 / 0xffff,
port->uartclk / 16); port->uartclk);
if (baud <= 115200) { if (baud <= 115200) {
serial_port_out(port, UART_MTK_HIGHS, 0x0); serial_port_out(port, UART_MTK_HIGHS, 0x0);
@ -76,10 +76,6 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
quot = DIV_ROUND_UP(port->uartclk, 4 * baud); quot = DIV_ROUND_UP(port->uartclk, 4 * baud);
} else { } else {
serial_port_out(port, UART_MTK_HIGHS, 0x3); serial_port_out(port, UART_MTK_HIGHS, 0x3);
/* Set to highest baudrate supported */
if (baud >= 1152000)
baud = 921600;
quot = DIV_ROUND_UP(port->uartclk, 256 * baud); quot = DIV_ROUND_UP(port->uartclk, 256 * baud);
} }

Просмотреть файл

@ -195,6 +195,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
switch (port_type) { switch (port_type) {
case PORT_8250 ... PORT_MAX_8250: case PORT_8250 ... PORT_MAX_8250:
{ {
u32 tx_threshold;
struct uart_8250_port port8250; struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250)); memset(&port8250, 0, sizeof(port8250));
port8250.port = port; port8250.port = port;
@ -202,6 +203,12 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (port.fifosize) if (port.fifosize)
port8250.capabilities = UART_CAP_FIFO; port8250.capabilities = UART_CAP_FIFO;
/* Check for TX FIFO threshold & set tx_loadsz */
if ((of_property_read_u32(ofdev->dev.of_node, "tx-threshold",
&tx_threshold) == 0) &&
(tx_threshold < port.fifosize))
port8250.tx_loadsz = port.fifosize - tx_threshold;
if (of_property_read_bool(ofdev->dev.of_node, if (of_property_read_bool(ofdev->dev.of_node,
"auto-flow-control")) "auto-flow-control"))
port8250.capabilities |= UART_CAP_AFE; port8250.capabilities |= UART_CAP_AFE;

Просмотреть файл

@ -21,14 +21,10 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/8250_pci.h> #include <linux/8250_pci.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/rational.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/io.h> #include <asm/io.h>
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h>
#include "8250.h" #include "8250.h"
/* /*
@ -1349,160 +1345,6 @@ ce4100_serial_setup(struct serial_private *priv,
return ret; return ret;
} }
#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
#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3
#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4
#define BYT_PRV_CLK 0x800
#define BYT_PRV_CLK_EN (1 << 0)
#define BYT_PRV_CLK_M_VAL_SHIFT 1
#define BYT_PRV_CLK_N_VAL_SHIFT 16
#define BYT_PRV_CLK_UPDATE (1 << 31)
#define BYT_TX_OVF_INT 0x820
#define BYT_TX_OVF_INT_MASK (1 << 1)
static void
byt_set_termios(struct uart_port *p, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = tty_termios_baud_rate(termios);
unsigned long fref = 100000000, 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.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M 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 bool byt_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 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 serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
struct pci_dev *pdev = priv->dev;
struct device *dev = port->port.dev;
struct uart_8250_dma *dma;
struct dw_dma_slave *tx_param, *rx_param;
struct pci_dev *dma_dev;
int ret;
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
if (!dma)
return -ENOMEM;
tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
if (!tx_param)
return -ENOMEM;
rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
if (!rx_param)
return -ENOMEM;
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_BYT_UART1:
case PCI_DEVICE_ID_INTEL_BSW_UART1:
case PCI_DEVICE_ID_INTEL_BDW_UART1:
rx_param->src_id = 3;
tx_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:
rx_param->src_id = 5;
tx_param->dst_id = 4;
break;
default:
return -EINVAL;
}
rx_param->m_master = 0;
rx_param->p_master = 1;
dma->rxconf.src_maxburst = 16;
tx_param->m_master = 0;
tx_param->p_master = 1;
dma->txconf.dst_maxburst = 16;
dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
rx_param->dma_dev = &dma_dev->dev;
tx_param->dma_dev = &dma_dev->dev;
dma->fn = byt_dma_filter;
dma->rx_param = rx_param;
dma->tx_param = tx_param;
ret = pci_default_setup(priv, board, port, idx);
port->port.iotype = UPIO_MEM;
port->port.type = PORT_16550A;
port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
port->port.set_termios = byt_set_termios;
port->port.get_mctrl = byt_get_mctrl;
port->port.fifosize = 64;
port->tx_loadsz = 64;
port->dma = dma;
port->capabilities = UART_CAP_FIFO | UART_CAP_AFE;
/* Disable Tx counter interrupts */
writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT);
return ret;
}
static int static int
pci_omegapci_setup(struct serial_private *priv, pci_omegapci_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
@ -1741,6 +1583,19 @@ static int pci_eg20t_init(struct pci_dev *dev)
#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
#define UART_EXAR_MPIOINT_7_0 0x8f /* MPIOINT[7:0] */
#define UART_EXAR_MPIOLVL_7_0 0x90 /* MPIOLVL[7:0] */
#define UART_EXAR_MPIO3T_7_0 0x91 /* MPIO3T[7:0] */
#define UART_EXAR_MPIOINV_7_0 0x92 /* MPIOINV[7:0] */
#define UART_EXAR_MPIOSEL_7_0 0x93 /* MPIOSEL[7:0] */
#define UART_EXAR_MPIOOD_7_0 0x94 /* MPIOOD[7:0] */
#define UART_EXAR_MPIOINT_15_8 0x95 /* MPIOINT[15:8] */
#define UART_EXAR_MPIOLVL_15_8 0x96 /* MPIOLVL[15:8] */
#define UART_EXAR_MPIO3T_15_8 0x97 /* MPIO3T[15:8] */
#define UART_EXAR_MPIOINV_15_8 0x98 /* MPIOINV[15:8] */
#define UART_EXAR_MPIOSEL_15_8 0x99 /* MPIOSEL[15:8] */
#define UART_EXAR_MPIOOD_15_8 0x9a /* MPIOOD[15:8] */
static int static int
pci_xr17c154_setup(struct serial_private *priv, pci_xr17c154_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
@ -1783,18 +1638,18 @@ pci_xr17v35x_setup(struct serial_private *priv,
* Setup Multipurpose Input/Output pins. * Setup Multipurpose Input/Output pins.
*/ */
if (idx == 0) { if (idx == 0) {
writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/ writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/ writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/ writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/ writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/ writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/ writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
} }
writeb(0x00, p + UART_EXAR_8XMODE); writeb(0x00, p + UART_EXAR_8XMODE);
writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
@ -1830,20 +1685,20 @@ pci_fastcom335_setup(struct serial_private *priv,
switch (priv->dev->device) { switch (priv->dev->device) {
case PCI_DEVICE_ID_COMMTECH_4222PCI335: case PCI_DEVICE_ID_COMMTECH_4222PCI335:
case PCI_DEVICE_ID_COMMTECH_4224PCI335: case PCI_DEVICE_ID_COMMTECH_4224PCI335:
writeb(0x78, p + 0x90); /* MPIOLVL[7:0] */ writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
writeb(0x00, p + 0x92); /* MPIOINV[7:0] */ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
writeb(0x00, p + 0x93); /* MPIOSEL[7:0] */ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
break; break;
case PCI_DEVICE_ID_COMMTECH_2324PCI335: case PCI_DEVICE_ID_COMMTECH_2324PCI335:
case PCI_DEVICE_ID_COMMTECH_2328PCI335: case PCI_DEVICE_ID_COMMTECH_2328PCI335:
writeb(0x00, p + 0x90); /* MPIOLVL[7:0] */ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
writeb(0xc0, p + 0x92); /* MPIOINV[7:0] */ writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
writeb(0xc0, p + 0x93); /* MPIOSEL[7:0] */ writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
break; break;
} }
writeb(0x00, p + 0x8f); /* MPIOINT[7:0] */ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
writeb(0x00, p + 0x91); /* MPIO3T[7:0] */ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
writeb(0x00, p + 0x94); /* MPIOOD[7:0] */ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
} }
writeb(0x00, p + UART_EXAR_8XMODE); writeb(0x00, p + UART_EXAR_8XMODE);
writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR); writeb(UART_FCTR_EXAR_TRGD, p + UART_EXAR_FCTR);
@ -1934,7 +1789,6 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022 #define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e #define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
#define PCI_DEVICE_ID_INTEL_QRK_UART 0x0936
#define PCI_VENDOR_ID_SUNIX 0x1fd4 #define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_DEVICE_ID_SUNIX_1999 0x1999 #define PCI_DEVICE_ID_SUNIX_1999 0x1999
@ -2078,48 +1932,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = kt_serial_setup, .setup = kt_serial_setup,
}, },
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BYT_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BYT_UART2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BSW_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BSW_UART2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BDW_UART1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_BDW_UART2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = byt_serial_setup,
},
/* /*
* ITE * ITE
*/ */
@ -2992,8 +2804,6 @@ enum pci_board_num_t {
pbn_ADDIDATA_PCIe_4_3906250, pbn_ADDIDATA_PCIe_4_3906250,
pbn_ADDIDATA_PCIe_8_3906250, pbn_ADDIDATA_PCIe_8_3906250,
pbn_ce4100_1_115200, pbn_ce4100_1_115200,
pbn_byt,
pbn_qrk,
pbn_omegapci, pbn_omegapci,
pbn_NETMOS9900_2s_115200, pbn_NETMOS9900_2s_115200,
pbn_brcm_trumanage, pbn_brcm_trumanage,
@ -3769,18 +3579,6 @@ static struct pciserial_board pci_boards[] = {
.base_baud = 921600, .base_baud = 921600,
.reg_shift = 2, .reg_shift = 2,
}, },
[pbn_byt] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
.reg_shift = 2,
},
[pbn_qrk] = {
.flags = FL_BASE0,
.num_ports = 1,
.base_baud = 2764800,
.reg_shift = 2,
},
[pbn_omegapci] = { [pbn_omegapci] = {
.flags = FL_BASE0, .flags = FL_BASE0,
.num_ports = 8, .num_ports = 8,
@ -3892,6 +3690,15 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(INTEL, 0x081d), }, { PCI_VDEVICE(INTEL, 0x081d), },
{ PCI_VDEVICE(INTEL, 0x1191), }, { PCI_VDEVICE(INTEL, 0x1191), },
{ PCI_VDEVICE(INTEL, 0x19d8), }, { PCI_VDEVICE(INTEL, 0x19d8), },
/* Intel platforms with DesignWare UART */
{ PCI_VDEVICE(INTEL, 0x0936), },
{ PCI_VDEVICE(INTEL, 0x0f0a), },
{ PCI_VDEVICE(INTEL, 0x0f0c), },
{ PCI_VDEVICE(INTEL, 0x228a), },
{ PCI_VDEVICE(INTEL, 0x228c), },
{ PCI_VDEVICE(INTEL, 0x9ce3), },
{ PCI_VDEVICE(INTEL, 0x9ce4), },
}; };
/* /*
@ -5659,40 +5466,7 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_ce4100_1_115200 }, pbn_ce4100_1_115200 },
/* Intel BayTrail */
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART1,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW_UART2,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
/* Intel Broadwell */
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
pbn_byt },
/*
* Intel Quark x1000
*/
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_qrk },
/* /*
* Cronyx Omega PCI * Cronyx Omega PCI
*/ */

Просмотреть файл

@ -178,7 +178,7 @@ static const struct serial8250_config uart_config[] = {
.fifo_size = 16, .fifo_size = 16,
.tx_loadsz = 16, .tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
.flags = UART_CAP_FIFO | UART_CAP_AFE, .flags = UART_CAP_FIFO /* | UART_CAP_AFE */,
}, },
[PORT_U6_16550A] = { [PORT_U6_16550A] = {
.name = "U6_16550A", .name = "U6_16550A",
@ -585,11 +585,11 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
*/ */
int serial8250_em485_init(struct uart_8250_port *p) int serial8250_em485_init(struct uart_8250_port *p)
{ {
if (p->em485 != NULL) if (p->em485)
return 0; return 0;
p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC); p->em485 = kmalloc(sizeof(struct uart_8250_em485), GFP_ATOMIC);
if (p->em485 == NULL) if (!p->em485)
return -ENOMEM; return -ENOMEM;
setup_timer(&p->em485->stop_tx_timer, setup_timer(&p->em485->stop_tx_timer,
@ -619,7 +619,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_init);
*/ */
void serial8250_em485_destroy(struct uart_8250_port *p) void serial8250_em485_destroy(struct uart_8250_port *p)
{ {
if (p->em485 == NULL) if (!p->em485)
return; return;
del_timer(&p->em485->start_tx_timer); del_timer(&p->em485->start_tx_timer);
@ -1402,10 +1402,8 @@ static void serial8250_stop_rx(struct uart_port *port)
static void __do_stop_tx_rs485(struct uart_8250_port *p) static void __do_stop_tx_rs485(struct uart_8250_port *p)
{ {
if (!p->em485)
return;
serial8250_em485_rts_after_send(p); serial8250_em485_rts_after_send(p);
/* /*
* Empty the RX FIFO, we are not interested in anything * Empty the RX FIFO, we are not interested in anything
* received during the half-duplex transmission. * received during the half-duplex transmission.
@ -1414,12 +1412,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_fifos(p); serial8250_clear_fifos(p);
serial8250_rpm_get(p);
p->ier |= UART_IER_RLSI | UART_IER_RDI; p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier); serial_port_out(&p->port, UART_IER, p->ier);
serial8250_rpm_put(p);
} }
} }
@ -1429,6 +1423,7 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg)
struct uart_8250_em485 *em485 = p->em485; struct uart_8250_em485 *em485 = p->em485;
unsigned long flags; unsigned long flags;
serial8250_rpm_get(p);
spin_lock_irqsave(&p->port.lock, flags); spin_lock_irqsave(&p->port.lock, flags);
if (em485 && if (em485 &&
em485->active_timer == &em485->stop_tx_timer) { em485->active_timer == &em485->stop_tx_timer) {
@ -1436,15 +1431,13 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg)
em485->active_timer = NULL; em485->active_timer = NULL;
} }
spin_unlock_irqrestore(&p->port.lock, flags); spin_unlock_irqrestore(&p->port.lock, flags);
serial8250_rpm_put(p);
} }
static void __stop_tx_rs485(struct uart_8250_port *p) static void __stop_tx_rs485(struct uart_8250_port *p)
{ {
struct uart_8250_em485 *em485 = p->em485; struct uart_8250_em485 *em485 = p->em485;
if (!em485)
return;
/* /*
* __do_stop_tx_rs485 is going to set RTS according to config * __do_stop_tx_rs485 is going to set RTS according to config
* AND flush RX FIFO if required. * AND flush RX FIFO if required.
@ -1475,7 +1468,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
unsigned char lsr = serial_in(p, UART_LSR); unsigned char lsr = serial_in(p, UART_LSR);
/* /*
* To provide required timeing and allow FIFO transfer, * To provide required timeing and allow FIFO transfer,
* __stop_tx_rs485 must be called only when both FIFO and * __stop_tx_rs485() must be called only when both FIFO and
* shift register are empty. It is for device driver to enable * shift register are empty. It is for device driver to enable
* interrupt on TEMT. * interrupt on TEMT.
*/ */
@ -1484,9 +1477,10 @@ static inline void __stop_tx(struct uart_8250_port *p)
del_timer(&em485->start_tx_timer); del_timer(&em485->start_tx_timer);
em485->active_timer = NULL; em485->active_timer = NULL;
__stop_tx_rs485(p);
} }
__do_stop_tx(p); __do_stop_tx(p);
__stop_tx_rs485(p);
} }
static void serial8250_stop_tx(struct uart_port *port) static void serial8250_stop_tx(struct uart_port *port)
@ -1876,6 +1870,30 @@ static int exar_handle_irq(struct uart_port *port)
return ret; return ret;
} }
/*
* Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP
* have a programmable TX threshold that triggers the THRE interrupt in
* the IIR register. In this case, the THRE interrupt indicates the FIFO
* has space available. Load it up with tx_loadsz bytes.
*/
static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
{
unsigned long flags;
unsigned int iir = serial_port_in(port, UART_IIR);
/* TX Threshold IRQ triggered so load up FIFO */
if ((iir & UART_IIR_ID) == UART_IIR_THRI) {
struct uart_8250_port *up = up_to_u8250p(port);
spin_lock_irqsave(&port->lock, flags);
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
}
iir = serial_port_in(port, UART_IIR);
return serial8250_handle_irq(port, iir);
}
static unsigned int serial8250_tx_empty(struct uart_port *port) static unsigned int serial8250_tx_empty(struct uart_port *port)
{ {
struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_port *up = up_to_u8250p(port);
@ -1988,6 +2006,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
if (--tmout == 0) if (--tmout == 0)
break; break;
udelay(1); udelay(1);
touch_nmi_watchdog();
} }
/* Wait up to 1s for flow control if necessary */ /* Wait up to 1s for flow control if necessary */
@ -2164,6 +2183,25 @@ int serial8250_do_startup(struct uart_port *port)
serial_port_out(port, UART_LCR, 0); serial_port_out(port, UART_LCR, 0);
} }
/*
* For the Altera 16550 variants, set TX threshold trigger level.
*/
if (((port->type == PORT_ALTR_16550_F32) ||
(port->type == PORT_ALTR_16550_F64) ||
(port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */
if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
pr_err("ttyS%d TX FIFO Threshold errors, skipping\n",
serial_index(port));
} else {
serial_port_out(port, UART_ALTR_AFR,
UART_ALTR_EN_TXFIFO_LW);
serial_port_out(port, UART_ALTR_TX_LOW,
port->fifosize - up->tx_loadsz);
port->handle_irq = serial8250_tx_threshold_handle_irq;
}
}
if (port->irq) { if (port->irq) {
unsigned char iir1; unsigned char iir1;
/* /*
@ -2499,8 +2537,6 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
struct ktermios *termios, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
{ {
unsigned int tolerance = port->uartclk / 100;
/* /*
* Ask the core to calculate the divisor for us. * Ask the core to calculate the divisor for us.
* Allow 1% tolerance at the upper limit so uart clks marginally * Allow 1% tolerance at the upper limit so uart clks marginally
@ -2509,7 +2545,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
*/ */
return uart_get_baud_rate(port, termios, old, return uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 0xffff, port->uartclk / 16 / 0xffff,
(port->uartclk + tolerance) / 16); port->uartclk);
} }
void void
@ -2546,12 +2582,9 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
/* /*
* MCR-based auto flow control. When AFE is enabled, RTS will be * MCR-based auto flow control. When AFE is enabled, RTS will be
* deasserted when the receive FIFO contains more characters than * deasserted when the receive FIFO contains more characters than
* the trigger, or the MCR RTS bit is cleared. In the case where * the trigger, or the MCR RTS bit is cleared.
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond. IOW, at least 32 bytes of FIFO.
*/ */
if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { if (up->capabilities & UART_CAP_AFE) {
up->mcr &= ~UART_MCR_AFE; up->mcr &= ~UART_MCR_AFE;
if (termios->c_cflag & CRTSCTS) if (termios->c_cflag & CRTSCTS)
up->mcr |= UART_MCR_AFE; up->mcr |= UART_MCR_AFE;

Просмотреть файл

@ -120,7 +120,6 @@ config SERIAL_8250_PCI
tristate "8250/16550 PCI device support" if EXPERT tristate "8250/16550 PCI device support" if EXPERT
depends on SERIAL_8250 && PCI depends on SERIAL_8250 && PCI
default SERIAL_8250 default SERIAL_8250
select RATIONAL
help help
This builds standard PCI serial support. You may be able to This builds standard PCI serial support. You may be able to
disable this feature if you only need legacy serial support. disable this feature if you only need legacy serial support.
@ -402,6 +401,21 @@ config SERIAL_8250_INGENIC
If you have a system using an Ingenic SoC and wish to make use of If you have a system using an Ingenic SoC and wish to make use of
its UARTs, say Y to this option. If unsure, say N. its UARTs, say Y to this option. If unsure, say N.
config SERIAL_8250_LPSS
tristate "Support for serial ports on Intel LPSS platforms" if EXPERT
default SERIAL_8250
depends on SERIAL_8250 && PCI
depends on X86 || COMPILE_TEST
select DW_DMAC_CORE if SERIAL_8250_DMA
select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS)
select RATIONAL
help
Selecting this option will enable handling of the extra features
present on the UART found on various Intel platforms such as:
- Intel Baytrail SoC
- Intel Braswell SoC
- Intel Quark X1000 SoC
config SERIAL_8250_MID config SERIAL_8250_MID
tristate "Support for serial ports on Intel MID platforms" if EXPERT tristate "Support for serial ports on Intel MID platforms" if EXPERT
default SERIAL_8250 default SERIAL_8250

Просмотреть файл

@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o

Просмотреть файл

@ -280,7 +280,7 @@ static int altera_jtaguart_verify_port(struct uart_port *port,
/* /*
* Define the basic serial functions we support. * Define the basic serial functions we support.
*/ */
static struct uart_ops altera_jtaguart_ops = { static const struct uart_ops altera_jtaguart_ops = {
.tx_empty = altera_jtaguart_tx_empty, .tx_empty = altera_jtaguart_tx_empty,
.get_mctrl = altera_jtaguart_get_mctrl, .get_mctrl = altera_jtaguart_get_mctrl,
.set_mctrl = altera_jtaguart_set_mctrl, .set_mctrl = altera_jtaguart_set_mctrl,

Просмотреть файл

@ -404,7 +404,7 @@ static void altera_uart_poll_put_char(struct uart_port *port, unsigned char c)
/* /*
* Define the basic serial functions we support. * Define the basic serial functions we support.
*/ */
static struct uart_ops altera_uart_ops = { static const struct uart_ops altera_uart_ops = {
.tx_empty = altera_uart_tx_empty, .tx_empty = altera_uart_tx_empty,
.get_mctrl = altera_uart_get_mctrl, .get_mctrl = altera_uart_get_mctrl,
.set_mctrl = altera_uart_set_mctrl, .set_mctrl = altera_uart_set_mctrl,

Просмотреть файл

@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = {
struct vendor_data { struct vendor_data {
const u16 *reg_offset; const u16 *reg_offset;
unsigned int ifls; unsigned int ifls;
unsigned int fr_busy;
unsigned int fr_dsr;
unsigned int fr_cts;
unsigned int fr_ri;
bool access_32b; bool access_32b;
bool oversampling; bool oversampling;
bool dma_threshold; bool dma_threshold;
@ -111,6 +115,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
static struct vendor_data vendor_arm = { static struct vendor_data vendor_arm = {
.reg_offset = pl011_std_offsets, .reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
.fr_ri = UART011_FR_RI,
.oversampling = false, .oversampling = false,
.dma_threshold = false, .dma_threshold = false,
.cts_event_workaround = false, .cts_event_workaround = false,
@ -121,6 +129,10 @@ static struct vendor_data vendor_arm = {
static struct vendor_data vendor_sbsa = { static struct vendor_data vendor_sbsa = {
.reg_offset = pl011_std_offsets, .reg_offset = pl011_std_offsets,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
.fr_ri = UART011_FR_RI,
.access_32b = true, .access_32b = true,
.oversampling = false, .oversampling = false,
.dma_threshold = false, .dma_threshold = false,
@ -164,6 +176,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev)
static struct vendor_data vendor_st = { static struct vendor_data vendor_st = {
.reg_offset = pl011_st_offsets, .reg_offset = pl011_st_offsets,
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
.fr_ri = UART011_FR_RI,
.oversampling = true, .oversampling = true,
.dma_threshold = true, .dma_threshold = true,
.cts_event_workaround = true, .cts_event_workaround = true,
@ -188,11 +204,20 @@ static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = {
[REG_DMACR] = ZX_UART011_DMACR, [REG_DMACR] = ZX_UART011_DMACR,
}; };
static struct vendor_data vendor_zte __maybe_unused = { static unsigned int get_fifosize_zte(struct amba_device *dev)
{
return 16;
}
static struct vendor_data vendor_zte = {
.reg_offset = pl011_zte_offsets, .reg_offset = pl011_zte_offsets,
.access_32b = true, .access_32b = true,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.get_fifosize = get_fifosize_arm, .fr_busy = ZX_UART01x_FR_BUSY,
.fr_dsr = ZX_UART01x_FR_DSR,
.fr_cts = ZX_UART01x_FR_CTS,
.fr_ri = ZX_UART011_FR_RI,
.get_fifosize = get_fifosize_zte,
}; };
/* Deals with DMA transactions */ /* Deals with DMA transactions */
@ -1167,7 +1192,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
return; return;
/* Disable RX and TX DMA */ /* Disable RX and TX DMA */
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
cpu_relax(); cpu_relax();
spin_lock_irq(&uap->port.lock); spin_lock_irq(&uap->port.lock);
@ -1416,11 +1441,12 @@ static void pl011_modem_status(struct uart_amba_port *uap)
if (delta & UART01x_FR_DCD) if (delta & UART01x_FR_DCD)
uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD);
if (delta & UART01x_FR_DSR) if (delta & uap->vendor->fr_dsr)
uap->port.icount.dsr++; uap->port.icount.dsr++;
if (delta & UART01x_FR_CTS) if (delta & uap->vendor->fr_cts)
uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); uart_handle_cts_change(&uap->port,
status & uap->vendor->fr_cts);
wake_up_interruptible(&uap->port.state->port.delta_msr_wait); wake_up_interruptible(&uap->port.state->port.delta_msr_wait);
} }
@ -1493,7 +1519,8 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
struct uart_amba_port *uap = struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port); container_of(port, struct uart_amba_port, port);
unsigned int status = pl011_read(uap, REG_FR); unsigned int status = pl011_read(uap, REG_FR);
return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; return status & (uap->vendor->fr_busy | UART01x_FR_TXFF) ?
0 : TIOCSER_TEMT;
} }
static unsigned int pl011_get_mctrl(struct uart_port *port) static unsigned int pl011_get_mctrl(struct uart_port *port)
@ -1508,9 +1535,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
result |= tiocmbit result |= tiocmbit
TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
TIOCMBIT(UART011_FR_RI, TIOCM_RNG); TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
#undef TIOCMBIT #undef TIOCMBIT
return result; return result;
} }
@ -2191,7 +2218,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty * Finally, wait for transmitter to become empty
* and restore the TCR * and restore the TCR
*/ */
while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
cpu_relax(); cpu_relax();
if (!uap->vendor->always_enabled) if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR); pl011_write(old_cr, uap, REG_CR);
@ -2555,6 +2582,7 @@ static int sbsa_uart_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) { if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "cannot obtain irq\n"); dev_err(&pdev->dev, "cannot obtain irq\n");
return ret; return ret;
} }
@ -2622,6 +2650,11 @@ static struct amba_id pl011_ids[] = {
.mask = 0x00ffffff, .mask = 0x00ffffff,
.data = &vendor_st, .data = &vendor_st,
}, },
{
.id = AMBA_LINUX_ID(0x00, 0x1, 0xffe),
.mask = 0x00ffffff,
.data = &vendor_zte,
},
{ 0, 0 }, { 0, 0 },
}; };

Просмотреть файл

@ -464,7 +464,7 @@ static int arc_serial_poll_getchar(struct uart_port *port)
} }
#endif #endif
static struct uart_ops arc_serial_pops = { static const struct uart_ops arc_serial_pops = {
.tx_empty = arc_serial_tx_empty, .tx_empty = arc_serial_tx_empty,
.set_mctrl = arc_serial_set_mctrl, .set_mctrl = arc_serial_set_mctrl,
.get_mctrl = arc_serial_get_mctrl, .get_mctrl = arc_serial_get_mctrl,

Просмотреть файл

@ -166,6 +166,7 @@ struct atmel_uart_port {
u32 rts_low; u32 rts_low;
bool ms_irq_enabled; bool ms_irq_enabled;
u32 rtor; /* address of receiver timeout register if it exists */ u32 rtor; /* address of receiver timeout register if it exists */
bool has_frac_baudrate;
bool has_hw_timer; bool has_hw_timer;
struct timer_list uart_timer; struct timer_list uart_timer;
@ -1634,8 +1635,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
if (np) { if (np) {
/* DMA/PDC usage specification */ /* DMA/PDC usage specification */
if (of_get_property(np, "atmel,use-dma-rx", NULL)) { if (of_property_read_bool(np, "atmel,use-dma-rx")) {
if (of_get_property(np, "dmas", NULL)) { if (of_property_read_bool(np, "dmas")) {
atmel_port->use_dma_rx = true; atmel_port->use_dma_rx = true;
atmel_port->use_pdc_rx = false; atmel_port->use_pdc_rx = false;
} else { } else {
@ -1647,8 +1648,8 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
atmel_port->use_pdc_rx = false; atmel_port->use_pdc_rx = false;
} }
if (of_get_property(np, "atmel,use-dma-tx", NULL)) { if (of_property_read_bool(np, "atmel,use-dma-tx")) {
if (of_get_property(np, "dmas", NULL)) { if (of_property_read_bool(np, "dmas")) {
atmel_port->use_dma_tx = true; atmel_port->use_dma_tx = true;
atmel_port->use_pdc_tx = false; atmel_port->use_pdc_tx = false;
} else { } else {
@ -1745,6 +1746,11 @@ static void atmel_get_ip_name(struct uart_port *port)
dbgu_uart = 0x44424755; /* DBGU */ dbgu_uart = 0x44424755; /* DBGU */
new_uart = 0x55415254; /* UART */ new_uart = 0x55415254; /* UART */
/*
* Only USART devices from at91sam9260 SOC implement fractional
* baudrate.
*/
atmel_port->has_frac_baudrate = false;
atmel_port->has_hw_timer = false; atmel_port->has_hw_timer = false;
if (name == new_uart) { if (name == new_uart) {
@ -1753,6 +1759,7 @@ static void atmel_get_ip_name(struct uart_port *port)
atmel_port->rtor = ATMEL_UA_RTOR; atmel_port->rtor = ATMEL_UA_RTOR;
} else if (name == usart) { } else if (name == usart) {
dev_dbg(port->dev, "Usart\n"); dev_dbg(port->dev, "Usart\n");
atmel_port->has_frac_baudrate = true;
atmel_port->has_hw_timer = true; atmel_port->has_hw_timer = true;
atmel_port->rtor = ATMEL_US_RTOR; atmel_port->rtor = ATMEL_US_RTOR;
} else if (name == dbgu_uart) { } else if (name == dbgu_uart) {
@ -1764,6 +1771,7 @@ static void atmel_get_ip_name(struct uart_port *port)
case 0x302: case 0x302:
case 0x10213: case 0x10213:
dev_dbg(port->dev, "This version is usart\n"); dev_dbg(port->dev, "This version is usart\n");
atmel_port->has_frac_baudrate = true;
atmel_port->has_hw_timer = true; atmel_port->has_hw_timer = true;
atmel_port->rtor = ATMEL_US_RTOR; atmel_port->rtor = ATMEL_US_RTOR;
break; break;
@ -1929,6 +1937,9 @@ static void atmel_shutdown(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/* Disable modem control lines interrupts */
atmel_disable_ms(port);
/* Disable interrupts at device level */ /* Disable interrupts at device level */
atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_uart_writel(port, ATMEL_US_IDR, -1);
@ -1979,8 +1990,6 @@ static void atmel_shutdown(struct uart_port *port)
*/ */
free_irq(port->irq, port); free_irq(port->irq, port);
atmel_port->ms_irq_enabled = false;
atmel_flush_buffer(port); atmel_flush_buffer(port);
} }
@ -2025,8 +2034,9 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned long flags; unsigned long flags;
unsigned int old_mode, mode, imr, quot, baud; unsigned int old_mode, mode, imr, quot, baud, div, cd, fp = 0;
/* save the current mode register */ /* save the current mode register */
mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR);
@ -2036,12 +2046,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
ATMEL_US_PAR | ATMEL_US_USMODE); ATMEL_US_PAR | ATMEL_US_USMODE);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
quot = uart_get_divisor(port, baud);
if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
quot /= 8;
mode |= ATMEL_US_USCLKS_MCK_DIV8;
}
/* byte size */ /* byte size */
switch (termios->c_cflag & CSIZE) { switch (termios->c_cflag & CSIZE) {
@ -2160,7 +2164,31 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
atmel_uart_writel(port, ATMEL_US_CR, rts_state); atmel_uart_writel(port, ATMEL_US_CR, rts_state);
} }
/* set the baud rate */ /*
* Set the baud rate:
* Fractional baudrate allows to setup output frequency more
* accurately. This feature is enabled only when using normal mode.
* baudrate = selected clock / (8 * (2 - OVER) * (CD + FP / 8))
* Currently, OVER is always set to 0 so we get
* baudrate = selected clock / (16 * (CD + FP / 8))
* then
* 8 CD + FP = selected clock / (2 * baudrate)
*/
if (atmel_port->has_frac_baudrate &&
(mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_NORMAL) {
div = DIV_ROUND_CLOSEST(port->uartclk, baud * 2);
cd = div >> 3;
fp = div & ATMEL_US_FP_MASK;
} else {
cd = uart_get_divisor(port, baud);
}
if (cd > 65535) { /* BRGR is 16-bit, so switch to slower clock */
cd /= 8;
mode |= ATMEL_US_USCLKS_MCK_DIV8;
}
quot = cd | fp << ATMEL_US_FP_OFFSET;
atmel_uart_writel(port, ATMEL_US_BRGR, quot); atmel_uart_writel(port, ATMEL_US_BRGR, quot);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
@ -2292,7 +2320,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
} }
#endif #endif
static struct uart_ops atmel_pops = { static const struct uart_ops atmel_pops = {
.tx_empty = atmel_tx_empty, .tx_empty = atmel_tx_empty,
.set_mctrl = atmel_set_mctrl, .set_mctrl = atmel_set_mctrl,
.get_mctrl = atmel_get_mctrl, .get_mctrl = atmel_get_mctrl,

Просмотреть файл

@ -631,7 +631,7 @@ static int bcm_uart_verify_port(struct uart_port *port,
} }
/* serial core callbacks */ /* serial core callbacks */
static struct uart_ops bcm_uart_ops = { static const struct uart_ops bcm_uart_ops = {
.tx_empty = bcm_uart_tx_empty, .tx_empty = bcm_uart_tx_empty,
.get_mctrl = bcm_uart_get_mctrl, .get_mctrl = bcm_uart_get_mctrl,
.set_mctrl = bcm_uart_set_mctrl, .set_mctrl = bcm_uart_set_mctrl,

Просмотреть файл

@ -53,7 +53,8 @@ static void smh_write(struct console *con, const char *s, unsigned n)
uart_console_write(&dev->port, s, n, smh_putc); uart_console_write(&dev->port, s, n, smh_putc);
} }
int __init early_smh_setup(struct earlycon_device *device, const char *opt) static int
__init early_smh_setup(struct earlycon_device *device, const char *opt)
{ {
device->con->write = smh_write; device->con->write = smh_write;
return 0; return 0;

Просмотреть файл

@ -21,6 +21,7 @@
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/acpi.h>
#ifdef CONFIG_FIX_EARLYCON_MEM #ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h> #include <asm/fixmap.h>
@ -38,7 +39,7 @@ static struct earlycon_device early_console_dev = {
.con = &early_con, .con = &early_con,
}; };
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size)
{ {
void __iomem *base; void __iomem *base;
#ifdef CONFIG_FIX_EARLYCON_MEM #ifdef CONFIG_FIX_EARLYCON_MEM
@ -49,8 +50,7 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
base = ioremap(paddr, size); base = ioremap(paddr, size);
#endif #endif
if (!base) if (!base)
pr_err("%s: Couldn't map 0x%llx\n", __func__, pr_err("%s: Couldn't map %pa\n", __func__, &paddr);
(unsigned long long)paddr);
return base; return base;
} }
@ -92,7 +92,7 @@ static int __init parse_options(struct earlycon_device *device, char *options)
{ {
struct uart_port *port = &device->port; struct uart_port *port = &device->port;
int length; int length;
unsigned long addr; resource_size_t addr;
if (uart_parse_earlycon(options, &port->iotype, &addr, &options)) if (uart_parse_earlycon(options, &port->iotype, &addr, &options))
return -EINVAL; return -EINVAL;
@ -199,6 +199,14 @@ int __init setup_earlycon(char *buf)
return -ENOENT; return -ENOENT;
} }
/*
* When CONFIG_ACPI_SPCR_TABLE is defined, "earlycon" without parameters in
* command line does not start DT earlycon immediately, instead it defers
* starting it until DT/ACPI decision is made. At that time if ACPI is enabled
* call parse_spcr(), else call early_init_dt_scan_chosen_stdout()
*/
bool earlycon_init_is_deferred __initdata;
/* early_param wrapper for setup_earlycon() */ /* early_param wrapper for setup_earlycon() */
static int __init param_setup_earlycon(char *buf) static int __init param_setup_earlycon(char *buf)
{ {
@ -208,8 +216,14 @@ static int __init param_setup_earlycon(char *buf)
* Just 'earlycon' is a valid param for devicetree earlycons; * Just 'earlycon' is a valid param for devicetree earlycons;
* don't generate a warning from parse_early_params() in that case * don't generate a warning from parse_early_params() in that case
*/ */
if (!buf || !buf[0]) if (!buf || !buf[0]) {
if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) {
earlycon_init_is_deferred = true;
return 0; return 0;
} else {
return early_init_dt_scan_chosen_stdout();
}
}
err = setup_earlycon(buf); err = setup_earlycon(buf);
if (err == -ENOENT || err == -EALREADY) if (err == -ENOENT || err == -EALREADY)

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -190,6 +190,7 @@
enum imx_uart_type { enum imx_uart_type {
IMX1_UART, IMX1_UART,
IMX21_UART, IMX21_UART,
IMX53_UART,
IMX6Q_UART, IMX6Q_UART,
}; };
@ -222,6 +223,9 @@ struct imx_port {
struct dma_chan *dma_chan_rx, *dma_chan_tx; struct dma_chan *dma_chan_rx, *dma_chan_tx;
struct scatterlist rx_sgl, tx_sgl[2]; struct scatterlist rx_sgl, tx_sgl[2];
void *rx_buf; void *rx_buf;
struct circ_buf rx_ring;
unsigned int rx_periods;
dma_cookie_t rx_cookie;
unsigned int tx_bytes; unsigned int tx_bytes;
unsigned int dma_tx_nents; unsigned int dma_tx_nents;
wait_queue_head_t dma_wait; wait_queue_head_t dma_wait;
@ -244,6 +248,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
.uts_reg = IMX21_UTS, .uts_reg = IMX21_UTS,
.devtype = IMX21_UART, .devtype = IMX21_UART,
}, },
[IMX53_UART] = {
.uts_reg = IMX21_UTS,
.devtype = IMX53_UART,
},
[IMX6Q_UART] = { [IMX6Q_UART] = {
.uts_reg = IMX21_UTS, .uts_reg = IMX21_UTS,
.devtype = IMX6Q_UART, .devtype = IMX6Q_UART,
@ -257,6 +265,9 @@ static const struct platform_device_id imx_uart_devtype[] = {
}, { }, {
.name = "imx21-uart", .name = "imx21-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
}, {
.name = "imx53-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART],
}, { }, {
.name = "imx6q-uart", .name = "imx6q-uart",
.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
@ -268,6 +279,7 @@ MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
static const struct of_device_id imx_uart_dt_ids[] = { static const struct of_device_id imx_uart_dt_ids[] = {
{ .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
{ .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], },
{ .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
{ .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
{ /* sentinel */ } { /* sentinel */ }
@ -289,6 +301,11 @@ static inline int is_imx21_uart(struct imx_port *sport)
return sport->devdata->devtype == IMX21_UART; return sport->devdata->devtype == IMX21_UART;
} }
static inline int is_imx53_uart(struct imx_port *sport)
{
return sport->devdata->devtype == IMX53_UART;
}
static inline int is_imx6q_uart(struct imx_port *sport) static inline int is_imx6q_uart(struct imx_port *sport)
{ {
return sport->devdata->devtype == IMX6Q_UART; return sport->devdata->devtype == IMX6Q_UART;
@ -701,6 +718,7 @@ out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void clear_rx_errors(struct imx_port *sport);
static int start_rx_dma(struct imx_port *sport); static int start_rx_dma(struct imx_port *sport);
/* /*
* If the RXFIFO is filled with some data, and then we * If the RXFIFO is filled with some data, and then we
@ -726,6 +744,11 @@ static void imx_dma_rxint(struct imx_port *sport)
temp &= ~(UCR2_ATEN); temp &= ~(UCR2_ATEN);
writel(temp, sport->port.membase + UCR2); writel(temp, sport->port.membase + UCR2);
/* disable the rx errors interrupts */
temp = readl(sport->port.membase + UCR4);
temp &= ~UCR4_OREN;
writel(temp, sport->port.membase + UCR4);
/* tell the DMA to receive the data. */ /* tell the DMA to receive the data. */
start_rx_dma(sport); start_rx_dma(sport);
} }
@ -740,12 +763,13 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
{ {
unsigned int tmp = TIOCM_DSR; unsigned int tmp = TIOCM_DSR;
unsigned usr1 = readl(sport->port.membase + USR1); unsigned usr1 = readl(sport->port.membase + USR1);
unsigned usr2 = readl(sport->port.membase + USR2);
if (usr1 & USR1_RTSS) if (usr1 & USR1_RTSS)
tmp |= TIOCM_CTS; tmp |= TIOCM_CTS;
/* in DCE mode DCDIN is always 0 */ /* in DCE mode DCDIN is always 0 */
if (!(usr1 & USR2_DCDIN)) if (!(usr2 & USR2_DCDIN))
tmp |= TIOCM_CAR; tmp |= TIOCM_CAR;
if (sport->dte_mode) if (sport->dte_mode)
@ -932,30 +956,6 @@ static void imx_timeout(unsigned long data)
} }
#define RX_BUF_SIZE (PAGE_SIZE) #define RX_BUF_SIZE (PAGE_SIZE)
static void imx_rx_dma_done(struct imx_port *sport)
{
unsigned long temp;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
/* re-enable interrupts to get notified when new symbols are incoming */
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR2);
temp |= UCR2_ATEN;
writel(temp, sport->port.membase + UCR2);
sport->dma_is_rxing = 0;
/* Is the shutdown waiting for us? */
if (waitqueue_active(&sport->dma_wait))
wake_up(&sport->dma_wait);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
/* /*
* There are two kinds of RX DMA interrupts(such as in the MX6Q): * There are two kinds of RX DMA interrupts(such as in the MX6Q):
@ -972,43 +972,76 @@ static void dma_rx_callback(void *data)
struct scatterlist *sgl = &sport->rx_sgl; struct scatterlist *sgl = &sport->rx_sgl;
struct tty_port *port = &sport->port.state->port; struct tty_port *port = &sport->port.state->port;
struct dma_tx_state state; struct dma_tx_state state;
struct circ_buf *rx_ring = &sport->rx_ring;
enum dma_status status; enum dma_status status;
unsigned int count; unsigned int w_bytes = 0;
unsigned int r_bytes;
/* unmap it first */ unsigned int bd_size;
dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
count = RX_BUF_SIZE - state.residue;
dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (status == DMA_ERROR) {
dev_err(sport->port.dev, "DMA transaction error.\n");
clear_rx_errors(sport);
return;
}
if (count) {
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
int bytes = tty_insert_flip_string(port, sport->rx_buf,
count);
if (bytes != count)
sport->port.icount.buf_overrun++;
}
tty_flip_buffer_push(port);
sport->port.icount.rx += count;
}
/* /*
* Restart RX DMA directly if more data is available in order to skip * The state-residue variable represents the empty space
* the roundtrip through the IRQ handler. If there is some data already * relative to the entire buffer. Taking this in consideration
* in the FIFO, DMA needs to be restarted soon anyways. * the head is always calculated base on the buffer total
* * length - DMA transaction residue. The UART script from the
* Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once * SDMA firmware will jump to the next buffer descriptor,
* data starts to arrive again. * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
* Taking this in consideration the tail is always at the
* beginning of the buffer descriptor that contains the head.
*/ */
if (readl(sport->port.membase + USR2) & USR2_RDR)
start_rx_dma(sport); /* Calculate the head */
else rx_ring->head = sg_dma_len(sgl) - state.residue;
imx_rx_dma_done(sport);
/* Calculate the tail. */
bd_size = sg_dma_len(sgl) / sport->rx_periods;
rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
if (rx_ring->head <= sg_dma_len(sgl) &&
rx_ring->head > rx_ring->tail) {
/* Move data from tail to head */
r_bytes = rx_ring->head - rx_ring->tail;
/* CPU claims ownership of RX DMA buffer */
dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
DMA_FROM_DEVICE);
w_bytes = tty_insert_flip_string(port,
sport->rx_buf + rx_ring->tail, r_bytes);
/* UART retrieves ownership of RX DMA buffer */
dma_sync_sg_for_device(sport->port.dev, sgl, 1,
DMA_FROM_DEVICE);
if (w_bytes != r_bytes)
sport->port.icount.buf_overrun++;
sport->port.icount.rx += w_bytes;
} else {
WARN_ON(rx_ring->head > sg_dma_len(sgl));
WARN_ON(rx_ring->head <= rx_ring->tail);
}
}
if (w_bytes) {
tty_flip_buffer_push(port);
dev_dbg(sport->port.dev, "We get %d bytes.\n", w_bytes);
}
} }
/* RX DMA buffer periods */
#define RX_DMA_PERIODS 4
static int start_rx_dma(struct imx_port *sport) static int start_rx_dma(struct imx_port *sport)
{ {
struct scatterlist *sgl = &sport->rx_sgl; struct scatterlist *sgl = &sport->rx_sgl;
@ -1017,14 +1050,21 @@ static int start_rx_dma(struct imx_port *sport)
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
int ret; int ret;
sport->rx_ring.head = 0;
sport->rx_ring.tail = 0;
sport->rx_periods = RX_DMA_PERIODS;
sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
if (ret == 0) { if (ret == 0) {
dev_err(dev, "DMA mapping error for RX.\n"); dev_err(dev, "DMA mapping error for RX.\n");
return -EINVAL; return -EINVAL;
} }
desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT); desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(sgl),
sg_dma_len(sgl), sg_dma_len(sgl) / sport->rx_periods,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!desc) { if (!desc) {
dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE); dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
dev_err(dev, "We cannot prepare for the RX slave dma!\n"); dev_err(dev, "We cannot prepare for the RX slave dma!\n");
@ -1034,11 +1074,36 @@ static int start_rx_dma(struct imx_port *sport)
desc->callback_param = sport; desc->callback_param = sport;
dev_dbg(dev, "RX: prepare for the DMA.\n"); dev_dbg(dev, "RX: prepare for the DMA.\n");
dmaengine_submit(desc); sport->rx_cookie = dmaengine_submit(desc);
dma_async_issue_pending(chan); dma_async_issue_pending(chan);
return 0; return 0;
} }
static void clear_rx_errors(struct imx_port *sport)
{
unsigned int status_usr1, status_usr2;
status_usr1 = readl(sport->port.membase + USR1);
status_usr2 = readl(sport->port.membase + USR2);
if (status_usr2 & USR2_BRCD) {
sport->port.icount.brk++;
writel(USR2_BRCD, sport->port.membase + USR2);
} else if (status_usr1 & USR1_FRAMERR) {
sport->port.icount.frame++;
writel(USR1_FRAMERR, sport->port.membase + USR1);
} else if (status_usr1 & USR1_PARITYERR) {
sport->port.icount.parity++;
writel(USR1_PARITYERR, sport->port.membase + USR1);
}
if (status_usr2 & USR2_ORE) {
sport->port.icount.overrun++;
writel(USR2_ORE, sport->port.membase + USR2);
}
}
#define TXTL_DEFAULT 2 /* reset default */ #define TXTL_DEFAULT 2 /* reset default */
#define RXTL_DEFAULT 1 /* reset default */ #define RXTL_DEFAULT 1 /* reset default */
#define TXTL_DMA 8 /* DMA burst setting */ #define TXTL_DMA 8 /* DMA burst setting */
@ -1058,14 +1123,16 @@ static void imx_setup_ufcr(struct imx_port *sport,
static void imx_uart_dma_exit(struct imx_port *sport) static void imx_uart_dma_exit(struct imx_port *sport)
{ {
if (sport->dma_chan_rx) { if (sport->dma_chan_rx) {
dmaengine_terminate_sync(sport->dma_chan_rx);
dma_release_channel(sport->dma_chan_rx); dma_release_channel(sport->dma_chan_rx);
sport->dma_chan_rx = NULL; sport->dma_chan_rx = NULL;
sport->rx_cookie = -EINVAL;
kfree(sport->rx_buf); kfree(sport->rx_buf);
sport->rx_buf = NULL; sport->rx_buf = NULL;
} }
if (sport->dma_chan_tx) { if (sport->dma_chan_tx) {
dmaengine_terminate_sync(sport->dma_chan_tx);
dma_release_channel(sport->dma_chan_tx); dma_release_channel(sport->dma_chan_tx);
sport->dma_chan_tx = NULL; sport->dma_chan_tx = NULL;
} }
@ -1103,6 +1170,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
sport->rx_ring.buf = sport->rx_buf;
/* Prepare for TX : */ /* Prepare for TX : */
sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
@ -1201,8 +1269,7 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
/* Can we enable the DMA support? */ /* Can we enable the DMA support? */
if (is_imx6q_uart(sport) && !uart_console(port) && if (!uart_console(port) && !sport->dma_is_inited)
!sport->dma_is_inited)
imx_uart_dma_init(sport); imx_uart_dma_init(sport);
spin_lock_irqsave(&sport->port.lock, flags); spin_lock_irqsave(&sport->port.lock, flags);
@ -1283,17 +1350,11 @@ static void imx_shutdown(struct uart_port *port)
unsigned long flags; unsigned long flags;
if (sport->dma_is_enabled) { if (sport->dma_is_enabled) {
int ret;
/* We have to wait for the DMA to finish. */
ret = wait_event_interruptible(sport->dma_wait,
!sport->dma_is_rxing && !sport->dma_is_txing);
if (ret != 0) {
sport->dma_is_rxing = 0; sport->dma_is_rxing = 0;
sport->dma_is_txing = 0; sport->dma_is_txing = 0;
dmaengine_terminate_all(sport->dma_chan_tx); dmaengine_terminate_sync(sport->dma_chan_tx);
dmaengine_terminate_all(sport->dma_chan_rx); dmaengine_terminate_sync(sport->dma_chan_rx);
}
spin_lock_irqsave(&sport->port.lock, flags); spin_lock_irqsave(&sport->port.lock, flags);
imx_stop_tx(port); imx_stop_tx(port);
imx_stop_rx(port); imx_stop_rx(port);
@ -1690,7 +1751,7 @@ static int imx_rs485_config(struct uart_port *port,
return 0; return 0;
} }
static struct uart_ops imx_pops = { static const struct uart_ops imx_pops = {
.tx_empty = imx_tx_empty, .tx_empty = imx_tx_empty,
.set_mctrl = imx_set_mctrl, .set_mctrl = imx_set_mctrl,
.get_mctrl = imx_get_mctrl, .get_mctrl = imx_get_mctrl,
@ -2077,8 +2138,10 @@ static int serial_imx_probe(struct platform_device *pdev)
/* For register access, we only need to enable the ipg clock. */ /* For register access, we only need to enable the ipg clock. */
ret = clk_prepare_enable(sport->clk_ipg); ret = clk_prepare_enable(sport->clk_ipg);
if (ret) if (ret) {
dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret);
return ret; return ret;
}
/* Disable interrupts before requesting them */ /* Disable interrupts before requesting them */
reg = readl_relaxed(sport->port.membase + UCR1); reg = readl_relaxed(sport->port.membase + UCR1);
@ -2095,19 +2158,27 @@ static int serial_imx_probe(struct platform_device *pdev)
if (txirq > 0) { if (txirq > 0) {
ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
dev_name(&pdev->dev), sport); dev_name(&pdev->dev), sport);
if (ret) if (ret) {
dev_err(&pdev->dev, "failed to request rx irq: %d\n",
ret);
return ret; return ret;
}
ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
dev_name(&pdev->dev), sport); dev_name(&pdev->dev), sport);
if (ret) if (ret) {
dev_err(&pdev->dev, "failed to request tx irq: %d\n",
ret);
return ret; return ret;
}
} else { } else {
ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
dev_name(&pdev->dev), sport); dev_name(&pdev->dev), sport);
if (ret) if (ret) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
return ret; return ret;
} }
}
imx_ports[sport->port.line] = sport; imx_ports[sport->port.line] = sport;

Просмотреть файл

@ -346,7 +346,7 @@ static void jsm_config_port(struct uart_port *port, int flags)
port->type = PORT_JSM; port->type = PORT_JSM;
} }
static struct uart_ops jsm_ops = { static const struct uart_ops jsm_ops = {
.tx_empty = jsm_tty_tx_empty, .tx_empty = jsm_tty_tx_empty,
.set_mctrl = jsm_tty_set_mctrl, .set_mctrl = jsm_tty_set_mctrl,
.get_mctrl = jsm_tty_get_mctrl, .get_mctrl = jsm_tty_get_mctrl,

Просмотреть файл

@ -712,7 +712,7 @@ static void max3100_break_ctl(struct uart_port *port, int break_state)
dev_dbg(&s->spi->dev, "%s\n", __func__); dev_dbg(&s->spi->dev, "%s\n", __func__);
} }
static struct uart_ops max3100_ops = { static const struct uart_ops max3100_ops = {
.tx_empty = max3100_tx_empty, .tx_empty = max3100_tx_empty,
.set_mctrl = max3100_set_mctrl, .set_mctrl = max3100_set_mctrl,
.get_mctrl = max3100_get_mctrl, .get_mctrl = max3100_get_mctrl,

Просмотреть файл

@ -1329,9 +1329,9 @@ static int max310x_spi_probe(struct spi_device *spi)
const struct spi_device_id *id_entry = spi_get_device_id(spi); const struct spi_device_id *id_entry = spi_get_device_id(spi);
devtype = (struct max310x_devtype *)id_entry->driver_data; devtype = (struct max310x_devtype *)id_entry->driver_data;
flags = IRQF_TRIGGER_FALLING;
} }
flags = IRQF_TRIGGER_FALLING;
regcfg.max_register = devtype->nr * 0x20 - 1; regcfg.max_register = devtype->nr * 0x20 - 1;
regmap = devm_regmap_init_spi(spi, &regcfg); regmap = devm_regmap_init_spi(spi, &regcfg);

Просмотреть файл

@ -775,7 +775,7 @@ static int men_z135_verify_port(struct uart_port *port,
return -EINVAL; return -EINVAL;
} }
static struct uart_ops men_z135_ops = { static const struct uart_ops men_z135_ops = {
.tx_empty = men_z135_tx_empty, .tx_empty = men_z135_tx_empty,
.set_mctrl = men_z135_set_mctrl, .set_mctrl = men_z135_set_mctrl,
.get_mctrl = men_z135_get_mctrl, .get_mctrl = men_z135_get_mctrl,

Просмотреть файл

@ -1317,7 +1317,7 @@ static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL); mxs_clr(AUART_LINECTRL_BRK, s, REG_LINECTRL);
} }
static struct uart_ops mxs_auart_ops = { static const struct uart_ops mxs_auart_ops = {
.tx_empty = mxs_auart_tx_empty, .tx_empty = mxs_auart_tx_empty,
.start_tx = mxs_auart_start_tx, .start_tx = mxs_auart_start_tx,
.stop_tx = mxs_auart_stop_tx, .stop_tx = mxs_auart_stop_tx,
@ -1510,10 +1510,7 @@ static int mxs_get_clks(struct mxs_auart_port *s,
if (!is_asm9260_auart(s)) { if (!is_asm9260_auart(s)) {
s->clk = devm_clk_get(&pdev->dev, NULL); s->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk)) return PTR_ERR_OR_ZERO(s->clk);
return PTR_ERR(s->clk);
return 0;
} }
s->clk = devm_clk_get(s->dev, "mod"); s->clk = devm_clk_get(s->dev, "mod");
@ -1537,16 +1534,20 @@ static int mxs_get_clks(struct mxs_auart_port *s,
err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb)); err = clk_set_rate(s->clk, clk_get_rate(s->clk_ahb));
if (err) { if (err) {
dev_err(s->dev, "Failed to set rate!\n"); dev_err(s->dev, "Failed to set rate!\n");
return err; goto disable_clk_ahb;
} }
err = clk_prepare_enable(s->clk); err = clk_prepare_enable(s->clk);
if (err) { if (err) {
dev_err(s->dev, "Failed to enable clk!\n"); dev_err(s->dev, "Failed to enable clk!\n");
return err; goto disable_clk_ahb;
} }
return 0; return 0;
disable_clk_ahb:
clk_disable_unprepare(s->clk_ahb);
return err;
} }
/* /*

Просмотреть файл

@ -1604,7 +1604,7 @@ static void pch_uart_put_poll_char(struct uart_port *port,
} }
#endif /* CONFIG_CONSOLE_POLL */ #endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops pch_uart_ops = { static const struct uart_ops pch_uart_ops = {
.tx_empty = pch_uart_tx_empty, .tx_empty = pch_uart_tx_empty,
.set_mctrl = pch_uart_set_mctrl, .set_mctrl = pch_uart_set_mctrl,
.get_mctrl = pch_uart_get_mctrl, .get_mctrl = pch_uart_get_mctrl,

Просмотреть файл

@ -1577,7 +1577,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb, static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data) unsigned long val, void *data)

Просмотреть файл

@ -102,7 +102,7 @@ struct s3c24xx_uart_port {
struct s3c24xx_uart_dma *dma; struct s3c24xx_uart_dma *dma;
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_ARM_S3C24XX_CPUFREQ
struct notifier_block freq_transition; struct notifier_block freq_transition;
#endif #endif
}; };

Просмотреть файл

@ -1205,6 +1205,10 @@ static int sc16is7xx_probe(struct device *dev,
} }
#endif #endif
/* reset device, purging any pending irq / data */
regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
SC16IS7XX_IOCONTROL_SRESET_BIT);
for (i = 0; i < devtype->nr_uart; ++i) { for (i = 0; i < devtype->nr_uart; ++i) {
s->p[i].line = i; s->p[i].line = i;
/* Initialize port data */ /* Initialize port data */
@ -1234,6 +1238,22 @@ static int sc16is7xx_probe(struct device *dev,
init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
/* Register port */ /* Register port */
uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
/* Enable EFR */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
regcache_cache_bypass(s->regmap, true);
/* Enable write access to enhanced features */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_ENABLE_BIT);
regcache_cache_bypass(s->regmap, false);
/* Restore access to general registers */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
/* Go to suspend mode */ /* Go to suspend mode */
sc16is7xx_power(&s->p[i].port, 0); sc16is7xx_power(&s->p[i].port, 0);
} }

Просмотреть файл

@ -235,18 +235,9 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
if (tty_port_initialized(port)) if (tty_port_initialized(port))
return 0; return 0;
/*
* Set the TTY IO error marker - we will only clear this
* once we have successfully opened the port.
*/
set_bit(TTY_IO_ERROR, &tty->flags);
retval = uart_port_startup(tty, state, init_hw); retval = uart_port_startup(tty, state, init_hw);
if (!retval) { if (retval)
tty_port_set_initialized(port, 1); set_bit(TTY_IO_ERROR, &tty->flags);
clear_bit(TTY_IO_ERROR, &tty->flags);
} else if (retval > 0)
retval = 0;
return retval; return retval;
} }
@ -972,8 +963,11 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
} }
uart_change_speed(tty, state, NULL); uart_change_speed(tty, state, NULL);
} }
} else } else {
retval = uart_startup(tty, state, 1); retval = uart_startup(tty, state, 1);
if (retval > 0)
retval = 0;
}
exit: exit:
return retval; return retval;
} }
@ -1139,6 +1133,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
uport->ops->config_port(uport, flags); uport->ops->config_port(uport, flags);
ret = uart_startup(tty, state, 1); ret = uart_startup(tty, state, 1);
if (ret > 0)
ret = 0;
} }
out: out:
mutex_unlock(&port->mutex); mutex_unlock(&port->mutex);
@ -1465,7 +1461,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
{ {
struct uart_state *state = tty->driver_data; struct uart_state *state = tty->driver_data;
struct tty_port *port; struct tty_port *port;
struct uart_port *uport;
if (!state) { if (!state) {
struct uart_driver *drv = tty->driver->driver_state; struct uart_driver *drv = tty->driver->driver_state;
@ -1481,56 +1476,36 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
port = &state->port; port = &state->port;
pr_debug("uart_close(%d) called\n", tty->index); pr_debug("uart_close(%d) called\n", tty->index);
if (tty_port_close_start(port, tty, filp) == 0) tty_port_close(tty->port, tty, filp);
return; }
mutex_lock(&port->mutex); static void uart_tty_port_shutdown(struct tty_port *port)
uport = uart_port_check(state); {
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = uart_port_check(state);
/* /*
* At this point, we stop accepting input. To do this, we * At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts. * disable the receive line status interrupts.
*/ */
if (tty_port_initialized(port) && if (WARN(!uport, "detached port still initialized!\n"))
!WARN(!uport, "detached port still initialized!\n")) { return;
spin_lock_irq(&uport->lock); spin_lock_irq(&uport->lock);
uport->ops->stop_rx(uport); uport->ops->stop_rx(uport);
spin_unlock_irq(&uport->lock); spin_unlock_irq(&uport->lock);
uart_port_shutdown(port);
/* /*
* Before we drop DTR, make sure the UART transmitter * It's possible for shutdown to be called after suspend if we get
* has completely drained; this is especially * a DCD drop (hangup) at just the right time. Clear suspended bit so
* important if there is a transmit FIFO! * we don't try to resume a port that has been shutdown.
*/ */
uart_wait_until_sent(tty, uport->timeout); tty_port_set_suspended(port, 0);
}
uart_shutdown(tty, state);
tty_port_tty_set(port, NULL);
spin_lock_irq(&port->lock);
if (port->blocked_open) {
spin_unlock_irq(&port->lock);
if (port->close_delay)
msleep_interruptible(jiffies_to_msecs(port->close_delay));
spin_lock_irq(&port->lock);
} else if (uport && !uart_console(uport)) {
spin_unlock_irq(&port->lock);
uart_change_pm(state, UART_PM_STATE_OFF); uart_change_pm(state, UART_PM_STATE_OFF);
spin_lock_irq(&port->lock);
}
spin_unlock_irq(&port->lock);
tty_port_set_active(port, 0);
/*
* Wake up anyone trying to open this port.
*/
wake_up_interruptible(&port->open_wait);
mutex_unlock(&port->mutex);
tty_ldisc_flush(tty);
tty->closing = 0;
} }
static void uart_wait_until_sent(struct tty_struct *tty, int timeout) static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@ -1711,52 +1686,31 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
struct uart_driver *drv = tty->driver->driver_state; struct uart_driver *drv = tty->driver->driver_state;
int retval, line = tty->index; int retval, line = tty->index;
struct uart_state *state = drv->state + line; struct uart_state *state = drv->state + line;
struct tty_port *port = &state->port;
struct uart_port *uport;
pr_debug("uart_open(%d) called\n", line);
spin_lock_irq(&port->lock);
++port->count;
spin_unlock_irq(&port->lock);
/*
* We take the semaphore here to guarantee that we won't be re-entered
* while allocating the state structure, or while we request any IRQs
* that the driver may need. This also has the nice side-effect that
* it delays the action of uart_hangup, so we can guarantee that
* state->port.tty will always contain something reasonable.
*/
if (mutex_lock_interruptible(&port->mutex)) {
retval = -ERESTARTSYS;
goto end;
}
uport = uart_port_check(state);
if (!uport || uport->flags & UPF_DEAD) {
retval = -ENXIO;
goto err_unlock;
}
tty->driver_data = state; tty->driver_data = state;
uport->state = state;
retval = tty_port_open(&state->port, tty, filp);
if (retval > 0)
retval = 0;
return retval;
}
static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
uport = uart_port_check(state);
if (!uport || uport->flags & UPF_DEAD)
return -ENXIO;
port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty_port_tty_set(port, tty);
/* /*
* Start up the serial port. * Start up the serial port.
*/ */
retval = uart_startup(tty, state, 0); return uart_startup(tty, state, 0);
/*
* If we succeeded, wait until the port is ready.
*/
err_unlock:
mutex_unlock(&port->mutex);
if (retval == 0)
retval = tty_port_block_til_ready(port, tty, filp);
end:
return retval;
} }
static const char *uart_type(struct uart_port *port) static const char *uart_type(struct uart_port *port)
@ -1940,7 +1894,7 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
* *
* Returns 0 on success or -EINVAL on failure * Returns 0 on success or -EINVAL on failure
*/ */
int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
char **options) char **options)
{ {
if (strncmp(p, "mmio,", 5) == 0) { if (strncmp(p, "mmio,", 5) == 0) {
@ -1968,7 +1922,11 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
return -EINVAL; return -EINVAL;
} }
*addr = simple_strtoul(p, NULL, 0); /*
* Before you replace it with kstrtoull(), think about options separator
* (',') it will not tolerate
*/
*addr = simple_strtoull(p, NULL, 0);
p = strchr(p, ','); p = strchr(p, ',');
if (p) if (p)
p++; p++;
@ -2470,6 +2428,8 @@ static const struct tty_operations uart_ops = {
static const struct tty_port_operations uart_port_ops = { static const struct tty_port_operations uart_port_ops = {
.carrier_raised = uart_carrier_raised, .carrier_raised = uart_carrier_raised,
.dtr_rts = uart_dtr_rts, .dtr_rts = uart_dtr_rts,
.activate = uart_port_activate,
.shutdown = uart_tty_port_shutdown,
}; };
/** /**
@ -2786,6 +2746,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
uport->cons = drv->cons; uport->cons = drv->cons;
uport->minor = drv->tty_driver->minor_start + uport->line; uport->minor = drv->tty_driver->minor_start + uport->line;
port->console = uart_console(uport);
/* /*
* If this port is a console, then the spinlock is already * If this port is a console, then the spinlock is already
* initialised. * initialised.

Просмотреть файл

@ -2533,7 +2533,7 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0; return 0;
} }
static struct uart_ops sci_uart_ops = { static const struct uart_ops sci_uart_ops = {
.tx_empty = sci_tx_empty, .tx_empty = sci_tx_empty,
.set_mctrl = sci_set_mctrl, .set_mctrl = sci_set_mctrl,
.get_mctrl = sci_get_mctrl, .get_mctrl = sci_get_mctrl,

Просмотреть файл

@ -639,7 +639,7 @@ static void asc_put_poll_char(struct uart_port *port, unsigned char c)
/*---------------------------------------------------------------------*/ /*---------------------------------------------------------------------*/
static struct uart_ops asc_uart_ops = { static const struct uart_ops asc_uart_ops = {
.tx_empty = asc_tx_empty, .tx_empty = asc_tx_empty,
.set_mctrl = asc_set_mctrl, .set_mctrl = asc_set_mctrl,
.get_mctrl = asc_get_mctrl, .get_mctrl = asc_get_mctrl,

Просмотреть файл

@ -1,6 +1,7 @@
/* /*
* Copyright (C) Maxime Coquelin 2015 * Copyright (C) Maxime Coquelin 2015
* Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> * Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* Gerald Baeza <gerald.baeza@st.com>
* License terms: GNU General Public License (GPL), version 2 * License terms: GNU General Public License (GPL), version 2
* *
* Inspired by st-asc.c from STMicroelectronics (c) * Inspired by st-asc.c from STMicroelectronics (c)
@ -10,120 +11,31 @@
#define SUPPORT_SYSRQ #define SUPPORT_SYSRQ
#endif #endif
#include <linux/module.h> #include <linux/clk.h>
#include <linux/serial.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/spinlock.h> #include <linux/dma-direction.h>
#include <linux/pm_runtime.h> #include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/clk.h> #include <linux/serial.h>
#include <linux/spinlock.h>
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/tty.h>
#define DRIVER_NAME "stm32-usart" #include "stm32-usart.h"
/* Register offsets */
#define USART_SR 0x00
#define USART_DR 0x04
#define USART_BRR 0x08
#define USART_CR1 0x0c
#define USART_CR2 0x10
#define USART_CR3 0x14
#define USART_GTPR 0x18
/* USART_SR */
#define USART_SR_PE BIT(0)
#define USART_SR_FE BIT(1)
#define USART_SR_NF BIT(2)
#define USART_SR_ORE BIT(3)
#define USART_SR_IDLE BIT(4)
#define USART_SR_RXNE BIT(5)
#define USART_SR_TC BIT(6)
#define USART_SR_TXE BIT(7)
#define USART_SR_LBD BIT(8)
#define USART_SR_CTS BIT(9)
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
USART_SR_FE | USART_SR_PE)
/* Dummy bits */
#define USART_SR_DUMMY_RX BIT(16)
/* USART_DR */
#define USART_DR_MASK GENMASK(8, 0)
/* USART_BRR */
#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
#define USART_BRR_DIV_M_SHIFT 4
/* USART_CR1 */
#define USART_CR1_SBK BIT(0)
#define USART_CR1_RWU BIT(1)
#define USART_CR1_RE BIT(2)
#define USART_CR1_TE BIT(3)
#define USART_CR1_IDLEIE BIT(4)
#define USART_CR1_RXNEIE BIT(5)
#define USART_CR1_TCIE BIT(6)
#define USART_CR1_TXEIE BIT(7)
#define USART_CR1_PEIE BIT(8)
#define USART_CR1_PS BIT(9)
#define USART_CR1_PCE BIT(10)
#define USART_CR1_WAKE BIT(11)
#define USART_CR1_M BIT(12)
#define USART_CR1_UE BIT(13)
#define USART_CR1_OVER8 BIT(15)
#define USART_CR1_IE_MASK GENMASK(8, 4)
/* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0)
#define USART_CR2_LBDL BIT(5)
#define USART_CR2_LBDIE BIT(6)
#define USART_CR2_LBCL BIT(8)
#define USART_CR2_CPHA BIT(9)
#define USART_CR2_CPOL BIT(10)
#define USART_CR2_CLKEN BIT(11)
#define USART_CR2_STOP_2B BIT(13)
#define USART_CR2_STOP_MASK GENMASK(13, 12)
#define USART_CR2_LINEN BIT(14)
/* USART_CR3 */
#define USART_CR3_EIE BIT(0)
#define USART_CR3_IREN BIT(1)
#define USART_CR3_IRLP BIT(2)
#define USART_CR3_HDSEL BIT(3)
#define USART_CR3_NACK BIT(4)
#define USART_CR3_SCEN BIT(5)
#define USART_CR3_DMAR BIT(6)
#define USART_CR3_DMAT BIT(7)
#define USART_CR3_RTSE BIT(8)
#define USART_CR3_CTSE BIT(9)
#define USART_CR3_CTSIE BIT(10)
#define USART_CR3_ONEBIT BIT(11)
/* USART_GTPR */
#define USART_GTPR_PSC_MASK GENMASK(7, 0)
#define USART_GTPR_GT_MASK GENMASK(15, 8)
#define DRIVER_NAME "stm32-usart"
#define STM32_SERIAL_NAME "ttyS"
#define STM32_MAX_PORTS 6
struct stm32_port {
struct uart_port port;
struct clk *clk;
bool hw_flow_control;
};
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
static struct uart_driver stm32_usart_driver;
static void stm32_stop_tx(struct uart_port *port); static void stm32_stop_tx(struct uart_port *port);
static void stm32_transmit_chars(struct uart_port *port);
static inline struct stm32_port *to_stm32_port(struct uart_port *port) static inline struct stm32_port *to_stm32_port(struct uart_port *port)
{ {
@ -148,19 +60,64 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits)
writel_relaxed(val, port->membase + reg); writel_relaxed(val, port->membase + reg);
} }
static void stm32_receive_chars(struct uart_port *port) static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
bool threaded)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
enum dma_status status;
struct dma_tx_state state;
*sr = readl_relaxed(port->membase + ofs->isr);
if (threaded && stm32_port->rx_ch) {
status = dmaengine_tx_status(stm32_port->rx_ch,
stm32_port->rx_ch->cookie,
&state);
if ((status == DMA_IN_PROGRESS) &&
(*last_res != state.residue))
return 1;
else
return 0;
} else if (*sr & USART_SR_RXNE) {
return 1;
}
return 0;
}
static unsigned long
stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long c;
if (stm32_port->rx_ch) {
c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
if ((*last_res) == 0)
*last_res = RX_BUF_L;
return c;
} else {
return readl_relaxed(port->membase + ofs->rdr);
}
}
static void stm32_receive_chars(struct uart_port *port, bool threaded)
{ {
struct tty_port *tport = &port->state->port; struct tty_port *tport = &port->state->port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long c; unsigned long c;
u32 sr; u32 sr;
char flag; char flag;
static int last_res = RX_BUF_L;
if (port->irq_wake) if (port->irq_wake)
pm_wakeup_event(tport->tty->dev, 0); pm_wakeup_event(tport->tty->dev, 0);
while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) { while (stm32_pending_rx(port, &sr, &last_res, threaded)) {
sr |= USART_SR_DUMMY_RX; sr |= USART_SR_DUMMY_RX;
c = readl_relaxed(port->membase + USART_DR); c = stm32_get_char(port, &sr, &last_res);
flag = TTY_NORMAL; flag = TTY_NORMAL;
port->icount.rx++; port->icount.rx++;
@ -170,6 +127,10 @@ static void stm32_receive_chars(struct uart_port *port)
if (uart_handle_break(port)) if (uart_handle_break(port))
continue; continue;
} else if (sr & USART_SR_ORE) { } else if (sr & USART_SR_ORE) {
if (ofs->icr != UNDEF_REG)
writel_relaxed(USART_ICR_ORECF,
port->membase +
ofs->icr);
port->icount.overrun++; port->icount.overrun++;
} else if (sr & USART_SR_PE) { } else if (sr & USART_SR_PE) {
port->icount.parity++; port->icount.parity++;
@ -197,14 +158,138 @@ static void stm32_receive_chars(struct uart_port *port)
spin_lock(&port->lock); spin_lock(&port->lock);
} }
static void stm32_tx_dma_complete(void *arg)
{
struct uart_port *port = arg;
struct stm32_port *stm32port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
unsigned int isr;
int ret;
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
isr,
(isr & USART_SR_TC),
10, 100000);
if (ret)
dev_err(port->dev, "terminal count not set\n");
if (ofs->icr == UNDEF_REG)
stm32_clr_bits(port, ofs->isr, USART_SR_TC);
else
stm32_set_bits(port, ofs->icr, USART_CR_TC);
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32port->tx_dma_busy = false;
/* Let's see if we have pending data to send */
stm32_transmit_chars(port);
}
static void stm32_transmit_chars_pio(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit;
unsigned int isr;
int ret;
if (stm32_port->tx_dma_busy) {
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
stm32_port->tx_dma_busy = false;
}
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
isr,
(isr & USART_SR_TXE),
10, 100);
if (ret)
dev_err(port->dev, "tx empty not set\n");
stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
static void stm32_transmit_chars_dma(struct uart_port *port)
{
struct stm32_port *stm32port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
struct circ_buf *xmit = &port->state->xmit;
struct dma_async_tx_descriptor *desc = NULL;
dma_cookie_t cookie;
unsigned int count, i;
if (stm32port->tx_dma_busy)
return;
stm32port->tx_dma_busy = true;
count = uart_circ_chars_pending(xmit);
if (count > TX_BUF_L)
count = TX_BUF_L;
if (xmit->tail < xmit->head) {
memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count);
} else {
size_t one = UART_XMIT_SIZE - xmit->tail;
size_t two;
if (one > count)
one = count;
two = count - one;
memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one);
if (two)
memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two);
}
desc = dmaengine_prep_slave_single(stm32port->tx_ch,
stm32port->tx_dma_buf,
count,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!desc) {
for (i = count; i > 0; i--)
stm32_transmit_chars_pio(port);
return;
}
desc->callback = stm32_tx_dma_complete;
desc->callback_param = port;
/* Push current DMA TX transaction in the pending queue */
cookie = dmaengine_submit(desc);
/* Issue pending DMA TX requests */
dma_async_issue_pending(stm32port->tx_ch);
stm32_clr_bits(port, ofs->isr, USART_SR_TC);
stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
port->icount.tx += count;
}
static void stm32_transmit_chars(struct uart_port *port) static void stm32_transmit_chars(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct circ_buf *xmit = &port->state->xmit; struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) { if (port->x_char) {
writel_relaxed(port->x_char, port->membase + USART_DR); if (stm32_port->tx_dma_busy)
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
writel_relaxed(port->x_char, port->membase + ofs->tdr);
port->x_char = 0; port->x_char = 0;
port->icount.tx++; port->icount.tx++;
if (stm32_port->tx_dma_busy)
stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
return; return;
} }
@ -218,9 +303,10 @@ static void stm32_transmit_chars(struct uart_port *port)
return; return;
} }
writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR); if (stm32_port->tx_ch)
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); stm32_transmit_chars_dma(port);
port->icount.tx++; else
stm32_transmit_chars_pio(port);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port); uart_write_wakeup(port);
@ -232,34 +318,60 @@ static void stm32_transmit_chars(struct uart_port *port)
static irqreturn_t stm32_interrupt(int irq, void *ptr) static irqreturn_t stm32_interrupt(int irq, void *ptr)
{ {
struct uart_port *port = ptr; struct uart_port *port = ptr;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
u32 sr; u32 sr;
spin_lock(&port->lock); spin_lock(&port->lock);
sr = readl_relaxed(port->membase + USART_SR); sr = readl_relaxed(port->membase + ofs->isr);
if (sr & USART_SR_RXNE) if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
stm32_receive_chars(port); stm32_receive_chars(port, false);
if (sr & USART_SR_TXE) if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch))
stm32_transmit_chars(port); stm32_transmit_chars(port);
spin_unlock(&port->lock); spin_unlock(&port->lock);
if (stm32_port->rx_ch)
return IRQ_WAKE_THREAD;
else
return IRQ_HANDLED;
}
static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
struct stm32_port *stm32_port = to_stm32_port(port);
spin_lock(&port->lock);
if (stm32_port->rx_ch)
stm32_receive_chars(port, true);
spin_unlock(&port->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static unsigned int stm32_tx_empty(struct uart_port *port) static unsigned int stm32_tx_empty(struct uart_port *port)
{ {
return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE; struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE;
} }
static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
stm32_set_bits(port, USART_CR3, USART_CR3_RTSE); stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE);
else else
stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE); stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE);
} }
static unsigned int stm32_get_mctrl(struct uart_port *port) static unsigned int stm32_get_mctrl(struct uart_port *port)
@ -271,7 +383,10 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
/* Transmit stop */ /* Transmit stop */
static void stm32_stop_tx(struct uart_port *port) static void stm32_stop_tx(struct uart_port *port)
{ {
stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
} }
/* There are probably characters waiting to be transmitted. */ /* There are probably characters waiting to be transmitted. */
@ -282,33 +397,40 @@ static void stm32_start_tx(struct uart_port *port)
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
return; return;
stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE); stm32_transmit_chars(port);
} }
/* Throttle the remote when input buffer is about to overflow. */ /* Throttle the remote when input buffer is about to overflow. */
static void stm32_throttle(struct uart_port *port) static void stm32_throttle(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
/* Unthrottle the remote, the input buffer can now accept data. */ /* Unthrottle the remote, the input buffer can now accept data. */
static void stm32_unthrottle(struct uart_port *port) static void stm32_unthrottle(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE); stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
/* Receive stop */ /* Receive stop */
static void stm32_stop_rx(struct uart_port *port) static void stm32_stop_rx(struct uart_port *port)
{ {
stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
} }
/* Handle breaks - ignored by us */ /* Handle breaks - ignored by us */
@ -318,26 +440,34 @@ static void stm32_break_ctl(struct uart_port *port, int break_state)
static int stm32_startup(struct uart_port *port) static int stm32_startup(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
const char *name = to_platform_device(port->dev)->name; const char *name = to_platform_device(port->dev)->name;
u32 val; u32 val;
int ret; int ret;
ret = request_irq(port->irq, stm32_interrupt, 0, name, port); ret = request_threaded_irq(port->irq, stm32_interrupt,
stm32_threaded_interrupt,
IRQF_NO_SUSPEND, name, port);
if (ret) if (ret)
return ret; return ret;
val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
stm32_set_bits(port, USART_CR1, val); stm32_set_bits(port, ofs->cr1, val);
return 0; return 0;
} }
static void stm32_shutdown(struct uart_port *port) static void stm32_shutdown(struct uart_port *port)
{ {
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
u32 val; u32 val;
val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
stm32_set_bits(port, USART_CR1, val); val |= BIT(cfg->uart_enable_bit);
stm32_clr_bits(port, ofs->cr1, val);
free_irq(port->irq, port); free_irq(port->irq, port);
} }
@ -346,6 +476,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
{ {
struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
unsigned int baud; unsigned int baud;
u32 usartdiv, mantissa, fraction, oversampling; u32 usartdiv, mantissa, fraction, oversampling;
tcflag_t cflag = termios->c_cflag; tcflag_t cflag = termios->c_cflag;
@ -360,9 +492,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/* Stop serial port and reset value */ /* Stop serial port and reset value */
writel_relaxed(0, port->membase + USART_CR1); writel_relaxed(0, port->membase + ofs->cr1);
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
cr1 |= BIT(cfg->uart_enable_bit);
cr2 = 0; cr2 = 0;
cr3 = 0; cr3 = 0;
@ -371,9 +504,13 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if (cflag & PARENB) { if (cflag & PARENB) {
cr1 |= USART_CR1_PCE; cr1 |= USART_CR1_PCE;
if ((cflag & CSIZE) == CS8) if ((cflag & CSIZE) == CS8) {
if (cfg->has_7bits_data)
cr1 |= USART_CR1_M0;
else
cr1 |= USART_CR1_M; cr1 |= USART_CR1_M;
} }
}
if (cflag & PARODD) if (cflag & PARODD)
cr1 |= USART_CR1_PS; cr1 |= USART_CR1_PS;
@ -394,15 +531,15 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
*/ */
if (usartdiv < 16) { if (usartdiv < 16) {
oversampling = 8; oversampling = 8;
stm32_set_bits(port, USART_CR1, USART_CR1_OVER8); stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8);
} else { } else {
oversampling = 16; oversampling = 16;
stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8); stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8);
} }
mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT;
fraction = usartdiv % oversampling; fraction = usartdiv % oversampling;
writel_relaxed(mantissa | fraction, port->membase + USART_BRR); writel_relaxed(mantissa | fraction, port->membase + ofs->brr);
uart_update_timeout(port, cflag, baud); uart_update_timeout(port, cflag, baud);
@ -430,9 +567,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CREAD) == 0) if ((termios->c_cflag & CREAD) == 0)
port->ignore_status_mask |= USART_SR_DUMMY_RX; port->ignore_status_mask |= USART_SR_DUMMY_RX;
writel_relaxed(cr3, port->membase + USART_CR3); if (stm32_port->rx_ch)
writel_relaxed(cr2, port->membase + USART_CR2); cr3 |= USART_CR3_DMAR;
writel_relaxed(cr1, port->membase + USART_CR1);
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr2, port->membase + ofs->cr2);
writel_relaxed(cr1, port->membase + ofs->cr1);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -469,6 +609,8 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
{ {
struct stm32_port *stm32port = container_of(port, struct stm32_port *stm32port = container_of(port,
struct stm32_port, port); struct stm32_port, port);
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
struct stm32_usart_config *cfg = &stm32port->info->cfg;
unsigned long flags = 0; unsigned long flags = 0;
switch (state) { switch (state) {
@ -477,7 +619,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state,
break; break;
case UART_PM_STATE_OFF: case UART_PM_STATE_OFF:
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
stm32_clr_bits(port, USART_CR1, USART_CR1_UE); stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
clk_disable_unprepare(stm32port->clk); clk_disable_unprepare(stm32port->clk);
break; break;
@ -539,8 +681,6 @@ static int stm32_init_port(struct stm32_port *stm32port,
if (!stm32port->port.uartclk) if (!stm32port->port.uartclk)
ret = -EINVAL; ret = -EINVAL;
clk_disable_unprepare(stm32port->clk);
return ret; return ret;
} }
@ -560,30 +700,162 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
return NULL; return NULL;
stm32_ports[id].hw_flow_control = of_property_read_bool(np, stm32_ports[id].hw_flow_control = of_property_read_bool(np,
"auto-flow-control"); "st,hw-flow-ctrl");
stm32_ports[id].port.line = id; stm32_ports[id].port.line = id;
return &stm32_ports[id]; return &stm32_ports[id];
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id stm32_match[] = { static const struct of_device_id stm32_match[] = {
{ .compatible = "st,stm32-usart", }, { .compatible = "st,stm32-usart", .data = &stm32f4_info},
{ .compatible = "st,stm32-uart", }, { .compatible = "st,stm32-uart", .data = &stm32f4_info},
{ .compatible = "st,stm32f7-usart", .data = &stm32f7_info},
{ .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, stm32_match); MODULE_DEVICE_TABLE(of, stm32_match);
#endif #endif
static int stm32_of_dma_rx_probe(struct stm32_port *stm32port,
struct platform_device *pdev)
{
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
struct uart_port *port = &stm32port->port;
struct device *dev = &pdev->dev;
struct dma_slave_config config;
struct dma_async_tx_descriptor *desc = NULL;
dma_cookie_t cookie;
int ret;
/* Request DMA RX channel */
stm32port->rx_ch = dma_request_slave_channel(dev, "rx");
if (!stm32port->rx_ch) {
dev_info(dev, "rx dma alloc failed\n");
return -ENODEV;
}
stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L,
&stm32port->rx_dma_buf,
GFP_KERNEL);
if (!stm32port->rx_buf) {
ret = -ENOMEM;
goto alloc_err;
}
/* Configure DMA channel */
memset(&config, 0, sizeof(config));
config.src_addr = port->mapbase + ofs->rdr;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
ret = dmaengine_slave_config(stm32port->rx_ch, &config);
if (ret < 0) {
dev_err(dev, "rx dma channel config failed\n");
ret = -ENODEV;
goto config_err;
}
/* Prepare a DMA cyclic transaction */
desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch,
stm32port->rx_dma_buf,
RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(dev, "rx dma prep cyclic failed\n");
ret = -ENODEV;
goto config_err;
}
/* No callback as dma buffer is drained on usart interrupt */
desc->callback = NULL;
desc->callback_param = NULL;
/* Push current DMA transaction in the pending queue */
cookie = dmaengine_submit(desc);
/* Issue pending DMA requests */
dma_async_issue_pending(stm32port->rx_ch);
return 0;
config_err:
dma_free_coherent(&pdev->dev,
RX_BUF_L, stm32port->rx_buf,
stm32port->rx_dma_buf);
alloc_err:
dma_release_channel(stm32port->rx_ch);
stm32port->rx_ch = NULL;
return ret;
}
static int stm32_of_dma_tx_probe(struct stm32_port *stm32port,
struct platform_device *pdev)
{
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
struct uart_port *port = &stm32port->port;
struct device *dev = &pdev->dev;
struct dma_slave_config config;
int ret;
stm32port->tx_dma_busy = false;
/* Request DMA TX channel */
stm32port->tx_ch = dma_request_slave_channel(dev, "tx");
if (!stm32port->tx_ch) {
dev_info(dev, "tx dma alloc failed\n");
return -ENODEV;
}
stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L,
&stm32port->tx_dma_buf,
GFP_KERNEL);
if (!stm32port->tx_buf) {
ret = -ENOMEM;
goto alloc_err;
}
/* Configure DMA channel */
memset(&config, 0, sizeof(config));
config.dst_addr = port->mapbase + ofs->tdr;
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
ret = dmaengine_slave_config(stm32port->tx_ch, &config);
if (ret < 0) {
dev_err(dev, "tx dma channel config failed\n");
ret = -ENODEV;
goto config_err;
}
return 0;
config_err:
dma_free_coherent(&pdev->dev,
TX_BUF_L, stm32port->tx_buf,
stm32port->tx_dma_buf);
alloc_err:
dma_release_channel(stm32port->tx_ch);
stm32port->tx_ch = NULL;
return ret;
}
static int stm32_serial_probe(struct platform_device *pdev) static int stm32_serial_probe(struct platform_device *pdev)
{ {
int ret; const struct of_device_id *match;
struct stm32_port *stm32port; struct stm32_port *stm32port;
int ret;
stm32port = stm32_of_get_stm32_port(pdev); stm32port = stm32_of_get_stm32_port(pdev);
if (!stm32port) if (!stm32port)
return -ENODEV; return -ENODEV;
match = of_match_device(stm32_match, &pdev->dev);
if (match && match->data)
stm32port->info = (struct stm32_usart_info *)match->data;
else
return -EINVAL;
ret = stm32_init_port(stm32port, pdev); ret = stm32_init_port(stm32port, pdev);
if (ret) if (ret)
return ret; return ret;
@ -592,6 +864,14 @@ static int stm32_serial_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = stm32_of_dma_rx_probe(stm32port, pdev);
if (ret)
dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n");
ret = stm32_of_dma_tx_probe(stm32port, pdev);
if (ret)
dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n");
platform_set_drvdata(pdev, &stm32port->port); platform_set_drvdata(pdev, &stm32port->port);
return 0; return 0;
@ -600,6 +880,30 @@ static int stm32_serial_probe(struct platform_device *pdev)
static int stm32_serial_remove(struct platform_device *pdev) static int stm32_serial_remove(struct platform_device *pdev)
{ {
struct uart_port *port = platform_get_drvdata(pdev); struct uart_port *port = platform_get_drvdata(pdev);
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
if (stm32_port->rx_ch)
dma_release_channel(stm32_port->rx_ch);
if (stm32_port->rx_dma_buf)
dma_free_coherent(&pdev->dev,
RX_BUF_L, stm32_port->rx_buf,
stm32_port->rx_dma_buf);
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
if (stm32_port->tx_ch)
dma_release_channel(stm32_port->tx_ch);
if (stm32_port->tx_dma_buf)
dma_free_coherent(&pdev->dev,
TX_BUF_L, stm32_port->tx_buf,
stm32_port->tx_dma_buf);
clk_disable_unprepare(stm32_port->clk);
return uart_remove_one_port(&stm32_usart_driver, port); return uart_remove_one_port(&stm32_usart_driver, port);
} }
@ -608,15 +912,21 @@ static int stm32_serial_remove(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_STM32_CONSOLE #ifdef CONFIG_SERIAL_STM32_CONSOLE
static void stm32_console_putchar(struct uart_port *port, int ch) static void stm32_console_putchar(struct uart_port *port, int ch)
{ {
while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE)) struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
cpu_relax(); cpu_relax();
writel_relaxed(ch, port->membase + USART_DR); writel_relaxed(ch, port->membase + ofs->tdr);
} }
static void stm32_console_write(struct console *co, const char *s, unsigned cnt) static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
{ {
struct uart_port *port = &stm32_ports[co->index].port; struct uart_port *port = &stm32_ports[co->index].port;
struct stm32_port *stm32_port = to_stm32_port(port);
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
unsigned long flags; unsigned long flags;
u32 old_cr1, new_cr1; u32 old_cr1, new_cr1;
int locked = 1; int locked = 1;
@ -629,15 +939,16 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt)
else else
spin_lock(&port->lock); spin_lock(&port->lock);
/* Save and disable interrupts */ /* Save and disable interrupts, enable the transmitter */
old_cr1 = readl_relaxed(port->membase + USART_CR1); old_cr1 = readl_relaxed(port->membase + ofs->cr1);
new_cr1 = old_cr1 & ~USART_CR1_IE_MASK; new_cr1 = old_cr1 & ~USART_CR1_IE_MASK;
writel_relaxed(new_cr1, port->membase + USART_CR1); new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit);
writel_relaxed(new_cr1, port->membase + ofs->cr1);
uart_console_write(port, s, cnt, stm32_console_putchar); uart_console_write(port, s, cnt, stm32_console_putchar);
/* Restore interrupt state */ /* Restore interrupt state */
writel_relaxed(old_cr1, port->membase + USART_CR1); writel_relaxed(old_cr1, port->membase + ofs->cr1);
if (locked) if (locked)
spin_unlock(&port->lock); spin_unlock(&port->lock);

Просмотреть файл

@ -0,0 +1,229 @@
/*
* Copyright (C) Maxime Coquelin 2015
* Authors: Maxime Coquelin <mcoquelin.stm32@gmail.com>
* Gerald Baeza <gerald_baeza@yahoo.fr>
* License terms: GNU General Public License (GPL), version 2
*/
#define DRIVER_NAME "stm32-usart"
struct stm32_usart_offsets {
u8 cr1;
u8 cr2;
u8 cr3;
u8 brr;
u8 gtpr;
u8 rtor;
u8 rqr;
u8 isr;
u8 icr;
u8 rdr;
u8 tdr;
};
struct stm32_usart_config {
u8 uart_enable_bit; /* USART_CR1_UE */
bool has_7bits_data;
};
struct stm32_usart_info {
struct stm32_usart_offsets ofs;
struct stm32_usart_config cfg;
};
#define UNDEF_REG ~0
/* Register offsets */
struct stm32_usart_info stm32f4_info = {
.ofs = {
.isr = 0x00,
.rdr = 0x04,
.tdr = 0x04,
.brr = 0x08,
.cr1 = 0x0c,
.cr2 = 0x10,
.cr3 = 0x14,
.gtpr = 0x18,
.rtor = UNDEF_REG,
.rqr = UNDEF_REG,
.icr = UNDEF_REG,
},
.cfg = {
.uart_enable_bit = 13,
.has_7bits_data = false,
}
};
struct stm32_usart_info stm32f7_info = {
.ofs = {
.cr1 = 0x00,
.cr2 = 0x04,
.cr3 = 0x08,
.brr = 0x0c,
.gtpr = 0x10,
.rtor = 0x14,
.rqr = 0x18,
.isr = 0x1c,
.icr = 0x20,
.rdr = 0x24,
.tdr = 0x28,
},
.cfg = {
.uart_enable_bit = 0,
.has_7bits_data = true,
}
};
/* USART_SR (F4) / USART_ISR (F7) */
#define USART_SR_PE BIT(0)
#define USART_SR_FE BIT(1)
#define USART_SR_NF BIT(2)
#define USART_SR_ORE BIT(3)
#define USART_SR_IDLE BIT(4)
#define USART_SR_RXNE BIT(5)
#define USART_SR_TC BIT(6)
#define USART_SR_TXE BIT(7)
#define USART_SR_LBD BIT(8)
#define USART_SR_CTSIF BIT(9)
#define USART_SR_CTS BIT(10) /* F7 */
#define USART_SR_RTOF BIT(11) /* F7 */
#define USART_SR_EOBF BIT(12) /* F7 */
#define USART_SR_ABRE BIT(14) /* F7 */
#define USART_SR_ABRF BIT(15) /* F7 */
#define USART_SR_BUSY BIT(16) /* F7 */
#define USART_SR_CMF BIT(17) /* F7 */
#define USART_SR_SBKF BIT(18) /* F7 */
#define USART_SR_TEACK BIT(21) /* F7 */
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
USART_SR_FE | USART_SR_PE)
/* Dummy bits */
#define USART_SR_DUMMY_RX BIT(16)
/* USART_ICR (F7) */
#define USART_CR_TC BIT(6)
/* USART_DR */
#define USART_DR_MASK GENMASK(8, 0)
/* USART_BRR */
#define USART_BRR_DIV_F_MASK GENMASK(3, 0)
#define USART_BRR_DIV_M_MASK GENMASK(15, 4)
#define USART_BRR_DIV_M_SHIFT 4
/* USART_CR1 */
#define USART_CR1_SBK BIT(0)
#define USART_CR1_RWU BIT(1) /* F4 */
#define USART_CR1_RE BIT(2)
#define USART_CR1_TE BIT(3)
#define USART_CR1_IDLEIE BIT(4)
#define USART_CR1_RXNEIE BIT(5)
#define USART_CR1_TCIE BIT(6)
#define USART_CR1_TXEIE BIT(7)
#define USART_CR1_PEIE BIT(8)
#define USART_CR1_PS BIT(9)
#define USART_CR1_PCE BIT(10)
#define USART_CR1_WAKE BIT(11)
#define USART_CR1_M BIT(12)
#define USART_CR1_M0 BIT(12) /* F7 */
#define USART_CR1_MME BIT(13) /* F7 */
#define USART_CR1_CMIE BIT(14) /* F7 */
#define USART_CR1_OVER8 BIT(15)
#define USART_CR1_DEDT_MASK GENMASK(20, 16) /* F7 */
#define USART_CR1_DEAT_MASK GENMASK(25, 21) /* F7 */
#define USART_CR1_RTOIE BIT(26) /* F7 */
#define USART_CR1_EOBIE BIT(27) /* F7 */
#define USART_CR1_M1 BIT(28) /* F7 */
#define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27))
/* USART_CR2 */
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
#define USART_CR2_ADDM7 BIT(4) /* F7 */
#define USART_CR2_LBDL BIT(5)
#define USART_CR2_LBDIE BIT(6)
#define USART_CR2_LBCL BIT(8)
#define USART_CR2_CPHA BIT(9)
#define USART_CR2_CPOL BIT(10)
#define USART_CR2_CLKEN BIT(11)
#define USART_CR2_STOP_2B BIT(13)
#define USART_CR2_STOP_MASK GENMASK(13, 12)
#define USART_CR2_LINEN BIT(14)
#define USART_CR2_SWAP BIT(15) /* F7 */
#define USART_CR2_RXINV BIT(16) /* F7 */
#define USART_CR2_TXINV BIT(17) /* F7 */
#define USART_CR2_DATAINV BIT(18) /* F7 */
#define USART_CR2_MSBFIRST BIT(19) /* F7 */
#define USART_CR2_ABREN BIT(20) /* F7 */
#define USART_CR2_ABRMOD_MASK GENMASK(22, 21) /* F7 */
#define USART_CR2_RTOEN BIT(23) /* F7 */
#define USART_CR2_ADD_F7_MASK GENMASK(31, 24) /* F7 */
/* USART_CR3 */
#define USART_CR3_EIE BIT(0)
#define USART_CR3_IREN BIT(1)
#define USART_CR3_IRLP BIT(2)
#define USART_CR3_HDSEL BIT(3)
#define USART_CR3_NACK BIT(4)
#define USART_CR3_SCEN BIT(5)
#define USART_CR3_DMAR BIT(6)
#define USART_CR3_DMAT BIT(7)
#define USART_CR3_RTSE BIT(8)
#define USART_CR3_CTSE BIT(9)
#define USART_CR3_CTSIE BIT(10)
#define USART_CR3_ONEBIT BIT(11)
#define USART_CR3_OVRDIS BIT(12) /* F7 */
#define USART_CR3_DDRE BIT(13) /* F7 */
#define USART_CR3_DEM BIT(14) /* F7 */
#define USART_CR3_DEP BIT(15) /* F7 */
#define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */
/* USART_GTPR */
#define USART_GTPR_PSC_MASK GENMASK(7, 0)
#define USART_GTPR_GT_MASK GENMASK(15, 8)
/* USART_RTOR */
#define USART_RTOR_RTO_MASK GENMASK(23, 0) /* F7 */
#define USART_RTOR_BLEN_MASK GENMASK(31, 24) /* F7 */
/* USART_RQR */
#define USART_RQR_ABRRQ BIT(0) /* F7 */
#define USART_RQR_SBKRQ BIT(1) /* F7 */
#define USART_RQR_MMRQ BIT(2) /* F7 */
#define USART_RQR_RXFRQ BIT(3) /* F7 */
#define USART_RQR_TXFRQ BIT(4) /* F7 */
/* USART_ICR */
#define USART_ICR_PECF BIT(0) /* F7 */
#define USART_ICR_FFECF BIT(1) /* F7 */
#define USART_ICR_NCF BIT(2) /* F7 */
#define USART_ICR_ORECF BIT(3) /* F7 */
#define USART_ICR_IDLECF BIT(4) /* F7 */
#define USART_ICR_TCCF BIT(6) /* F7 */
#define USART_ICR_LBDCF BIT(8) /* F7 */
#define USART_ICR_CTSCF BIT(9) /* F7 */
#define USART_ICR_RTOCF BIT(11) /* F7 */
#define USART_ICR_EOBCF BIT(12) /* F7 */
#define USART_ICR_CMCF BIT(17) /* F7 */
#define STM32_SERIAL_NAME "ttyS"
#define STM32_MAX_PORTS 6
#define RX_BUF_L 200 /* dma rx buffer length */
#define RX_BUF_P RX_BUF_L /* dma rx buffer period */
#define TX_BUF_L 200 /* dma tx buffer length */
struct stm32_port {
struct uart_port port;
struct clk *clk;
struct stm32_usart_info *info;
struct dma_chan *rx_ch; /* dma rx channel */
dma_addr_t rx_dma_buf; /* dma rx buffer bus address */
unsigned char *rx_buf; /* dma rx buffer cpu address */
struct dma_chan *tx_ch; /* dma tx channel */
dma_addr_t tx_dma_buf; /* dma tx buffer bus address */
unsigned char *tx_buf; /* dma tx buffer cpu address */
bool tx_dma_busy; /* dma tx busy */
bool hw_flow_control;
};
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
static struct uart_driver stm32_usart_driver;

Просмотреть файл

@ -394,7 +394,7 @@ static int timbuart_verify_port(struct uart_port *port,
return -EINVAL; return -EINVAL;
} }
static struct uart_ops timbuart_ops = { static const struct uart_ops timbuart_ops = {
.tx_empty = timbuart_tx_empty, .tx_empty = timbuart_tx_empty,
.set_mctrl = timbuart_set_mctrl, .set_mctrl = timbuart_set_mctrl,
.get_mctrl = timbuart_get_mctrl, .get_mctrl = timbuart_get_mctrl,

Просмотреть файл

@ -387,7 +387,7 @@ static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
} }
#endif #endif
static struct uart_ops ulite_ops = { static const struct uart_ops ulite_ops = {
.tx_empty = ulite_tx_empty, .tx_empty = ulite_tx_empty,
.set_mctrl = ulite_set_mctrl, .set_mctrl = ulite_set_mctrl,
.get_mctrl = ulite_get_mctrl, .get_mctrl = ulite_get_mctrl,

Просмотреть файл

@ -118,7 +118,7 @@ struct vt8500_port {
* have been allocated as we can't use pdev->id in * have been allocated as we can't use pdev->id in
* devicetree * devicetree
*/ */
static unsigned long vt8500_ports_in_use; static DECLARE_BITMAP(vt8500_ports_in_use, VT8500_MAX_PORTS);
static inline void vt8500_write(struct uart_port *port, unsigned int val, static inline void vt8500_write(struct uart_port *port, unsigned int val,
unsigned int off) unsigned int off)
@ -663,15 +663,15 @@ static int vt8500_serial_probe(struct platform_device *pdev)
if (port < 0) { if (port < 0) {
/* calculate the port id */ /* calculate the port id */
port = find_first_zero_bit(&vt8500_ports_in_use, port = find_first_zero_bit(vt8500_ports_in_use,
sizeof(vt8500_ports_in_use)); VT8500_MAX_PORTS);
} }
if (port >= VT8500_MAX_PORTS) if (port >= VT8500_MAX_PORTS)
return -ENODEV; return -ENODEV;
/* reserve the port id */ /* reserve the port id */
if (test_and_set_bit(port, &vt8500_ports_in_use)) { if (test_and_set_bit(port, vt8500_ports_in_use)) {
/* port already in use - shouldn't really happen */ /* port already in use - shouldn't really happen */
return -EBUSY; return -EBUSY;
} }

Просмотреть файл

@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ #define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ #define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ #define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
/* Control Register Bit Definitions */ /* Control Register Bit Definitions */
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ #define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ #define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ #define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
#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 */
/* /*
* Mode Register: * Mode Register:
@ -126,13 +130,27 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */
#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ #define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */
#define CDNS_UART_RX_IRQS (CDNS_UART_IXR_PARITY | CDNS_UART_IXR_FRAMING | \ /*
CDNS_UART_IXR_OVERRUN | CDNS_UART_IXR_RXTRIG | \ * 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 | \
CDNS_UART_IXR_TOUT) CDNS_UART_IXR_TOUT)
/* Goes in read_status_mask for break detection as the HW doesn't do it*/ /* Goes in read_status_mask for break detection as the HW doesn't do it*/
#define CDNS_UART_IXR_BRK 0x80000000 #define CDNS_UART_IXR_BRK 0x00002000
#define CDNS_UART_RXBS_SUPPORT BIT(1)
/* /*
* Modem Control register: * Modem Control register:
* The read/write Modem Control register controls the interface with the modem * The read/write Modem Control register controls the interface with the modem
@ -172,46 +190,66 @@ struct cdns_uart {
struct clk *pclk; struct clk *pclk;
unsigned int baud; unsigned int baud;
struct notifier_block clk_rate_change_nb; struct notifier_block clk_rate_change_nb;
u32 quirks;
};
struct cdns_platform_data {
u32 quirks;
}; };
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
clk_rate_change_nb); clk_rate_change_nb);
static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus) /**
{ * cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
/* * @dev_id: Id of the UART port
* There is no hardware break detection, so we interpret framing * @isrstatus: The interrupt status register value as read
* error with all-zeros data as a break sequence. Most of the time, * Return: None
* there's another non-zero byte at the end of the sequence.
*/ */
if (isrstatus & CDNS_UART_IXR_FRAMING) { static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
while (!(readl(port->membase + CDNS_UART_SR) & {
CDNS_UART_SR_RXEMPTY)) { struct uart_port *port = (struct uart_port *)dev_id;
if (!readl(port->membase + CDNS_UART_FIFO)) { struct cdns_uart *cdns_uart = port->private_data;
port->read_status_mask |= CDNS_UART_IXR_BRK; unsigned int data;
isrstatus &= ~CDNS_UART_IXR_FRAMING; unsigned int rxbs_status = 0;
} unsigned int status_mask;
} unsigned int framerrprocessed = 0;
writel(CDNS_UART_IXR_FRAMING, port->membase + CDNS_UART_ISR); char status = TTY_NORMAL;
} bool is_rxbs_support;
/* drop byte with parity error if IGNPAR specified */ is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
if (isrstatus & port->ignore_status_mask & CDNS_UART_IXR_PARITY)
isrstatus &= ~(CDNS_UART_IXR_RXTRIG | CDNS_UART_IXR_TOUT); while ((readl(port->membase + CDNS_UART_SR) &
CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
if (is_rxbs_support)
rxbs_status = readl(port->membase + CDNS_UART_RXBS);
data = readl(port->membase + CDNS_UART_FIFO);
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;
continue;
}
}
if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) {
port->icount.brk++;
status = TTY_BREAK;
if (uart_handle_break(port))
continue;
}
isrstatus &= port->read_status_mask; isrstatus &= port->read_status_mask;
isrstatus &= ~port->ignore_status_mask; isrstatus &= ~port->ignore_status_mask;
status_mask = port->read_status_mask;
status_mask &= ~port->ignore_status_mask;
if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG))) if (data &&
return; (port->read_status_mask & CDNS_UART_IXR_BRK)) {
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)) {
u32 data;
char status = TTY_NORMAL;
data = readl(port->membase + CDNS_UART_FIFO);
/* Non-NULL byte after BREAK is garbage (99%) */
if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) {
port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->read_status_mask &= ~CDNS_UART_IXR_BRK;
port->icount.brk++; port->icount.brk++;
if (uart_handle_break(port)) if (uart_handle_break(port))
@ -221,33 +259,54 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
if (uart_handle_sysrq_char(port, data)) if (uart_handle_sysrq_char(port, data))
continue; continue;
port->icount.rx++; 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;
}
} else {
if (isrstatus & CDNS_UART_IXR_PARITY) { if (isrstatus & CDNS_UART_IXR_PARITY) {
port->icount.parity++; port->icount.parity++;
status = TTY_PARITY; status = TTY_PARITY;
} else if (isrstatus & CDNS_UART_IXR_FRAMING) { }
if ((isrstatus & CDNS_UART_IXR_FRAMING) &&
!framerrprocessed) {
port->icount.frame++; port->icount.frame++;
status = TTY_FRAME; status = TTY_FRAME;
} else if (isrstatus & CDNS_UART_IXR_OVERRUN) { }
}
if (isrstatus & CDNS_UART_IXR_OVERRUN) {
port->icount.overrun++; port->icount.overrun++;
tty_insert_flip_char(&port->state->port, 0,
TTY_OVERRUN);
} }
tty_insert_flip_char(&port->state->port, data, status);
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN, isrstatus = 0;
data, status);
} }
spin_unlock(&port->lock);
tty_flip_buffer_push(&port->state->port); tty_flip_buffer_push(&port->state->port);
spin_lock(&port->lock);
} }
static void cdns_uart_handle_tx(struct uart_port *port) /**
* 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)
{ {
struct uart_port *port = (struct uart_port *)dev_id;
unsigned int numbytes; unsigned int numbytes;
if (uart_circ_empty(&port->state->xmit)) { if (uart_circ_empty(&port->state->xmit)) {
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
return; } else {
}
numbytes = port->fifosize; numbytes = port->fifosize;
while (numbytes && !uart_circ_empty(&port->state->xmit) && while (numbytes && !uart_circ_empty(&port->state->xmit) &&
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) { !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
@ -256,8 +315,10 @@ static void cdns_uart_handle_tx(struct uart_port *port)
* and write it to the cdns_uart's TX_FIFO * and write it to the cdns_uart's TX_FIFO
* register. * register.
*/ */
writel(port->state->xmit.buf[port->state->xmit.tail], writel(
port->membase + CDNS_UART_FIFO); port->state->xmit.buf[port->state->xmit.
tail], port->membase + CDNS_UART_FIFO);
port->icount.tx++; port->icount.tx++;
/* /*
@ -265,13 +326,16 @@ static void cdns_uart_handle_tx(struct uart_port *port)
* the buffer if it reaches limit. * the buffer if it reaches limit.
*/ */
port->state->xmit.tail = port->state->xmit.tail =
(port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); (port->state->xmit.tail + 1) &
(UART_XMIT_SIZE - 1);
numbytes--; numbytes--;
} }
if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(
&port->state->xmit) < WAKEUP_CHARS)
uart_write_wakeup(port); uart_write_wakeup(port);
}
} }
/** /**
@ -284,27 +348,24 @@ static void cdns_uart_handle_tx(struct uart_port *port)
static irqreturn_t cdns_uart_isr(int irq, void *dev_id) static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
{ {
struct uart_port *port = (struct uart_port *)dev_id; struct uart_port *port = (struct uart_port *)dev_id;
unsigned long flags;
unsigned int isrstatus; unsigned int isrstatus;
spin_lock_irqsave(&port->lock, flags); spin_lock(&port->lock);
/* Read the interrupt status register to determine which /* Read the interrupt status register to determine which
* interrupt(s) is/are active. * interrupt(s) is/are active and clear them.
*/ */
isrstatus = readl(port->membase + CDNS_UART_ISR); isrstatus = readl(port->membase + CDNS_UART_ISR);
if (isrstatus & CDNS_UART_RX_IRQS)
cdns_uart_handle_rx(port, isrstatus);
if ((isrstatus & CDNS_UART_IXR_TXEMPTY) == CDNS_UART_IXR_TXEMPTY)
cdns_uart_handle_tx(port);
writel(isrstatus, port->membase + CDNS_UART_ISR); writel(isrstatus, port->membase + CDNS_UART_ISR);
/* be sure to release the lock and tty before leaving */ if (isrstatus & CDNS_UART_IXR_TXEMPTY) {
spin_unlock_irqrestore(&port->lock, flags); cdns_uart_handle_tx(dev_id);
isrstatus &= ~CDNS_UART_IXR_TXEMPTY;
}
if (isrstatus & CDNS_UART_IXR_MASK)
cdns_uart_handle_rx(dev_id, isrstatus);
spin_unlock(&port->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -653,6 +714,10 @@ static void cdns_uart_set_termios(struct uart_port *port,
ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST; ctrl_reg |= CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST;
writel(ctrl_reg, port->membase + CDNS_UART_CR); writel(ctrl_reg, port->membase + CDNS_UART_CR);
while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* /*
* Clear the RX disable and TX disable bits and then set the TX enable * 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. * bit and RX enable bit to enable the transmitter and receiver.
@ -736,10 +801,14 @@ static void cdns_uart_set_termios(struct uart_port *port,
*/ */
static int cdns_uart_startup(struct uart_port *port) static int cdns_uart_startup(struct uart_port *port)
{ {
struct cdns_uart *cdns_uart = port->private_data;
bool is_brk_support;
int ret; int ret;
unsigned long flags; unsigned long flags;
unsigned int status = 0; unsigned int status = 0;
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
/* Disable the TX and RX */ /* Disable the TX and RX */
@ -752,6 +821,10 @@ static int cdns_uart_startup(struct uart_port *port)
writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST, writel(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST,
port->membase + CDNS_UART_CR); port->membase + CDNS_UART_CR);
while (readl(port->membase + CDNS_UART_CR) &
(CDNS_UART_CR_TXRST | CDNS_UART_CR_RXRST))
cpu_relax();
/* /*
* Clear the RX disable bit and then set the RX enable bit to enable * Clear the RX disable bit and then set the RX enable bit to enable
* the receiver. * the receiver.
@ -794,6 +867,10 @@ static int cdns_uart_startup(struct uart_port *port)
} }
/* Set the Interrupt Registers with desired interrupts */ /* Set the Interrupt Registers with desired interrupts */
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); writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
return 0; return 0;
@ -993,7 +1070,7 @@ static void cdns_uart_pm(struct uart_port *port, unsigned int state,
} }
} }
static struct uart_ops cdns_uart_ops = { static const struct uart_ops cdns_uart_ops = {
.set_mctrl = cdns_uart_set_mctrl, .set_mctrl = cdns_uart_set_mctrl,
.get_mctrl = cdns_uart_get_mctrl, .get_mctrl = cdns_uart_get_mctrl,
.start_tx = cdns_uart_start_tx, .start_tx = cdns_uart_start_tx,
@ -1088,9 +1165,34 @@ static void __init cdns_early_write(struct console *con, const char *s,
static int __init cdns_early_console_setup(struct earlycon_device *device, static int __init cdns_early_console_setup(struct earlycon_device *device,
const char *opt) const char *opt)
{ {
if (!device->port.membase) struct uart_port *port = &device->port;
if (!port->membase)
return -ENODEV; return -ENODEV;
/* 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);
}
device->con->write = cdns_early_write; device->con->write = cdns_early_write;
return 0; return 0;
@ -1328,6 +1430,18 @@ static int cdns_uart_resume(struct device *device)
static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend, static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
cdns_uart_resume); cdns_uart_resume);
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 },
{}
};
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/** /**
* cdns_uart_probe - Platform driver probe * cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure * @pdev: Pointer to the platform device structure
@ -1340,12 +1454,20 @@ static int cdns_uart_probe(struct platform_device *pdev)
struct uart_port *port; struct uart_port *port;
struct resource *res; struct resource *res;
struct cdns_uart *cdns_uart_data; struct cdns_uart *cdns_uart_data;
const struct of_device_id *match;
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data), cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL); GFP_KERNEL);
if (!cdns_uart_data) if (!cdns_uart_data)
return -ENOMEM; return -ENOMEM;
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;
}
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(cdns_uart_data->pclk)) { if (IS_ERR(cdns_uart_data->pclk)) {
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
@ -1471,14 +1593,6 @@ static int cdns_uart_remove(struct platform_device *pdev)
return rc; return rc;
} }
/* Match table for of_platform binding */
static const struct of_device_id cdns_uart_of_match[] = {
{ .compatible = "xlnx,xuartps", },
{ .compatible = "cdns,uart-r1p8", },
{}
};
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
static struct platform_driver cdns_uart_platform_driver = { static struct platform_driver cdns_uart_platform_driver = {
.probe = cdns_uart_probe, .probe = cdns_uart_probe,
.remove = cdns_uart_remove, .remove = cdns_uart_remove,

Просмотреть файл

@ -1312,12 +1312,12 @@ static int vc_t416_color(struct vc_data *vc, int i,
if (i > vc->vc_npar) if (i > vc->vc_npar)
return i; return i;
if (vc->vc_par[i] == 5 && i < vc->vc_npar) { if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) {
/* 256 colours -- ubiquitous */ /* 256 colours */
i++; i++;
rgb_from_256(vc->vc_par[i], &c); rgb_from_256(vc->vc_par[i], &c);
} else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) { } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) {
/* 24 bit -- extremely rare */ /* 24 bit */
c.r = vc->vc_par[i + 1]; c.r = vc->vc_par[i + 1];
c.g = vc->vc_par[i + 2]; c.g = vc->vc_par[i + 2];
c.b = vc->vc_par[i + 3]; c.b = vc->vc_par[i + 3];
@ -1415,6 +1415,11 @@ static void csi_m(struct vc_data *vc)
(vc->vc_color & 0x0f); (vc->vc_color & 0x0f);
break; break;
default: default:
if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
if (vc->vc_par[i] < 100)
vc->vc_intensity = 2;
vc->vc_par[i] -= 60;
}
if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37) if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
vc->vc_color = color_table[vc->vc_par[i] - 30] vc->vc_color = color_table[vc->vc_par[i] - 30]
| (vc->vc_color & 0xf0); | (vc->vc_color & 0xf0);

Просмотреть файл

@ -272,13 +272,8 @@ static int mknod_ptmx(struct super_block *sb)
struct dentry *root = sb->s_root; struct dentry *root = sb->s_root;
struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_fs_info *fsi = DEVPTS_SB(sb);
struct pts_mount_opts *opts = &fsi->mount_opts; struct pts_mount_opts *opts = &fsi->mount_opts;
kuid_t root_uid; kuid_t ptmx_uid = current_fsuid();
kgid_t root_gid; kgid_t ptmx_gid = current_fsgid();
root_uid = make_kuid(current_user_ns(), 0);
root_gid = make_kgid(current_user_ns(), 0);
if (!uid_valid(root_uid) || !gid_valid(root_gid))
return -EINVAL;
inode_lock(d_inode(root)); inode_lock(d_inode(root));
@ -309,8 +304,8 @@ static int mknod_ptmx(struct super_block *sb)
mode = S_IFCHR|opts->ptmxmode; mode = S_IFCHR|opts->ptmxmode;
init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2)); init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
inode->i_uid = root_uid; inode->i_uid = ptmx_uid;
inode->i_gid = root_gid; inode->i_gid = ptmx_gid;
d_add(dentry, inode); d_add(dentry, inode);
@ -336,7 +331,6 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_fs_info *fsi = DEVPTS_SB(sb);
struct pts_mount_opts *opts = &fsi->mount_opts; struct pts_mount_opts *opts = &fsi->mount_opts;
sync_filesystem(sb);
err = parse_mount_options(data, PARSE_REMOUNT, opts); err = parse_mount_options(data, PARSE_REMOUNT, opts);
/* /*
@ -395,6 +389,7 @@ static int
devpts_fill_super(struct super_block *s, void *data, int silent) devpts_fill_super(struct super_block *s, void *data, int silent)
{ {
struct inode *inode; struct inode *inode;
int error;
s->s_iflags &= ~SB_I_NODEV; s->s_iflags &= ~SB_I_NODEV;
s->s_blocksize = 1024; s->s_blocksize = 1024;
@ -403,10 +398,16 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
s->s_op = &devpts_sops; s->s_op = &devpts_sops;
s->s_time_gran = 1; s->s_time_gran = 1;
error = -ENOMEM;
s->s_fs_info = new_pts_fs_info(s); s->s_fs_info = new_pts_fs_info(s);
if (!s->s_fs_info) if (!s->s_fs_info)
goto fail; goto fail;
error = parse_mount_options(data, PARSE_MOUNT, &DEVPTS_SB(s)->mount_opts);
if (error)
goto fail;
error = -ENOMEM;
inode = new_inode(s); inode = new_inode(s);
if (!inode) if (!inode)
goto fail; goto fail;
@ -418,13 +419,21 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
set_nlink(inode, 2); set_nlink(inode, 2);
s->s_root = d_make_root(inode); s->s_root = d_make_root(inode);
if (s->s_root) if (!s->s_root) {
return 0;
pr_err("get root dentry failed\n"); pr_err("get root dentry failed\n");
goto fail;
}
error = mknod_ptmx(s);
if (error)
goto fail_dput;
return 0;
fail_dput:
dput(s->s_root);
s->s_root = NULL;
fail: fail:
return -ENOMEM; return error;
} }
/* /*
@ -436,42 +445,14 @@ fail:
static struct dentry *devpts_mount(struct file_system_type *fs_type, static struct dentry *devpts_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data) int flags, const char *dev_name, void *data)
{ {
int error; return mount_nodev(fs_type, flags, data, devpts_fill_super);
struct pts_mount_opts opts;
struct super_block *s;
error = parse_mount_options(data, PARSE_MOUNT, &opts);
if (error)
return ERR_PTR(error);
s = sget(fs_type, NULL, set_anon_super, flags, NULL);
if (IS_ERR(s))
return ERR_CAST(s);
if (!s->s_root) {
error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error)
goto out_undo_sget;
s->s_flags |= MS_ACTIVE;
}
memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts));
error = mknod_ptmx(s);
if (error)
goto out_undo_sget;
return dget(s->s_root);
out_undo_sget:
deactivate_locked_super(s);
return ERR_PTR(error);
} }
static void devpts_kill_sb(struct super_block *sb) static void devpts_kill_sb(struct super_block *sb)
{ {
struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_fs_info *fsi = DEVPTS_SB(sb);
if (fsi)
ida_destroy(&fsi->allocated_ptys); ida_destroy(&fsi->allocated_ptys);
kfree(fsi); kfree(fsi);
kill_litter_super(sb); kill_litter_super(sb);

Просмотреть файл

@ -1099,4 +1099,10 @@ extern bool acpi_has_watchdog(void);
static inline bool acpi_has_watchdog(void) { return false; } static inline bool acpi_has_watchdog(void) { return false; }
#endif #endif
#ifdef CONFIG_ACPI_SPCR_TABLE
int parse_spcr(bool earlycon);
#else
static inline int parse_spcr(bool earlycon) { return 0; }
#endif
#endif /*_LINUX_ACPI_H*/ #endif /*_LINUX_ACPI_H*/

Просмотреть файл

@ -53,8 +53,14 @@ enum amba_vendor {
AMBA_VENDOR_ST = 0x80, AMBA_VENDOR_ST = 0x80,
AMBA_VENDOR_QCOM = 0x51, AMBA_VENDOR_QCOM = 0x51,
AMBA_VENDOR_LSI = 0xb6, AMBA_VENDOR_LSI = 0xb6,
AMBA_VENDOR_LINUX = 0xfe, /* This value is not official */
}; };
/* This is used to generate pseudo-ID for AMBA device */
#define AMBA_LINUX_ID(conf, rev, part) \
(((conf) & 0xff) << 24 | ((rev) & 0xf) << 20 | \
AMBA_VENDOR_LINUX << 12 | ((part) & 0xfff))
extern struct bus_type amba_bustype; extern struct bus_type amba_bustype;
#define to_amba_device(d) container_of(d, struct amba_device, dev) #define to_amba_device(d) container_of(d, struct amba_device, dev)

Просмотреть файл

@ -104,6 +104,15 @@
#define UART01x_FR_CTS 0x001 #define UART01x_FR_CTS 0x001
#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) #define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY)
/*
* Some bits of Flag Register on ZTE device have different position from
* standard ones.
*/
#define ZX_UART01x_FR_BUSY 0x100
#define ZX_UART01x_FR_DSR 0x008
#define ZX_UART01x_FR_CTS 0x002
#define ZX_UART011_FR_RI 0x001
#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ #define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */
#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */ #define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */
#define UART011_CR_OUT2 0x2000 /* OUT2 */ #define UART011_CR_OUT2 0x2000 /* OUT2 */

Просмотреть файл

@ -118,6 +118,8 @@
#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ #define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */
#define ATMEL_US_CD GENMASK(15, 0) /* Clock Divider */ #define ATMEL_US_CD GENMASK(15, 0) /* Clock Divider */
#define ATMEL_US_FP_OFFSET 16 /* Fractional Part */
#define ATMEL_US_FP_MASK 0x7
#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register for USART */ #define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register for USART */
#define ATMEL_UA_RTOR 0x28 /* Receiver Time-out Register for UART */ #define ATMEL_UA_RTOR 0x28 /* Receiver Time-out Register for UART */

Просмотреть файл

@ -40,8 +40,13 @@ struct dw_dma_chip {
}; };
/* Export to the platform drivers */ /* Export to the platform drivers */
#if IS_ENABLED(CONFIG_DW_DMAC_CORE)
int dw_dma_probe(struct dw_dma_chip *chip); int dw_dma_probe(struct dw_dma_chip *chip);
int dw_dma_remove(struct dw_dma_chip *chip); int dw_dma_remove(struct dw_dma_chip *chip);
#else
static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
#endif /* CONFIG_DW_DMAC_CORE */
/* DMA API extensions */ /* DMA API extensions */
struct dw_desc; struct dw_desc;

Просмотреть файл

@ -41,8 +41,7 @@ struct hsu_dma_chip {
/* Export to the internal users */ /* Export to the internal users */
int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr, int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
u32 *status); u32 *status);
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr, u32 status);
u32 status);
/* Export to the platform drivers */ /* Export to the platform drivers */
int hsu_dma_probe(struct hsu_dma_chip *chip); int hsu_dma_probe(struct hsu_dma_chip *chip);
@ -53,10 +52,10 @@ static inline int hsu_dma_get_status(struct hsu_dma_chip *chip,
{ {
return 0; return 0;
} }
static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, static inline int hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
unsigned short nr, u32 status) u32 status)
{ {
return IRQ_NONE; return 0;
} }
static inline int hsu_dma_probe(struct hsu_dma_chip *chip) { return -ENODEV; } static inline int hsu_dma_probe(struct hsu_dma_chip *chip) { return -ENODEV; }
static inline int hsu_dma_remove(struct hsu_dma_chip *chip) { return 0; } static inline int hsu_dma_remove(struct hsu_dma_chip *chip) { return 0; }

Просмотреть файл

@ -14,6 +14,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h>
/* Definitions used by the flattened device tree */ /* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* marker */ #define OF_DT_HEADER 0xd00dfeed /* marker */
@ -66,6 +67,7 @@ extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data); int depth, void *data);
extern int early_init_dt_scan_memory(unsigned long node, const char *uname, extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data); int depth, void *data);
extern int early_init_dt_scan_chosen_stdout(void);
extern void early_init_fdt_scan_reserved_mem(void); extern void early_init_fdt_scan_reserved_mem(void);
extern void early_init_fdt_reserve_self(void); extern void early_init_fdt_reserve_self(void);
extern void early_init_dt_add_memory_arch(u64 base, u64 size); extern void early_init_dt_add_memory_arch(u64 base, u64 size);
@ -94,6 +96,7 @@ extern void early_get_first_memblock_info(void *, phys_addr_t *);
extern u64 of_flat_dt_translate_address(unsigned long node); extern u64 of_flat_dt_translate_address(unsigned long node);
extern void of_fdt_limit_memory(int limit); extern void of_fdt_limit_memory(int limit);
#else /* CONFIG_OF_FLATTREE */ #else /* CONFIG_OF_FLATTREE */
static inline int early_init_dt_scan_chosen_stdout(void) { return -ENODEV; }
static inline void early_init_fdt_scan_reserved_mem(void) {} static inline void early_init_fdt_scan_reserved_mem(void) {}
static inline void early_init_fdt_reserve_self(void) {} static inline void early_init_fdt_reserve_self(void) {}
static inline const char *of_flat_dt_get_machine_name(void) { return NULL; } static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }

Просмотреть файл

@ -23,6 +23,7 @@
* @dst_id: dst request line * @dst_id: dst request line
* @m_master: memory master for transfers on allocated channel * @m_master: memory master for transfers on allocated channel
* @p_master: peripheral master for transfers on allocated channel * @p_master: peripheral master for transfers on allocated channel
* @hs_polarity:set active low polarity of handshake interface
*/ */
struct dw_dma_slave { struct dw_dma_slave {
struct device *dma_dev; struct device *dma_dev;
@ -30,6 +31,7 @@ struct dw_dma_slave {
u8 dst_id; u8 dst_id;
u8 m_master; u8 m_master;
u8 p_master; u8 p_master;
bool hs_polarity;
}; };
/** /**
@ -38,6 +40,7 @@ struct dw_dma_slave {
* @is_private: The device channels should be marked as private and not for * @is_private: The device channels should be marked as private and not for
* by the general purpose DMA channel allocator. * by the general purpose DMA channel allocator.
* @is_memcpy: The device channels do support memory-to-memory transfers. * @is_memcpy: The device channels do support memory-to-memory transfers.
* @is_nollp: The device channels does not support multi block transfers.
* @chan_allocation_order: Allocate channels starting from 0 or 7 * @chan_allocation_order: Allocate channels starting from 0 or 7
* @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0.
* @block_size: Maximum block size supported by the controller * @block_size: Maximum block size supported by the controller
@ -49,6 +52,7 @@ struct dw_dma_platform_data {
unsigned int nr_channels; unsigned int nr_channels;
bool is_private; bool is_private;
bool is_memcpy; bool is_memcpy;
bool is_nollp;
#define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ #define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */
#define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ #define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */
unsigned char chan_allocation_order; unsigned char chan_allocation_order;

Просмотреть файл

@ -367,14 +367,21 @@ extern const struct earlycon_id __earlycon_table_end[];
#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) #define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn)
extern int setup_earlycon(char *buf);
extern int of_setup_earlycon(const struct earlycon_id *match, extern int of_setup_earlycon(const struct earlycon_id *match,
unsigned long node, unsigned long node,
const char *options); const char *options);
#ifdef CONFIG_SERIAL_EARLYCON
extern bool earlycon_init_is_deferred __initdata;
int setup_earlycon(char *buf);
#else
static const bool earlycon_init_is_deferred;
static inline int setup_earlycon(char *buf) { return 0; }
#endif
struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct uart_port *uart_get_console(struct uart_port *ports, int nr,
struct console *c); struct console *c);
int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
char **options); char **options);
void uart_parse_options(char *options, int *baud, int *parity, int *bits, void uart_parse_options(char *options, int *baud, int *parity, int *bits,
int *flow); int *flow);
@ -412,7 +419,7 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
static inline int uart_tx_stopped(struct uart_port *port) static inline int uart_tx_stopped(struct uart_port *port)
{ {
struct tty_struct *tty = port->state->port.tty; struct tty_struct *tty = port->state->port.tty;
if (tty->stopped || port->hw_stopped) if ((tty && tty->stopped) || port->hw_stopped)
return 1; return 1;
return 0; return 0;
} }

Просмотреть файл

@ -376,5 +376,13 @@
#define UART_EXAR_TXTRG 0x0a /* Tx FIFO trigger level write-only */ #define UART_EXAR_TXTRG 0x0a /* Tx FIFO trigger level write-only */
#define UART_EXAR_RXTRG 0x0b /* Rx FIFO trigger level write-only */ #define UART_EXAR_RXTRG 0x0b /* Rx FIFO trigger level write-only */
/*
* These are definitions for the Altera ALTR_16550_F32/F64/F128
* Normalized from 0x100 to 0x40 because of shift by 2 (32 bit regs).
*/
#define UART_ALTR_AFR 0x40 /* Additional Features Register */
#define UART_ALTR_EN_TXFIFO_LW 0x01 /* Enable the TX FIFO Low Watermark */
#define UART_ALTR_TX_LOW 0x41 /* Tx FIFO Low Watermark */
#endif /* _LINUX_SERIAL_REG_H */ #endif /* _LINUX_SERIAL_REG_H */