* serial drivers polishing
From: Enrico Weigelt, metux IT consult @ 2019-04-27 12:51 UTC (permalink / raw)
To: linux-kernel
Cc: gregkh, andrew, andriy.shevchenko, macro, vz, slemieux.tyco,
khilman, liviu.dudau, sudeep.holla, lorenzo.pieralisi, davem,
jacmet, linux, matthias.bgg, linux-mips, linux-serial, linux-ia64,
linux-amlogic, linuxppc-dev, sparclinux
Hello folks,
here's another attempt of polishing the serial drivers:
* lots of minor cleanups to make checkpatch happier
(eg. formatting, includes, inttypes, ...)
* use appropriate logging helpers instead of printk()
* consequent use of mapsize/mapbase fields:
the basic idea is, all drivers should fill mapbase/mapbase fields at
init time and later only use those fields, instead of hardcoded values
(later on, we can add generic helpers for the map/unmap stuff, etc)
* untwisting serial8250_port_size() at all:
move the iomem size probing to initialization time, move out some
platform specific magic to corresponding platform code, etc.
Unfortunately, I don't have the actual hardware to really test all
the code, so please let me know if there's something broken in here.
have fun,
--mtx
^ permalink raw reply
* Re: [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Enrico Weigelt, metux IT consult @ 2019-04-27 11:57 UTC (permalink / raw)
To: Esben Haabendal, Andy Shevchenko
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
He Zhe, Jisheng Zhang, Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <87tvejakot.fsf@haabendal.dk>
On 27.04.19 10:58, Esben Haabendal wrote:
Hi folks,
> That said, the purpose of UPF_BOOT_AUTOCONF (for 8250 driver) is to> request and map the register memory. So when that is already done by>
the parent MFD driver, I think it is silly to workaround problems
caused> by UPF_BOOT_AUTOCONF being force setted, when it really shouldn't.
I tend to agree. Maybe we should give serial8250_register_8250_port()
some flags for controlling this, or add another function for those
cases.
A minimal-invasive approach could be introducing an
serial8250_register_8250_port_ext() with extra parameters, and let
serial8250_register_8250_port() just call it.
By the way: the mem-mapping code pathes in serial8250 are a bit strange
anyways, eg. serial8250_port_size() is always called when map/unmap is
done, and this function does special logic for certain devices.
IMHO, it this should be called only once on device init and later just
use the already computed value:
https://github.com/metux/linux/commit/7ec63b699c910228b92cfb27eb8edfda90fdfd63
(haven't sent this queue yet, but feel free to cherry-pick if you like)
--mtx
--
Enrico Weigelt, metux IT consult
Free software and Linux embedded engineering
info@metux.net -- +49-151-27565287
^ permalink raw reply
* [PATCH v2] tty: serial: 8250: Fix type field in format string
From: Hao Lee @ 2019-04-27 9:19 UTC (permalink / raw)
To: gregkh; +Cc: jslaby, haolee.swjtu, linux-serial, linux-kernel
The dev_dbg statement should print the value of uart.port.mapbase instead
of its address. Besides that, uart.port.irq and uart.port.iotype are all
unsigned types, so using %u is more appropriate.
Signed-off-by: Hao Lee <haolee.swjtu@gmail.com>
---
drivers/tty/serial/8250/8250_pnp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 431e69a5a6a0..9dea11baf479 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -462,8 +462,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
return -ENODEV;
dev_dbg(&dev->dev,
- "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
- uart.port.iobase, &uart.port.mapbase,
+ "Setup PNP port: port %#lx, mem %#lx, irq %u, type %u\n",
+ uart.port.iobase, uart.port.mapbase,
uart.port.irq, uart.port.iotype);
if (flags & CIR_PORT) {
--
2.14.5
^ permalink raw reply related
* Re: [PATCH] tty: serial: 8250: Fix type field in format string
From: Greg KH @ 2019-04-27 8:59 UTC (permalink / raw)
To: Hao Lee; +Cc: jslaby, linux-serial, linux-kernel
In-Reply-To: <CA+PpKPkdpkC9nqL4NzKK=5Xys0H6-ZBAUmjE91WSRg=b1LyiOQ@mail.gmail.com>
On Sat, Apr 27, 2019 at 04:41:44PM +0800, Hao Lee wrote:
> On Sat, 27 Apr 2019 at 16:09, Greg KH <gregkh@linuxfoundation.org> wrote:
> >
> > On Sat, Apr 27, 2019 at 04:00:15PM +0800, Hao Lee wrote:
> > > The variable type and the type field is inconsistent.
> >
> > In what way? Please be very specific when you resend this.
>
> The main problem is the dev_dbg statement should print the value of
> uart.port.mapbase instead of its address. Besides that, uart.port.irq
> and uart.port.iotype are all unsigned types, so using %u is more
> appropriate.
Wonderful, put all of that in the changelog text and please resend.
What you submitted is not sufficient.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Esben Haabendal @ 2019-04-27 8:58 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
He Zhe, Jisheng Zhang, Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <20190426215103.GD9224@smile.fi.intel.com>
Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
> On Fri, Apr 26, 2019 at 06:54:05PM +0200, Esben Haabendal wrote:
>> Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
>> > On Fri, Apr 26, 2019 at 10:40:37AM +0200, Esben Haabendal wrote:
>> >> With serial8250_register_8250_port() forcing UPF_BOOT_AUTOCONF bit on, it
>> >> is not possible to register a port without having
>> >> serial8250_request_std_resource() called.
>> >>
>> >> For adding a 8250 port to an MFD device, this is problematic, as the
>> >> request_mem_region() call will fail, as the MFD device (and rightly so)
>> >> has requested the region. For this case, the 8250 port should accept
>> >> having passed mapbase and membase, and just use that.
>> >
>> > You need to simple set port type and use UPF_FIXED_TYPE.
>> > No need for this patch.
>>
>> The reason for this patch is to be able to do exactly that (set port
>> type and UPF_FIXED_TYPE) without having UPF_BOOT_AUTOCONF added.
>>
>> In the current serial8250_register_8250_port() there is:
>>
>> uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
>>
>> So, even though I set UPF_FIXED_TYPE, I get
>> UPF_FIXED_TYPE|UPF_BOOT_AUTOCONF.
>
> Yes.
>
>> So I need this patch.
>
> Why? I don't see any problems to have these flags set.
The problem with having UPF_BOOT_AUTOCONF is the call to
serial8250_request_std_resource(). It calls request_mem_region(), which
fails if the MFD driver already have requested the memory region for the
MFD device. And I believe that is a valid thing to do.
To workaround this, I first thought I could just avoid setting
port->mapbase, causing serial8250_request_std_resource() to be a no-op.
But this breaks with more than one UART port, as uart_match_port() will
match the same line for all such UART ports, causing all but the last
one to be removed.
That said, the purpose of UPF_BOOT_AUTOCONF (for 8250 driver) is to
request and map the register memory. So when that is already done by
the parent MFD driver, I think it is silly to workaround problems caused
by UPF_BOOT_AUTOCONF being force setted, when it really shouldn't.
> Moreover, some drivers
> are used as MFD counterparts with exactly same bits set.
>
>> I think it is unfortunate that UPF_BOOT_AUTOCONF is or'ed to flags like
>> that, but changing that will surely break stuff.
>
> True.
^ permalink raw reply
* Re: [PATCH] tty: serial: 8250: Fix type field in format string
From: Hao Lee @ 2019-04-27 8:41 UTC (permalink / raw)
To: Greg KH; +Cc: jslaby, linux-serial, linux-kernel
In-Reply-To: <20190427080942.GA8218@kroah.com>
On Sat, 27 Apr 2019 at 16:09, Greg KH <gregkh@linuxfoundation.org> wrote:
>
> On Sat, Apr 27, 2019 at 04:00:15PM +0800, Hao Lee wrote:
> > The variable type and the type field is inconsistent.
>
> In what way? Please be very specific when you resend this.
The main problem is the dev_dbg statement should print the value of
uart.port.mapbase instead of its address. Besides that, uart.port.irq
and uart.port.iotype are all unsigned types, so using %u is more
appropriate.
Regards,
Hao Lee
^ permalink raw reply
* Re: [PATCH] tty: serial: 8250: Fix type field in format string
From: Greg KH @ 2019-04-27 8:09 UTC (permalink / raw)
To: Hao Lee; +Cc: jslaby, linux-serial, linux-kernel
In-Reply-To: <20190427080013.GA3624@haolee.io>
On Sat, Apr 27, 2019 at 04:00:15PM +0800, Hao Lee wrote:
> The variable type and the type field is inconsistent.
In what way? Please be very specific when you resend this.
thanks,
greg k-h
^ permalink raw reply
* [PATCH] tty: serial: 8250: Fix type field in format string
From: Hao Lee @ 2019-04-27 8:00 UTC (permalink / raw)
To: gregkh; +Cc: jslaby, haolee.swjtu, linux-serial, linux-kernel
The variable type and the type field is inconsistent.
Signed-off-by: Hao Lee <haolee.swjtu@gmail.com>
---
drivers/tty/serial/8250/8250_pnp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 431e69a5a6a0..9dea11baf479 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -462,8 +462,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
return -ENODEV;
dev_dbg(&dev->dev,
- "Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
- uart.port.iobase, &uart.port.mapbase,
+ "Setup PNP port: port %#lx, mem %#lx, irq %u, type %u\n",
+ uart.port.iobase, uart.port.mapbase,
uart.port.irq, uart.port.iotype);
if (flags & CIR_PORT) {
--
2.14.5
^ permalink raw reply related
* [PATCH 4/4] serial: 8250-mtk: modify uart DMA rx
From: Long Cheng @ 2019-04-27 3:36 UTC (permalink / raw)
To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
Sean Wang, Nicolas Boichat, Matthias Brugger
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu, Long Cheng
In-Reply-To: <1556336193-15198-1-git-send-email-long.cheng@mediatek.com>
Modify uart rx and complete for DMA.
Signed-off-by: Long Cheng <long.cheng@mediatek.com>
---
drivers/tty/serial/8250/8250_mtk.c | 53 ++++++++++++++++--------------------
1 file changed, 23 insertions(+), 30 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index c1fdbc0..04081a6 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -30,7 +30,6 @@
#define MTK_UART_DMA_EN_TX 0x2
#define MTK_UART_DMA_EN_RX 0x5
-#define MTK_UART_TX_SIZE UART_XMIT_SIZE
#define MTK_UART_RX_SIZE 0x8000
#define MTK_UART_TX_TRIGGER 1
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
@@ -64,28 +63,30 @@ static void mtk8250_dma_rx_complete(void *param)
struct mtk8250_data *data = up->port.private_data;
struct tty_port *tty_port = &up->port.state->port;
struct dma_tx_state state;
+ int copied, cnt, tmp;
unsigned char *ptr;
- int copied;
- dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
+ if (data->rx_status == DMA_RX_SHUTDOWN)
+ return;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+ cnt = dma->rx_size - state.residue;
+ tmp = cnt;
- if (data->rx_status == DMA_RX_SHUTDOWN)
- return;
+ if ((data->rx_pos + cnt) > dma->rx_size)
+ tmp = dma->rx_size - data->rx_pos;
- if ((data->rx_pos + state.residue) <= dma->rx_size) {
- ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
- copied = tty_insert_flip_string(tty_port, ptr, state.residue);
- } else {
- ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
- copied = tty_insert_flip_string(tty_port, ptr,
- dma->rx_size - data->rx_pos);
+ ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
+ copied = tty_insert_flip_string(tty_port, ptr, tmp);
+ data->rx_pos += tmp;
+
+ if (cnt > tmp) {
ptr = (unsigned char *)(dma->rx_buf);
- copied += tty_insert_flip_string(tty_port, ptr,
- data->rx_pos + state.residue - dma->rx_size);
+ tmp = cnt - tmp;
+ copied += tty_insert_flip_string(tty_port, ptr, tmp);
+ data->rx_pos = tmp;
}
+
up->port.icount.rx += copied;
tty_flip_buffer_push(tty_port);
@@ -96,9 +97,7 @@ static void mtk8250_dma_rx_complete(void *param)
static void mtk8250_rx_dma(struct uart_8250_port *up)
{
struct uart_8250_dma *dma = up->dma;
- struct mtk8250_data *data = up->port.private_data;
struct dma_async_tx_descriptor *desc;
- struct dma_tx_state state;
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
@@ -113,12 +112,6 @@ static void mtk8250_rx_dma(struct uart_8250_port *up)
dma->rx_cookie = dmaengine_submit(desc);
- dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
- data->rx_pos = state.residue;
-
- dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
- dma->rx_size, DMA_FROM_DEVICE);
-
dma_async_issue_pending(dma->rxchan);
}
@@ -131,13 +124,13 @@ static void mtk8250_dma_enable(struct uart_8250_port *up)
if (data->rx_status != DMA_RX_START)
return;
- dma->rxconf.direction = DMA_DEV_TO_MEM;
- dma->rxconf.src_addr_width = dma->rx_size / 1024;
- dma->rxconf.src_addr = dma->rx_addr;
+ dma->rxconf.direction = DMA_DEV_TO_MEM;
+ dma->rxconf.src_port_window_size = dma->rx_size;
+ dma->rxconf.src_addr = dma->rx_addr;
- dma->txconf.direction = DMA_MEM_TO_DEV;
- dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
- dma->txconf.dst_addr = dma->tx_addr;
+ dma->txconf.direction = DMA_MEM_TO_DEV;
+ dma->txconf.dst_port_window_size = UART_XMIT_SIZE;
+ dma->txconf.dst_addr = dma->tx_addr;
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
@@ -217,7 +210,7 @@ static void mtk8250_shutdown(struct uart_port *port)
* Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
*
* We need to recalcualte the quot register, as the claculation depends
- * on the vaule in the highspeed register.
+ * on the value in the highspeed register.
*
* Some baudrates are not supported by the chip, so we use the next
* lower rate supported and update termios c_flag.
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/4] dt-bindings: dma: uart: rename binding
From: Long Cheng @ 2019-04-27 3:36 UTC (permalink / raw)
To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
Sean Wang, Nicolas Boichat, Matthias Brugger
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu, Long Cheng
In-Reply-To: <1556336193-15198-1-git-send-email-long.cheng@mediatek.com>
The filename matches mtk-uart-apdma.c.
So using "mtk-uart-apdma.txt" should be better.
And add some property.
Signed-off-by: Long Cheng <long.cheng@mediatek.com>
---
.../devicetree/bindings/dma/8250_mtk_dma.txt | 33 ------------
.../devicetree/bindings/dma/mtk-uart-apdma.txt | 55 ++++++++++++++++++++
2 files changed, 55 insertions(+), 33 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
create mode 100644 Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
diff --git a/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt b/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
deleted file mode 100644
index 3fe0961..0000000
--- a/Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-* Mediatek UART APDMA Controller
-
-Required properties:
-- compatible should contain:
- * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
- * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
-
-- reg: The base address of the APDMA register bank.
-
-- interrupts: A single interrupt specifier.
-
-- clocks : Must contain an entry for each entry in clock-names.
- See ../clocks/clock-bindings.txt for details.
-- clock-names: The APDMA clock for register accesses
-
-Examples:
-
- apdma: dma-controller@11000380 {
- compatible = "mediatek,mt2712-uart-dma";
- reg = <0 0x11000380 0 0x400>;
- interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 65 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 66 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 67 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 68 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 69 IRQ_TYPE_LEVEL_LOW>,
- <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&pericfg CLK_PERI_AP_DMA>;
- clock-names = "apdma";
- #dma-cells = <1>;
- };
-
diff --git a/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt b/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
new file mode 100644
index 0000000..e0424b3
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
@@ -0,0 +1,55 @@
+* Mediatek UART APDMA Controller
+
+Required properties:
+- compatible should contain:
+ * "mediatek,mt2712-uart-dma" for MT2712 compatible APDMA
+ * "mediatek,mt6577-uart-dma" for MT6577 and all of the above
+
+- reg: The base address of the APDMA register bank.
+
+- interrupts: A single interrupt specifier.
+ One interrupt per dma-requests, or 8 if no dma-requests property is present
+
+- dma-requests: The number of DMA channels
+
+- clocks : Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names: The APDMA clock for register accesses
+
+- mediatek,dma-33bits: Present if the DMA requires support
+
+Examples:
+
+ apdma: dma-controller@11000400 {
+ compatible = "mediatek,mt2712-uart-dma";
+ reg = <0 0x11000400 0 0x80>,
+ <0 0x11000480 0 0x80>,
+ <0 0x11000500 0 0x80>,
+ <0 0x11000580 0 0x80>,
+ <0 0x11000600 0 0x80>,
+ <0 0x11000680 0 0x80>,
+ <0 0x11000700 0 0x80>,
+ <0 0x11000780 0 0x80>,
+ <0 0x11000800 0 0x80>,
+ <0 0x11000880 0 0x80>,
+ <0 0x11000900 0 0x80>,
+ <0 0x11000980 0 0x80>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+ dma-requests = <12>;
+ clocks = <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "apdma";
+ mediatek,dma-33bits;
+ #dma-cells = <1>;
+ };
+
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/4] arm: dts: mt2712: add uart APDMA to device tree
From: Long Cheng @ 2019-04-27 3:36 UTC (permalink / raw)
To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
Sean Wang, Nicolas Boichat, Matthias Brugger
Cc: Zhenbao Liu, devicetree, srv_heupstream, Greg Kroah-Hartman,
Sean Wang, linux-kernel, YT Shen, Long Cheng, linux-mediatek,
linux-serial, Jiri Slaby, dmaengine, Yingjoe Chen, Dan Williams,
linux-arm-kernel
In-Reply-To: <1556336193-15198-1-git-send-email-long.cheng@mediatek.com>
1. add uart APDMA controller device node
2. add uart 0/1/2/3/4/5 DMA function
Signed-off-by: Long Cheng <long.cheng@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 51 +++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
index 976d92a..f1e419e 100644
--- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
@@ -300,6 +300,9 @@
interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 10
+ &apdma 11>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -369,6 +372,39 @@
(GIC_CPU_MASK_RAW(0x13) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ apdma: dma-controller@11000400 {
+ compatible = "mediatek,mt2712-uart-dma",
+ "mediatek,mt6577-uart-dma";
+ reg = <0 0x11000400 0 0x80>,
+ <0 0x11000480 0 0x80>,
+ <0 0x11000500 0 0x80>,
+ <0 0x11000580 0 0x80>,
+ <0 0x11000600 0 0x80>,
+ <0 0x11000680 0 0x80>,
+ <0 0x11000700 0 0x80>,
+ <0 0x11000780 0 0x80>,
+ <0 0x11000800 0 0x80>,
+ <0 0x11000880 0 0x80>,
+ <0 0x11000900 0 0x80>,
+ <0 0x11000980 0 0x80>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
+ dma-requests = <12>;
+ clocks = <&pericfg CLK_PERI_AP_DMA>;
+ clock-names = "apdma";
+ #dma-cells = <1>;
+ };
+
auxadc: adc@11001000 {
compatible = "mediatek,mt2712-auxadc";
reg = <0 0x11001000 0 0x1000>;
@@ -385,6 +421,9 @@
interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 0
+ &apdma 1>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -395,6 +434,9 @@
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 2
+ &apdma 3>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -405,6 +447,9 @@
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 4
+ &apdma 5>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -415,6 +460,9 @@
interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 6
+ &apdma 7>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -629,6 +677,9 @@
interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_LOW>;
clocks = <&baud_clk>, <&sys_clk>;
clock-names = "baud", "bus";
+ dmas = <&apdma 8
+ &apdma 9>;
+ dma-names = "tx", "rx";
status = "disabled";
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/4] dmaengine: mediatek: Add MediaTek UART APDMA support
From: Long Cheng @ 2019-04-27 3:36 UTC (permalink / raw)
To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
Sean Wang, Nicolas Boichat, Matthias Brugger
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu, Long Cheng
In-Reply-To: <1556336193-15198-1-git-send-email-long.cheng@mediatek.com>
Add 8250 UART APDMA to support MediaTek UART. If MediaTek UART is
enabled by SERIAL_8250_MT6577, and we can enable this driver to offload
the UART device moving bytes.
Signed-off-by: Long Cheng <long.cheng@mediatek.com>
Signed-off-by: Sean Wang <sean.wang@mediatek.com>
---
drivers/dma/mediatek/Kconfig | 11 +
drivers/dma/mediatek/Makefile | 1 +
drivers/dma/mediatek/mtk-uart-apdma.c | 666 +++++++++++++++++++++++++++++++++
3 files changed, 678 insertions(+)
create mode 100644 drivers/dma/mediatek/mtk-uart-apdma.c
diff --git a/drivers/dma/mediatek/Kconfig b/drivers/dma/mediatek/Kconfig
index 680fc05..ac49eb6 100644
--- a/drivers/dma/mediatek/Kconfig
+++ b/drivers/dma/mediatek/Kconfig
@@ -24,3 +24,14 @@ config MTK_CQDMA
This controller provides the channels which is dedicated to
memory-to-memory transfer to offload from CPU.
+
+config MTK_UART_APDMA
+ tristate "MediaTek SoCs APDMA support for UART"
+ depends on OF && SERIAL_8250_MT6577
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support for the UART DMA engine found on MediaTek MTK SoCs.
+ When SERIAL_8250_MT6577 is enabled, and if you want to use DMA,
+ you can enable the config. The DMA engine can only be used
+ with MediaTek SoCs.
diff --git a/drivers/dma/mediatek/Makefile b/drivers/dma/mediatek/Makefile
index 41bb381..61a6d29 100644
--- a/drivers/dma/mediatek/Makefile
+++ b/drivers/dma/mediatek/Makefile
@@ -1,2 +1,3 @@
+obj-$(CONFIG_MTK_UART_APDMA) += mtk-uart-apdma.o
obj-$(CONFIG_MTK_HSDMA) += mtk-hsdma.o
obj-$(CONFIG_MTK_CQDMA) += mtk-cqdma.o
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
new file mode 100644
index 0000000..546995c
--- /dev/null
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek UART APDMA driver.
+ *
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Long Cheng <long.cheng@mediatek.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../virt-dma.h"
+
+/* The default number of virtual channel */
+#define MTK_UART_APDMA_NR_VCHANS 8
+
+#define VFF_EN_B BIT(0)
+#define VFF_STOP_B BIT(0)
+#define VFF_FLUSH_B BIT(0)
+#define VFF_4G_EN_B BIT(0)
+/* rx valid size >= vff thre */
+#define VFF_RX_INT_EN_B (BIT(0) | BIT(1))
+/* tx left size >= vff thre */
+#define VFF_TX_INT_EN_B BIT(0)
+#define VFF_WARM_RST_B BIT(0)
+#define VFF_RX_INT_CLR_B (BIT(0) | BIT(1))
+#define VFF_TX_INT_CLR_B 0
+#define VFF_STOP_CLR_B 0
+#define VFF_EN_CLR_B 0
+#define VFF_INT_EN_CLR_B 0
+#define VFF_4G_SUPPORT_CLR_B 0
+
+/*
+ * interrupt trigger level for tx
+ * if threshold is n, no polling is required to start tx.
+ * otherwise need polling VFF_FLUSH.
+ */
+#define VFF_TX_THRE(n) (n)
+/* interrupt trigger level for rx */
+#define VFF_RX_THRE(n) ((n) * 3 / 4)
+
+#define VFF_RING_SIZE 0xffff
+/* invert this bit when wrap ring head again */
+#define VFF_RING_WRAP 0x10000
+
+#define VFF_INT_FLAG 0x00
+#define VFF_INT_EN 0x04
+#define VFF_EN 0x08
+#define VFF_RST 0x0c
+#define VFF_STOP 0x10
+#define VFF_FLUSH 0x14
+#define VFF_ADDR 0x1c
+#define VFF_LEN 0x24
+#define VFF_THRE 0x28
+#define VFF_WPT 0x2c
+#define VFF_RPT 0x30
+/* TX: the buffer size HW can read. RX: the buffer size SW can read. */
+#define VFF_VALID_SIZE 0x3c
+/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
+#define VFF_LEFT_SIZE 0x40
+#define VFF_DEBUG_STATUS 0x50
+#define VFF_4G_SUPPORT 0x54
+
+struct mtk_uart_apdmadev {
+ struct dma_device ddev;
+ struct clk *clk;
+ bool support_33bits;
+ unsigned int dma_requests;
+};
+
+struct mtk_uart_apdma_desc {
+ struct virt_dma_desc vd;
+
+ dma_addr_t addr;
+ unsigned int avail_len;
+};
+
+struct mtk_chan {
+ struct virt_dma_chan vc;
+ struct dma_slave_config cfg;
+ struct mtk_uart_apdma_desc *desc;
+ enum dma_transfer_direction dir;
+
+ void __iomem *base;
+ unsigned int irq;
+
+ unsigned int rx_status;
+};
+
+static inline struct mtk_uart_apdmadev *
+to_mtk_uart_apdma_dev(struct dma_device *d)
+{
+ return container_of(d, struct mtk_uart_apdmadev, ddev);
+}
+
+static inline struct mtk_chan *to_mtk_uart_apdma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct mtk_chan, vc.chan);
+}
+
+static inline struct mtk_uart_apdma_desc *to_mtk_uart_apdma_desc
+ (struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct mtk_uart_apdma_desc, vd.tx);
+}
+
+static void mtk_uart_apdma_write(struct mtk_chan *c,
+ unsigned int reg, unsigned int val)
+{
+ writel(val, c->base + reg);
+}
+
+static unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
+{
+ return readl(c->base + reg);
+}
+
+static void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
+{
+ struct dma_chan *chan = vd->tx.chan;
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ kfree(c->desc);
+}
+
+static void mtk_uart_apdma_start_tx(struct mtk_chan *c)
+{
+ struct mtk_uart_apdmadev *mtkd =
+ to_mtk_uart_apdma_dev(c->vc.chan.device);
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int wpt, vff_sz;
+
+ vff_sz = c->cfg.dst_port_window_size;
+ if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+ mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+ mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+ mtk_uart_apdma_write(c, VFF_THRE, VFF_TX_THRE(vff_sz));
+ mtk_uart_apdma_write(c, VFF_WPT, 0);
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+ }
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+ if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+ dev_err(c->vc.chan.device->dev, "Enable TX fail\n");
+
+ if (!mtk_uart_apdma_read(c, VFF_LEFT_SIZE)) {
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+ return;
+ }
+
+ wpt = mtk_uart_apdma_read(c, VFF_WPT);
+
+ wpt += c->desc->avail_len;
+ if ((wpt & VFF_RING_SIZE) == vff_sz)
+ wpt = (wpt & VFF_RING_WRAP) ^ VFF_RING_WRAP;
+
+ /* Let DMA start moving data */
+ mtk_uart_apdma_write(c, VFF_WPT, wpt);
+
+ /* HW auto set to 0 when left size >= threshold */
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
+ if (!mtk_uart_apdma_read(c, VFF_FLUSH))
+ mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+}
+
+static void mtk_uart_apdma_start_rx(struct mtk_chan *c)
+{
+ struct mtk_uart_apdmadev *mtkd =
+ to_mtk_uart_apdma_dev(c->vc.chan.device);
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int vff_sz;
+
+ vff_sz = c->cfg.src_port_window_size;
+ if (!mtk_uart_apdma_read(c, VFF_LEN)) {
+ mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
+ mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
+ mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(vff_sz));
+ mtk_uart_apdma_write(c, VFF_RPT, 0);
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
+ }
+
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B);
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
+ if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
+ dev_err(c->vc.chan.device->dev, "Enable RX fail\n");
+}
+
+static void mtk_uart_apdma_tx_handler(struct mtk_chan *c)
+{
+ struct mtk_uart_apdma_desc *d = c->desc;
+
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+
+ list_del(&d->vd.node);
+ vchan_cookie_complete(&d->vd);
+}
+
+static void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
+{
+ struct mtk_uart_apdma_desc *d = c->desc;
+ unsigned int len, wg, rg;
+ int cnt;
+
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+
+ if (!mtk_uart_apdma_read(c, VFF_VALID_SIZE))
+ return;
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ len = c->cfg.src_port_window_size;
+ rg = mtk_uart_apdma_read(c, VFF_RPT);
+ wg = mtk_uart_apdma_read(c, VFF_WPT);
+ cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
+
+ /*
+ * The buffer is ring buffer. If wrap bit different,
+ * represents the start of the next cycle for WPT
+ */
+ if ((rg ^ wg) & VFF_RING_WRAP)
+ cnt += len;
+
+ c->rx_status = d->avail_len - cnt;
+ mtk_uart_apdma_write(c, VFF_RPT, wg);
+
+ list_del(&d->vd.node);
+ vchan_cookie_complete(&d->vd);
+}
+
+static irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
+{
+ struct dma_chan *chan = (struct dma_chan *)dev_id;
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_rx_handler(c);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_tx_handler(c);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned int status;
+ int ret;
+
+ ret = pm_runtime_get_sync(mtkd->ddev.dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(chan->device->dev);
+ return ret;
+ }
+
+ mtk_uart_apdma_write(c, VFF_ADDR, 0);
+ mtk_uart_apdma_write(c, VFF_THRE, 0);
+ mtk_uart_apdma_write(c, VFF_LEN, 0);
+ mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);
+
+ ret = readx_poll_timeout(readl, c->base + VFF_EN,
+ status, !status, 10, 100);
+ if (ret)
+ return ret;
+
+ ret = request_irq(c->irq, mtk_uart_apdma_irq_handler,
+ IRQF_TRIGGER_NONE, KBUILD_MODNAME, chan);
+ if (ret < 0) {
+ dev_err(chan->device->dev, "Can't request dma IRQ\n");
+ return -EINVAL;
+ }
+
+ if (mtkd->support_33bits)
+ mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
+
+ return ret;
+}
+
+static void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
+{
+ struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ free_irq(c->irq, chan);
+
+ tasklet_kill(&c->vc.task);
+
+ vchan_free_chan_resources(&c->vc);
+
+ pm_runtime_put_sync(mtkd->ddev.dev);
+}
+
+static enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ enum dma_status ret;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (!txstate)
+ return ret;
+
+ dma_set_residue(txstate, c->rx_status);
+
+ return ret;
+}
+
+/*
+ * dmaengine_prep_slave_single will call the function. and sglen is 1.
+ * 8250 uart using one ring buffer, and deal with one sg.
+ */
+static struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
+ (struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sglen, enum dma_transfer_direction dir,
+ unsigned long tx_flags, void *context)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ struct mtk_uart_apdma_desc *d;
+
+ if (!is_slave_direction(dir) || sglen != 1)
+ return NULL;
+
+ /* Now allocate and setup the descriptor */
+ d = kzalloc(sizeof(*d), GFP_ATOMIC);
+ if (!d)
+ return NULL;
+
+ d->avail_len = sg_dma_len(sgl);
+ d->addr = sg_dma_address(sgl);
+ c->dir = dir;
+
+ return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
+}
+
+static void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (vchan_issue_pending(&c->vc)) {
+ vd = vchan_next_desc(&c->vc);
+ c->desc = to_mtk_uart_apdma_desc(&vd->tx);
+
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_start_rx(c);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_start_tx(c);
+ }
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static int mtk_uart_apdma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+
+ memcpy(&c->cfg, config, sizeof(*config));
+
+ return 0;
+}
+
+static int mtk_uart_apdma_terminate_all(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+ unsigned int status;
+ LIST_HEAD(head);
+ int ret;
+
+ mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
+
+ ret = readx_poll_timeout(readl, c->base + VFF_FLUSH,
+ status, status != VFF_FLUSH_B, 10, 100);
+ if (ret)
+ dev_err(c->vc.chan.device->dev, "flush: fail, status=0x%x\n",
+ mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+ /*
+ * Stop need 3 steps.
+ * 1. set stop to 1
+ * 2. wait en to 0
+ * 3. set stop as 0
+ */
+ mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_B);
+ ret = readx_poll_timeout(readl, c->base + VFF_EN,
+ status, !status, 10, 100);
+ if (ret)
+ dev_err(c->vc.chan.device->dev, "stop: fail, status=0x%x\n",
+ mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
+
+ mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ if (c->dir == DMA_DEV_TO_MEM)
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
+ else if (c->dir == DMA_MEM_TO_DEV)
+ mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
+
+ synchronize_irq(c->irq);
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_get_all_descriptors(&c->vc, &head);
+ vchan_dma_desc_free_list(&c->vc, &head);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_device_pause(struct dma_chan *chan)
+{
+ struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
+ mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
+
+ synchronize_irq(c->irq);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return 0;
+}
+
+static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
+{
+ while (!list_empty(&mtkd->ddev.channels)) {
+ struct mtk_chan *c = list_first_entry(&mtkd->ddev.channels,
+ struct mtk_chan, vc.chan.device_node);
+
+ list_del(&c->vc.chan.device_node);
+ tasklet_kill(&c->vc.task);
+ }
+}
+
+static const struct of_device_id mtk_uart_apdma_match[] = {
+ { .compatible = "mediatek,mt6577-uart-dma", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_uart_apdma_match);
+
+static int mtk_uart_apdma_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mtk_uart_apdmadev *mtkd;
+ int bit_mask = 32, rc;
+ struct resource *res;
+ struct mtk_chan *c;
+ unsigned int i;
+
+ mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
+ if (!mtkd)
+ return -ENOMEM;
+
+ mtkd->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mtkd->clk)) {
+ dev_err(&pdev->dev, "No clock specified\n");
+ rc = PTR_ERR(mtkd->clk);
+ return rc;
+ }
+
+ if (of_property_read_bool(np, "mediatek,dma-33bits"))
+ mtkd->support_33bits = true;
+
+ if (mtkd->support_33bits)
+ bit_mask = 33;
+
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
+ if (rc)
+ return rc;
+
+ dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
+ mtkd->ddev.device_alloc_chan_resources =
+ mtk_uart_apdma_alloc_chan_resources;
+ mtkd->ddev.device_free_chan_resources =
+ mtk_uart_apdma_free_chan_resources;
+ mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
+ mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
+ mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
+ mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
+ mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
+ mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
+ mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+ mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
+ mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+ mtkd->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&mtkd->ddev.channels);
+
+ mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
+ if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
+ dev_info(&pdev->dev,
+ "Using %u as missing dma-requests property\n",
+ MTK_UART_APDMA_NR_VCHANS);
+ }
+
+ for (i = 0; i < mtkd->dma_requests; i++) {
+ c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ rc = -ENODEV;
+ goto err_no_dma;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res) {
+ rc = -ENODEV;
+ goto err_no_dma;
+ }
+
+ c->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(c->base)) {
+ rc = PTR_ERR(c->base);
+ goto err_no_dma;
+ }
+ c->vc.desc_free = mtk_uart_apdma_desc_free;
+ vchan_init(&c->vc, &mtkd->ddev);
+
+ rc = platform_get_irq(pdev, i);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ[%d]\n", i);
+ goto err_no_dma;
+ }
+ c->irq = rc;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+
+ rc = dma_async_device_register(&mtkd->ddev);
+ if (rc)
+ goto rpm_disable;
+
+ platform_set_drvdata(pdev, mtkd);
+
+ /* Device-tree DMA controller registration */
+ rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
+ if (rc)
+ goto dma_remove;
+
+ return rc;
+
+dma_remove:
+ dma_async_device_unregister(&mtkd->ddev);
+rpm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_no_dma:
+ mtk_uart_apdma_free(mtkd);
+ return rc;
+}
+
+static int mtk_uart_apdma_remove(struct platform_device *pdev)
+{
+ struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+
+ mtk_uart_apdma_free(mtkd);
+
+ dma_async_device_unregister(&mtkd->ddev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_uart_apdma_suspend(struct device *dev)
+{
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ if (!pm_runtime_suspended(dev))
+ clk_disable_unprepare(mtkd->clk);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_resume(struct device *dev)
+{
+ int ret;
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = clk_prepare_enable(mtkd->clk);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int mtk_uart_apdma_runtime_suspend(struct device *dev)
+{
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(mtkd->clk);
+
+ return 0;
+}
+
+static int mtk_uart_apdma_runtime_resume(struct device *dev)
+{
+ int ret;
+ struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
+
+ ret = clk_prepare_enable(mtkd->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
+ SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
+ mtk_uart_apdma_runtime_resume, NULL)
+};
+
+static struct platform_driver mtk_uart_apdma_driver = {
+ .probe = mtk_uart_apdma_probe,
+ .remove = mtk_uart_apdma_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .pm = &mtk_uart_apdma_pm_ops,
+ .of_match_table = of_match_ptr(mtk_uart_apdma_match),
+ },
+};
+
+module_platform_driver(mtk_uart_apdma_driver);
+
+MODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
+MODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
--
1.7.9.5
^ permalink raw reply related
* [PATCH v12 0/4] add uart DMA function
From: Long Cheng @ 2019-04-27 3:36 UTC (permalink / raw)
To: Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland, Ryder Lee,
Sean Wang, Nicolas Boichat, Matthias Brugger
Cc: Dan Williams, Greg Kroah-Hartman, Jiri Slaby, Sean Wang,
dmaengine, devicetree, linux-arm-kernel, linux-mediatek,
linux-kernel, linux-serial, srv_heupstream, Yingjoe Chen, YT Shen,
Zhenbao Liu, Long Cheng
In Mediatek SOCs, the uart can support DMA function.
Base on DMA engine formwork, we add the DMA code to support uart. And put the code under drivers/dma/mediatek.
This series contains document bindings, Kconfig to control the function enable or not,
device tree including interrupt and dma device node, the code of UART DMA
Changes compared to v11
-modify TX/RX
-pause function by software
Changes compared to v10
-modify DMA tx status function
-modify 8250_mtk for DMA rx
-add notes to binding Document.
Changes compared to v9
-rename dt-bindings file
-remove direction from device_config
-simplified code
Changes compared to v8
-revise missing items
Changes compared to v7:
-modify apdma uart tx
Changes compared to v6:
-Correct spelling
Changes compared to v5:
-move 'requst irqs' to alloc channel
-remove tasklet.
Changes compared to v4:
-modify Kconfig depends on.
Changes compared to v3:
-fix CONFIG_PM, will cause build fail
Changes compared to v2:
-remove unimportant parameters
-instead of cookie, use APIs of virtual channel.
-use of_dma_xlate_by_chan_id.
Changes compared to v1:
-mian revised file, 8250_mtk_dma.c
--parameters renamed for standard
--remove atomic operation
Long Cheng (4):
dmaengine: mediatek: Add MediaTek UART APDMA support
arm: dts: mt2712: add uart APDMA to device tree
dt-bindings: dma: uart: rename binding
serial: 8250-mtk: modify uart DMA rx
.../devicetree/bindings/dma/8250_mtk_dma.txt | 33 -
.../devicetree/bindings/dma/mtk-uart-apdma.txt | 55 ++
arch/arm64/boot/dts/mediatek/mt2712e.dtsi | 51 ++
drivers/dma/mediatek/Kconfig | 11 +
drivers/dma/mediatek/Makefile | 1 +
drivers/dma/mediatek/mtk-uart-apdma.c | 666 ++++++++++++++++++++
drivers/tty/serial/8250/8250_mtk.c | 53 +-
7 files changed, 807 insertions(+), 63 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/dma/8250_mtk_dma.txt
create mode 100644 Documentation/devicetree/bindings/dma/mtk-uart-apdma.txt
create mode 100644 drivers/dma/mediatek/mtk-uart-apdma.c
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Andy Shevchenko @ 2019-04-26 21:51 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
He Zhe, Jisheng Zhang, Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <871s1og11u.fsf@haabendal.dk>
On Fri, Apr 26, 2019 at 06:54:05PM +0200, Esben Haabendal wrote:
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
> > On Fri, Apr 26, 2019 at 10:40:37AM +0200, Esben Haabendal wrote:
> >> With serial8250_register_8250_port() forcing UPF_BOOT_AUTOCONF bit on, it
> >> is not possible to register a port without having
> >> serial8250_request_std_resource() called.
> >>
> >> For adding a 8250 port to an MFD device, this is problematic, as the
> >> request_mem_region() call will fail, as the MFD device (and rightly so)
> >> has requested the region. For this case, the 8250 port should accept
> >> having passed mapbase and membase, and just use that.
> >
> > You need to simple set port type and use UPF_FIXED_TYPE.
> > No need for this patch.
>
> The reason for this patch is to be able to do exactly that (set port
> type and UPF_FIXED_TYPE) without having UPF_BOOT_AUTOCONF added.
>
> In the current serial8250_register_8250_port() there is:
>
> uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
>
> So, even though I set UPF_FIXED_TYPE, I get
> UPF_FIXED_TYPE|UPF_BOOT_AUTOCONF.
Yes.
> So I need this patch.
Why? I don't see any problems to have these flags set. Moreover, some drivers
are used as MFD counterparts with exactly same bits set.
> I think it is unfortunate that UPF_BOOT_AUTOCONF is or'ed to flags like
> that, but changing that will surely break stuff.
True.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v3] serial: Add Milbeaut serial control
From: Alan Cox @ 2019-04-26 18:15 UTC (permalink / raw)
To: Sugaya Taichi
Cc: Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann, Takao Orito,
Kazuhiro Kasai, Shinji Kanematsu, Jassi Brar, Masami Hiramatsu,
linux-kernel, linux-serial
In-Reply-To: <1555555916-22251-1-git-send-email-sugaya.taichi@socionext.com>
O
> +static void mlb_usio_set_termios(struct uart_port *port,
> + struct ktermios *termios, struct ktermios *old)
> +{
> + unsigned int escr, smr = MLB_USIO_SMR_SOE;
> + unsigned long flags, baud, quot;
> +
> + switch (termios->c_cflag & CSIZE) {
> + case CS5:
> + escr = MLB_USIO_ESCR_L_5BIT;
> + break;
> + case CS6:
> + escr = MLB_USIO_ESCR_L_6BIT;
> + break;
> + case CS7:
> + escr = MLB_USIO_ESCR_L_7BIT;
> + break;
> + case CS8:
> + default:
> + escr = MLB_USIO_ESCR_L_8BIT;
> + break;
> + }
> +
> + if (termios->c_cflag & CSTOPB)
> + smr |= MLB_USIO_SMR_SBL;
> +
> + if (termios->c_cflag & PARENB) {
> + escr |= MLB_USIO_ESCR_PEN;
> + if (termios->c_cflag & PARODD)
> + escr |= MLB_USIO_ESCR_P;
> + }
If you don't suport CMSPAR then clear that bit in termios as well
> + /* Set hard flow control */
> + if (of_property_read_bool(port->dev->of_node, "auto-flow-control") ||
> + (termios->c_cflag & CRTSCTS))
> + escr |= MLB_USIO_ESCR_FLWEN;
That's just broken. The termios bits are the definitive things for the
port, and in addition even if they are forced you need to correct the
termios data.
You might want to control flow control *at boot* with an OF property but
doing it post boot is just busted.
Alan
^ permalink raw reply
* Re: [PATCH 0/2] serial: 8250: Add support for 8250/16550 as MFD function
From: Andy Shevchenko @ 2019-04-26 17:21 UTC (permalink / raw)
To: Esben Haabendal
Cc: Andy Shevchenko, open list:SERIAL DRIVERS, Greg Kroah-Hartman,
Jiri Slaby, Darwin Dingel, Florian Fainelli, He Zhe,
Jisheng Zhang, Lokesh Vutla, Sebastian Andrzej Siewior,
Tony Lindgren, Linux Kernel Mailing List
In-Reply-To: <87wojgemci.fsf@haabendal.dk>
On Fri, Apr 26, 2019 at 8:16 PM Esben Haabendal <esben@haabendal.dk> wrote:
>
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
>
> > On Fri, Apr 26, 2019 at 10:40:36AM +0200, Esben Haabendal wrote:
> >> This series adds a driver for adding 8250/16550 UART ports as functions to
> >> MFD devices.
> >>
> >
> > The patch 2/2 disappeared.
>
> Yes, seems like that. I have resent it by itself. Or do I have to
> resend the series as a whole?
Series, but first check up on existing comments and try to address them first.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 0/2] serial: 8250: Add support for 8250/16550 as MFD function
From: Esben Haabendal @ 2019-04-26 16:57 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
Florian Fainelli, He Zhe, Jisheng Zhang, Lokesh Vutla,
Sebastian Andrzej Siewior, Tony Lindgren, linux-kernel
In-Reply-To: <20190426143521.GW9224@smile.fi.intel.com>
Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
> On Fri, Apr 26, 2019 at 10:40:36AM +0200, Esben Haabendal wrote:
>> This series adds a driver for adding 8250/16550 UART ports as functions to
>> MFD devices.
>>
>
> The patch 2/2 disappeared.
Yes, seems like that. I have resent it by itself. Or do I have to
resend the series as a whole?
/Esben
^ permalink raw reply
* [PATCH 2/2] serial: 8250: Add support for 8250/16550 as MFD function
From: Esben Haabendal @ 2019-04-26 16:55 UTC (permalink / raw)
To: linux-serial, Greg Kroah-Hartman, Jiri Slaby
Cc: Tony Lindgren, Nishanth Menon, Vignesh R, Lokesh Vutla,
Florian Fainelli, linux-kernel
The serial8250-mfd driver is for adding 8250/16550 UART ports as functions
to an MFD driver.
When calling mfd_add_device(), platform_data should be a pointer to a
struct plat_serial8250_port, with proper settings like .flags, .type,
.iotype, .regshift and .uartclk. Memory (or ioport) and IRQ should be
passed as cell resources.
Do not include UPF_BOOT_AUTOCONF in platform_data.flags.
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/tty/serial/8250/8250_mfd.c | 119 +++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 12 ++++
drivers/tty/serial/8250/Makefile | 1 +
3 files changed, 132 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_mfd.c
diff --git a/drivers/tty/serial/8250/8250_mfd.c b/drivers/tty/serial/8250/8250_mfd.c
new file mode 100644
index 0000000..eae1566
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_mfd.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Serial Port driver for 8250/16550-type MFD sub devices
+ *
+ * This mimics the serial8250_probe of 8250_core.c, while allowing
+ * use without UPF_BOOT_AUTOCONF, which is problematic for MFD, as
+ * the request_mem_region() will typically fail as the region is
+ * already requested by the MFD device.
+ *
+ * Memory and irq are passed as platform resources, which allows easy
+ * use together with (devm_)mfd_add_devices().
+ *
+ * Other parameters are passed as struct plat_serial8250_port in
+ * device platform_data.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/serial_8250.h>
+
+struct serial8250_mfd_data {
+ int line;
+};
+
+static int serial8250_mfd_probe(struct platform_device *pdev)
+{
+ struct plat_serial8250_port *pdata = dev_get_platdata(&pdev->dev);
+ struct serial8250_mfd_data *data;
+ struct uart_8250_port up;
+ struct resource *r;
+ void __iomem *membase;
+
+ if (!pdata)
+ return -ENODEV;
+
+ memset(&up, 0, sizeof(up));
+
+ switch (pdata->iotype) {
+ case UPIO_AU:
+ case UPIO_TSI:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+ case UPIO_MEM16:
+ case UPIO_MEM:
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+ membase = devm_ioremap_nocache(&pdev->dev,
+ r->start, resource_size(r));
+ if (!membase)
+ return -ENOMEM;
+ up.port.mapbase = r->start;
+ up.port.membase = membase;
+ break;
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!r)
+ return -ENODEV;
+ up.port.iobase = r->start;
+ break;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ up.port.irq = platform_get_irq(pdev, 0);
+ if (up.port.irq < 0)
+ up.port.irq = 0; /* no interrupt -> use polling */
+
+ /* Register with 8250_core.c */
+ up.port.irqflags = pdata->irqflags;
+ up.port.uartclk = pdata->uartclk;
+ up.port.regshift = pdata->regshift;
+ up.port.iotype = pdata->iotype;
+ up.port.flags = pdata->flags;
+ up.port.hub6 = pdata->hub6;
+ up.port.private_data = pdata->private_data;
+ up.port.type = pdata->type;
+ up.port.serial_in = pdata->serial_in;
+ up.port.serial_out = pdata->serial_out;
+ up.port.handle_irq = pdata->handle_irq;
+ up.port.handle_break = pdata->handle_break;
+ up.port.set_termios = pdata->set_termios;
+ up.port.set_ldisc = pdata->set_ldisc;
+ up.port.get_mctrl = pdata->get_mctrl;
+ up.port.pm = pdata->pm;
+ up.port.dev = &pdev->dev;
+ data->line = __serial8250_register_8250_port(&up, 0);
+ if (data->line < 0)
+ return data->line;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+}
+
+static int serial8250_mfd_remove(struct platform_device *pdev)
+{
+ struct serial8250_mfd_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ return 0;
+}
+
+static struct platform_driver serial8250_mfd_driver = {
+ .probe = serial8250_mfd_probe,
+ .remove = serial8250_mfd_remove,
+ .driver = {
+ .name = "serial8250-mfd",
+ },
+};
+
+module_platform_driver(serial8250_mfd_driver);
+
+MODULE_AUTHOR("Esben Haabendal <esben@geanix.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for 8250/16550-type MFD sub devices");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 15c2c54..ef1572b 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -58,6 +58,18 @@ config SERIAL_8250_PNP
This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support.
+config SERIAL_8250_MFD
+ bool "8250/16550 MFD function support"
+ depends on SERIAL_8250 && MFD_CORE
+ default n
+ help
+ This builds support for using 8250/16550-type UARTs as MFD
+ functions.
+
+ MFD drivers needing this should select it automatically.
+
+ If unsure, say N.
+
config SERIAL_8250_FINTEK
bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
depends on SERIAL_8250
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 18751bc..da8e139 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250-y := 8250_core.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_MFD) += 8250_mfd.o
8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
--
2.4.11
^ permalink raw reply related
* Re: [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Esben Haabendal @ 2019-04-26 16:54 UTC (permalink / raw)
To: Andy Shevchenko
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
He Zhe, Jisheng Zhang, Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <20190426143946.GX9224@smile.fi.intel.com>
Andy Shevchenko <andriy.shevchenko@linux.intel.com> writes:
> On Fri, Apr 26, 2019 at 10:40:37AM +0200, Esben Haabendal wrote:
>> With serial8250_register_8250_port() forcing UPF_BOOT_AUTOCONF bit on, it
>> is not possible to register a port without having
>> serial8250_request_std_resource() called.
>>
>> For adding a 8250 port to an MFD device, this is problematic, as the
>> request_mem_region() call will fail, as the MFD device (and rightly so)
>> has requested the region. For this case, the 8250 port should accept
>> having passed mapbase and membase, and just use that.
>
> You need to simple set port type and use UPF_FIXED_TYPE.
> No need for this patch.
The reason for this patch is to be able to do exactly that (set port
type and UPF_FIXED_TYPE) without having UPF_BOOT_AUTOCONF added.
In the current serial8250_register_8250_port() there is:
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
So, even though I set UPF_FIXED_TYPE, I get
UPF_FIXED_TYPE|UPF_BOOT_AUTOCONF. So I need this patch.
I think it is unfortunate that UPF_BOOT_AUTOCONF is or'ed to flags like
that, but changing that will surely break stuff.
/Esben
>
>>
>> Signed-off-by: Esben Haabendal <esben@geanix.com>
>> ---
>> drivers/tty/serial/8250/8250_core.c | 36 +++++++++++++++++++++---------------
>> include/linux/serial_8250.h | 2 ++
>> 2 files changed, 23 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
>> index e441221..ddbb0a0 100644
>> --- a/drivers/tty/serial/8250/8250_core.c
>> +++ b/drivers/tty/serial/8250/8250_core.c
>> @@ -957,20 +957,8 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
>> spin_unlock_irqrestore(&port->lock, flags);
>> }
>>
>> -/**
>> - * serial8250_register_8250_port - register a serial port
>> - * @up: serial port template
>> - *
>> - * Configure the serial port specified by the request. If the
>> - * port exists and is in use, it is hung up and unregistered
>> - * first.
>> - *
>> - * The port is then probed and if necessary the IRQ is autodetected
>> - * If this fails an error is returned.
>> - *
>> - * On success the port is ready to use and the line number is returned.
>> - */
>> -int serial8250_register_8250_port(struct uart_8250_port *up)
>> +int __serial8250_register_8250_port(struct uart_8250_port *up,
>> + unsigned int extra_flags)
>> {
>> struct uart_8250_port *uart;
>> int ret = -ENOSPC;
>> @@ -993,7 +981,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
>> uart->port.fifosize = up->port.fifosize;
>> uart->port.regshift = up->port.regshift;
>> uart->port.iotype = up->port.iotype;
>> - uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
>> + uart->port.flags = up->port.flags | extra_flags;
>> uart->bugs = up->bugs;
>> uart->port.mapbase = up->port.mapbase;
>> uart->port.mapsize = up->port.mapsize;
>> @@ -1086,6 +1074,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
>>
>> return ret;
>> }
>> +
>> +/**
>> + * serial8250_register_8250_port - register a serial port
>> + * @up: serial port template
>> + *
>> + * Configure the serial port specified by the request. If the
>> + * port exists and is in use, it is hung up and unregistered
>> + * first.
>> + *
>> + * The port is then probed and if necessary the IRQ is autodetected
>> + * If this fails an error is returned.
>> + *
>> + * On success the port is ready to use and the line number is returned.
>> + */
>> +int serial8250_register_8250_port(struct uart_8250_port *up)
>> +{
>> + return __serial8250_register_8250_port(up, UPF_BOOT_AUTOCONF);
>> +}
>> EXPORT_SYMBOL(serial8250_register_8250_port);
>>
>> /**
>> diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
>> index 5a655ba..9d1fe2e 100644
>> --- a/include/linux/serial_8250.h
>> +++ b/include/linux/serial_8250.h
>> @@ -145,6 +145,8 @@ static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
>> return container_of(up, struct uart_8250_port, port);
>> }
>>
>> +extern int __serial8250_register_8250_port(struct uart_8250_port *,
>> + unsigned int);
>> int serial8250_register_8250_port(struct uart_8250_port *);
>> void serial8250_unregister_port(int line);
>> void serial8250_suspend_port(int line);
>> --
>> 2.4.11
>>
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: serial: add documentation for the SiFive UART driver
From: Paul Walmsley @ 2019-04-26 16:36 UTC (permalink / raw)
To: Rob Herring
Cc: Paul Walmsley, linux-kernel@vger.kernel.org,
open list:SERIAL DRIVERS, linux-riscv, Greg Kroah-Hartman,
Paul Walmsley, devicetree, Mark Rutland, Palmer Dabbelt
In-Reply-To: <CAL_JsqLMFmkM3YHS3BK9LBdidmqRMZn0w+_WUGg7zZvyv3g=sw@mail.gmail.com>
On Fri, 26 Apr 2019, Rob Herring wrote:
> On Fri, Apr 12, 2019 at 9:01 PM Paul Walmsley <paul.walmsley@sifive.com> wrote:
> >
> > Add DT binding documentation for the Linux driver for the SiFive
> > asynchronous serial IP block.
> >
> > This revision incorporates changes based on feedback from Rob
> > Herring <robh@kernel.org>.
> >
> > Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
> > Signed-off-by: Paul Walmsley <paul@pwsan.com>
> > Cc: linux-serial@vger.kernel.org
> > Cc: devicetree@vger.kernel.org
> > Cc: linux-riscv@lists.infradead.org
> > Cc: linux-kernel@vger.kernel.org
> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > Cc: Rob Herring <robh+dt@kernel.org>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > Cc: Palmer Dabbelt <palmer@sifive.com>
> > ---
> > .../bindings/serial/sifive-serial.txt | 33 +++++++++++++++++++
> > 1 file changed, 33 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/serial/sifive-serial.txt
>
> Reviewed-by: Rob Herring <robh@kernel.org>
Thanks Rob.
> However, what about flow-control configuration? You'd better think now
> about what the default is and overriding that.
The underlying IP doesn't support it.
https://github.com/sifive/riscv-linux/blob/dev/paulw/dts-v5.1-rc6-experimental/drivers/tty/serial/sifive.c#L30
- Paul
^ permalink raw reply
* Re: [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Andy Shevchenko @ 2019-04-26 14:39 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
He Zhe, Jisheng Zhang, Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <20190426084038.6377-2-esben@geanix.com>
On Fri, Apr 26, 2019 at 10:40:37AM +0200, Esben Haabendal wrote:
> With serial8250_register_8250_port() forcing UPF_BOOT_AUTOCONF bit on, it
> is not possible to register a port without having
> serial8250_request_std_resource() called.
>
> For adding a 8250 port to an MFD device, this is problematic, as the
> request_mem_region() call will fail, as the MFD device (and rightly so)
> has requested the region. For this case, the 8250 port should accept
> having passed mapbase and membase, and just use that.
You need to simple set port type and use UPF_FIXED_TYPE.
No need for this patch.
>
> Signed-off-by: Esben Haabendal <esben@geanix.com>
> ---
> drivers/tty/serial/8250/8250_core.c | 36 +++++++++++++++++++++---------------
> include/linux/serial_8250.h | 2 ++
> 2 files changed, 23 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index e441221..ddbb0a0 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -957,20 +957,8 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
> spin_unlock_irqrestore(&port->lock, flags);
> }
>
> -/**
> - * serial8250_register_8250_port - register a serial port
> - * @up: serial port template
> - *
> - * Configure the serial port specified by the request. If the
> - * port exists and is in use, it is hung up and unregistered
> - * first.
> - *
> - * The port is then probed and if necessary the IRQ is autodetected
> - * If this fails an error is returned.
> - *
> - * On success the port is ready to use and the line number is returned.
> - */
> -int serial8250_register_8250_port(struct uart_8250_port *up)
> +int __serial8250_register_8250_port(struct uart_8250_port *up,
> + unsigned int extra_flags)
> {
> struct uart_8250_port *uart;
> int ret = -ENOSPC;
> @@ -993,7 +981,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
> uart->port.fifosize = up->port.fifosize;
> uart->port.regshift = up->port.regshift;
> uart->port.iotype = up->port.iotype;
> - uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
> + uart->port.flags = up->port.flags | extra_flags;
> uart->bugs = up->bugs;
> uart->port.mapbase = up->port.mapbase;
> uart->port.mapsize = up->port.mapsize;
> @@ -1086,6 +1074,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
>
> return ret;
> }
> +
> +/**
> + * serial8250_register_8250_port - register a serial port
> + * @up: serial port template
> + *
> + * Configure the serial port specified by the request. If the
> + * port exists and is in use, it is hung up and unregistered
> + * first.
> + *
> + * The port is then probed and if necessary the IRQ is autodetected
> + * If this fails an error is returned.
> + *
> + * On success the port is ready to use and the line number is returned.
> + */
> +int serial8250_register_8250_port(struct uart_8250_port *up)
> +{
> + return __serial8250_register_8250_port(up, UPF_BOOT_AUTOCONF);
> +}
> EXPORT_SYMBOL(serial8250_register_8250_port);
>
> /**
> diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
> index 5a655ba..9d1fe2e 100644
> --- a/include/linux/serial_8250.h
> +++ b/include/linux/serial_8250.h
> @@ -145,6 +145,8 @@ static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
> return container_of(up, struct uart_8250_port, port);
> }
>
> +extern int __serial8250_register_8250_port(struct uart_8250_port *,
> + unsigned int);
> int serial8250_register_8250_port(struct uart_8250_port *);
> void serial8250_unregister_port(int line);
> void serial8250_suspend_port(int line);
> --
> 2.4.11
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 0/2] serial: 8250: Add support for 8250/16550 as MFD function
From: Andy Shevchenko @ 2019-04-26 14:35 UTC (permalink / raw)
To: Esben Haabendal
Cc: linux-serial, Greg Kroah-Hartman, Jiri Slaby, Darwin Dingel,
Florian Fainelli, He Zhe, Jisheng Zhang, Lokesh Vutla,
Sebastian Andrzej Siewior, Tony Lindgren, linux-kernel
In-Reply-To: <20190426084038.6377-1-esben@geanix.com>
On Fri, Apr 26, 2019 at 10:40:36AM +0200, Esben Haabendal wrote:
> This series adds a driver for adding 8250/16550 UART ports as functions to
> MFD devices.
>
The patch 2/2 disappeared.
> Esben Haabendal (2):
> serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
> serial: 8250: Add support for 8250/16550 as MFD function
>
> drivers/tty/serial/8250/8250_core.c | 36 ++++++-----
> drivers/tty/serial/8250/8250_mfd.c | 119 ++++++++++++++++++++++++++++++++++++
> drivers/tty/serial/8250/Kconfig | 12 ++++
> drivers/tty/serial/8250/Makefile | 1 +
> include/linux/serial_8250.h | 2 +
> 5 files changed, 155 insertions(+), 15 deletions(-)
> create mode 100644 drivers/tty/serial/8250/8250_mfd.c
>
> --
> 2.4.11
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v5 1/2] dt-bindings: serial: add documentation for the SiFive UART driver
From: Rob Herring @ 2019-04-26 14:08 UTC (permalink / raw)
To: Paul Walmsley
Cc: linux-kernel@vger.kernel.org, open list:SERIAL DRIVERS,
linux-riscv, Greg Kroah-Hartman, Paul Walmsley, devicetree,
Mark Rutland, Palmer Dabbelt
In-Reply-To: <20190413020111.23400-2-paul.walmsley@sifive.com>
On Fri, Apr 12, 2019 at 9:01 PM Paul Walmsley <paul.walmsley@sifive.com> wrote:
>
> Add DT binding documentation for the Linux driver for the SiFive
> asynchronous serial IP block.
>
> This revision incorporates changes based on feedback from Rob
> Herring <robh@kernel.org>.
>
> Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>
> Signed-off-by: Paul Walmsley <paul@pwsan.com>
> Cc: linux-serial@vger.kernel.org
> Cc: devicetree@vger.kernel.org
> Cc: linux-riscv@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Palmer Dabbelt <palmer@sifive.com>
> ---
> .../bindings/serial/sifive-serial.txt | 33 +++++++++++++++++++
> 1 file changed, 33 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/serial/sifive-serial.txt
Reviewed-by: Rob Herring <robh@kernel.org>
However, what about flow-control configuration? You'd better think now
about what the default is and overriding that.
Rob
^ permalink raw reply
* [PATCH 2/2] serial: 8250: Add support for 8250/16550 as MFD function
From: Esben Haabendal @ 2019-04-26 8:40 UTC (permalink / raw)
To: linux-serial, Greg Kroah-Hartman, Jiri Slaby
Cc: Nishanth Menon, Vignesh R, Tony Lindgren, Lokesh Vutla,
Florian Fainelli, linux-kernel
In-Reply-To: <20190426084038.6377-1-esben@geanix.com>
The serial8250-mfd driver is for adding 8250/16550 UART ports as functions
to an MFD driver.
When calling mfd_add_device(), platform_data should be a pointer to a
struct plat_serial8250_port, with proper settings like .flags, .type,
.iotype, .regshift and .uartclk. Memory (or ioport) and IRQ should be
passed as cell resources.
Do not include UPF_BOOT_AUTOCONF in platform_data.flags.
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/tty/serial/8250/8250_mfd.c | 119 +++++++++++++++++++++++++++++++++++++
drivers/tty/serial/8250/Kconfig | 12 ++++
drivers/tty/serial/8250/Makefile | 1 +
3 files changed, 132 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_mfd.c
diff --git a/drivers/tty/serial/8250/8250_mfd.c b/drivers/tty/serial/8250/8250_mfd.c
new file mode 100644
index 0000000..eae1566
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_mfd.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Serial Port driver for 8250/16550-type MFD sub devices
+ *
+ * This mimics the serial8250_probe of 8250_core.c, while allowing
+ * use without UPF_BOOT_AUTOCONF, which is problematic for MFD, as
+ * the request_mem_region() will typically fail as the region is
+ * already requested by the MFD device.
+ *
+ * Memory and irq are passed as platform resources, which allows easy
+ * use together with (devm_)mfd_add_devices().
+ *
+ * Other parameters are passed as struct plat_serial8250_port in
+ * device platform_data.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/serial_8250.h>
+
+struct serial8250_mfd_data {
+ int line;
+};
+
+static int serial8250_mfd_probe(struct platform_device *pdev)
+{
+ struct plat_serial8250_port *pdata = dev_get_platdata(&pdev->dev);
+ struct serial8250_mfd_data *data;
+ struct uart_8250_port up;
+ struct resource *r;
+ void __iomem *membase;
+
+ if (!pdata)
+ return -ENODEV;
+
+ memset(&up, 0, sizeof(up));
+
+ switch (pdata->iotype) {
+ case UPIO_AU:
+ case UPIO_TSI:
+ case UPIO_MEM32:
+ case UPIO_MEM32BE:
+ case UPIO_MEM16:
+ case UPIO_MEM:
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+ membase = devm_ioremap_nocache(&pdev->dev,
+ r->start, resource_size(r));
+ if (!membase)
+ return -ENOMEM;
+ up.port.mapbase = r->start;
+ up.port.membase = membase;
+ break;
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!r)
+ return -ENODEV;
+ up.port.iobase = r->start;
+ break;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ up.port.irq = platform_get_irq(pdev, 0);
+ if (up.port.irq < 0)
+ up.port.irq = 0; /* no interrupt -> use polling */
+
+ /* Register with 8250_core.c */
+ up.port.irqflags = pdata->irqflags;
+ up.port.uartclk = pdata->uartclk;
+ up.port.regshift = pdata->regshift;
+ up.port.iotype = pdata->iotype;
+ up.port.flags = pdata->flags;
+ up.port.hub6 = pdata->hub6;
+ up.port.private_data = pdata->private_data;
+ up.port.type = pdata->type;
+ up.port.serial_in = pdata->serial_in;
+ up.port.serial_out = pdata->serial_out;
+ up.port.handle_irq = pdata->handle_irq;
+ up.port.handle_break = pdata->handle_break;
+ up.port.set_termios = pdata->set_termios;
+ up.port.set_ldisc = pdata->set_ldisc;
+ up.port.get_mctrl = pdata->get_mctrl;
+ up.port.pm = pdata->pm;
+ up.port.dev = &pdev->dev;
+ data->line = __serial8250_register_8250_port(&up, 0);
+ if (data->line < 0)
+ return data->line;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+}
+
+static int serial8250_mfd_remove(struct platform_device *pdev)
+{
+ struct serial8250_mfd_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ return 0;
+}
+
+static struct platform_driver serial8250_mfd_driver = {
+ .probe = serial8250_mfd_probe,
+ .remove = serial8250_mfd_remove,
+ .driver = {
+ .name = "serial8250-mfd",
+ },
+};
+
+module_platform_driver(serial8250_mfd_driver);
+
+MODULE_AUTHOR("Esben Haabendal <esben@geanix.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for 8250/16550-type MFD sub devices");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 15c2c54..ef1572b 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -58,6 +58,18 @@ config SERIAL_8250_PNP
This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support.
+config SERIAL_8250_MFD
+ bool "8250/16550 MFD function support"
+ depends on SERIAL_8250 && MFD_CORE
+ default n
+ help
+ This builds support for using 8250/16550-type UARTs as MFD
+ functions.
+
+ MFD drivers needing this should select it automatically.
+
+ If unsure, say N.
+
config SERIAL_8250_FINTEK
bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
depends on SERIAL_8250
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 18751bc..da8e139 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250-y := 8250_core.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_MFD) += 8250_mfd.o
8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
--
2.4.11
^ permalink raw reply related
* [PATCH 1/2] serial: 8250: Allow port registration without UPF_BOOT_AUTOCONF
From: Esben Haabendal @ 2019-04-26 8:40 UTC (permalink / raw)
To: linux-serial, Greg Kroah-Hartman, Jiri Slaby
Cc: Darwin Dingel, Andy Shevchenko, He Zhe, Jisheng Zhang,
Sebastian Andrzej Siewior, linux-kernel
In-Reply-To: <20190426084038.6377-1-esben@geanix.com>
With serial8250_register_8250_port() forcing UPF_BOOT_AUTOCONF bit on, it
is not possible to register a port without having
serial8250_request_std_resource() called.
For adding a 8250 port to an MFD device, this is problematic, as the
request_mem_region() call will fail, as the MFD device (and rightly so)
has requested the region. For this case, the 8250 port should accept
having passed mapbase and membase, and just use that.
Signed-off-by: Esben Haabendal <esben@geanix.com>
---
drivers/tty/serial/8250/8250_core.c | 36 +++++++++++++++++++++---------------
include/linux/serial_8250.h | 2 ++
2 files changed, 23 insertions(+), 15 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index e441221..ddbb0a0 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -957,20 +957,8 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
spin_unlock_irqrestore(&port->lock, flags);
}
-/**
- * serial8250_register_8250_port - register a serial port
- * @up: serial port template
- *
- * Configure the serial port specified by the request. If the
- * port exists and is in use, it is hung up and unregistered
- * first.
- *
- * The port is then probed and if necessary the IRQ is autodetected
- * If this fails an error is returned.
- *
- * On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_8250_port(struct uart_8250_port *up)
+int __serial8250_register_8250_port(struct uart_8250_port *up,
+ unsigned int extra_flags)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
@@ -993,7 +981,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.fifosize = up->port.fifosize;
uart->port.regshift = up->port.regshift;
uart->port.iotype = up->port.iotype;
- uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->port.flags = up->port.flags | extra_flags;
uart->bugs = up->bugs;
uart->port.mapbase = up->port.mapbase;
uart->port.mapsize = up->port.mapsize;
@@ -1086,6 +1074,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
return ret;
}
+
+/**
+ * serial8250_register_8250_port - register a serial port
+ * @up: serial port template
+ *
+ * Configure the serial port specified by the request. If the
+ * port exists and is in use, it is hung up and unregistered
+ * first.
+ *
+ * The port is then probed and if necessary the IRQ is autodetected
+ * If this fails an error is returned.
+ *
+ * On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_8250_port(struct uart_8250_port *up)
+{
+ return __serial8250_register_8250_port(up, UPF_BOOT_AUTOCONF);
+}
EXPORT_SYMBOL(serial8250_register_8250_port);
/**
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 5a655ba..9d1fe2e 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -145,6 +145,8 @@ static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
return container_of(up, struct uart_8250_port, port);
}
+extern int __serial8250_register_8250_port(struct uart_8250_port *,
+ unsigned int);
int serial8250_register_8250_port(struct uart_8250_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
--
2.4.11
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox