From patchwork Fri Feb 10 07:26:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaWei Wang X-Patchwork-Id: 13135438 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A1AABC05027 for ; Fri, 10 Feb 2023 07:28:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=e5Phx8KH7RxSx2c9sCXANvgplUDVwRTeP8Sq4MWs10Q=; b=ziHLNq+QfmqEOu +OSgIAHewGv0vegZJQrQAfa61l9jbSFMUQNi7GQTAoQZ6iPywjFODhfYgaQrsgWalViz7HSm1PsPL glL+9jYcyyoMQOiQKJ2fdTnja+WbhWkuIhRpdNU+42YasCwrBysEmRi/X3I0sKZHQFMrxlEIVWa0z 4SWQVD9oywIhtESTY39dhfvk6RlbEZltU7P1NDMolfuIpHnLSNXB7FkUwygy4zWIClymxVfDjRxQ7 3/kNGZ24P+DwVpW8XSvuxEFMkFUGVTysgJAVnngdT4UM/0Q1AfnReuUg49Bolx912mMpRTGFVx84t kbpni7WWU7kUuaBs60Tw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNp0-004c48-Is; Fri, 10 Feb 2023 07:27:50 +0000 Received: from twspam01.aspeedtech.com ([211.20.114.71]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNop-004bxP-Fw for linux-arm-kernel@lists.infradead.org; Fri, 10 Feb 2023 07:27:41 +0000 Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 31A7EWro068845; Fri, 10 Feb 2023 15:14:32 +0800 (GMT-8) (envelope-from chiawei_wang@aspeedtech.com) Received: from Chiawei-PC03.aspeed.com (192.168.2.66) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 10 Feb 2023 15:26:47 +0800 From: Chia-Wei Wang To: , , , , , , , , , , , Subject: [PATCH 1/4] dt-bindings: aspeed: Add UART controller Date: Fri, 10 Feb 2023 15:26:40 +0800 Message-ID: <20230210072643.2772-2-chiawei_wang@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> References: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.2.66] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 31A7EWro068845 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230209_232740_003919_2CB8CDBB X-CRM114-Status: GOOD ( 14.38 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add dt-bindings for Aspeed UART controller. Signed-off-by: Chia-Wei Wang --- .../bindings/serial/aspeed,uart.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/aspeed,uart.yaml diff --git a/Documentation/devicetree/bindings/serial/aspeed,uart.yaml b/Documentation/devicetree/bindings/serial/aspeed,uart.yaml new file mode 100644 index 000000000000..10c457d6a72e --- /dev/null +++ b/Documentation/devicetree/bindings/serial/aspeed,uart.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/aspeed,uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aspeed Universal Asynchronous Receiver/Transmitter + +maintainers: + - Chia-Wei Wang + +allOf: + - $ref: serial.yaml# + +description: | + The Aspeed UART is based on the basic 8250 UART and compatible + with 16550A, with support for DMA + +properties: + compatible: + const: aspeed,ast2600-uart + + reg: + description: The base address of the UART register bank + maxItems: 1 + + clocks: + description: The clock the baudrate is derived from + maxItems: 1 + + interrupts: + description: The IRQ number of the device + maxItems: 1 + + dma-mode: + type: boolean + description: Enable DMA + + dma-channel: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The channel number to be used in the DMA engine + + virtual: + type: boolean + description: Indicate virtual UART + + sirq: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The serial IRQ number on LPC bus interface + + sirq-polarity: + $ref: /schemas/types.yaml#/definitions/uint32 + description: The serial IRQ polarity on LPC bus interface + + pinctrl-0: true + + pinctrl_names: + const: default + +required: + - compatible + - reg + - clocks + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + serial@1e783000 { + compatible = "aspeed,ast2600-uart"; + reg = <0x1e783000 0x20>; + interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>; + pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>; + dma-mode; + dma-channel = <0>; + }; From patchwork Fri Feb 10 07:26:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaWei Wang X-Patchwork-Id: 13135440 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 433F9C05027 for ; Fri, 10 Feb 2023 07:29:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=R/BKZIKWsI/YuGxIaMTjs8VFbI7ghJU+Iprvuoc3Jy8=; b=jJ6q12hy9emMg8 tu1OdIGg4RA8PIy+0Ght6zYbqmt2w2XSv0jTe4g7QqHacYQUbSLRAQJ2xCz/T52HB9m6Gd2tBMffR 4o3mrgYe4fSFGZXHfZ0zi20Nkw+ud249YgioYIAQTs5bmYpv7BMQnqgiU4ws498UrqRGBewHuWQfR fYgsGfBnuzJT4G/ZnMUCMH1yUTP+HjNXi+Oeq1QXQhVRNqpwVg8VjEUm5iVKJ55WMlInYnCo4RXE9 MbMtY8hxGiMx2cYMtQT6dK1nYqP/WAlEdy1TuWjakVcKhPXAOwce9oFTe22tkcL2FkvrmLd4ywP+L jfKWfIr8239aYrBysyDw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNpQ-004cF7-V6; Fri, 10 Feb 2023 07:28:17 +0000 Received: from twspam01.aspeedtech.com ([211.20.114.71]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNop-004bye-Ox for linux-arm-kernel@lists.infradead.org; Fri, 10 Feb 2023 07:27:43 +0000 Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 31A7EWrp068845; Fri, 10 Feb 2023 15:14:33 +0800 (GMT-8) (envelope-from chiawei_wang@aspeedtech.com) Received: from Chiawei-PC03.aspeed.com (192.168.2.66) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 10 Feb 2023 15:26:47 +0800 From: Chia-Wei Wang To: , , , , , , , , , , , Subject: [PATCH 2/4] soc: aspeed: Add UART DMA support Date: Fri, 10 Feb 2023 15:26:41 +0800 Message-ID: <20230210072643.2772-3-chiawei_wang@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> References: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.2.66] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 31A7EWrp068845 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230209_232740_487108_851E76AF X-CRM114-Status: GOOD ( 29.22 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This driver provides DMA support for AST26xx UART and VUART devices. It is useful to offload CPU overhead while using UART/VUART for binary file transfer. Signed-off-by: Chia-Wei Wang --- drivers/soc/aspeed/Kconfig | 9 + drivers/soc/aspeed/Makefile | 1 + drivers/soc/aspeed/aspeed-udma.c | 447 +++++++++++++++++++++++++ include/linux/soc/aspeed/aspeed-udma.h | 34 ++ 4 files changed, 491 insertions(+) create mode 100644 drivers/soc/aspeed/aspeed-udma.c create mode 100644 include/linux/soc/aspeed/aspeed-udma.h diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index f579ee0b5afa..c3bb238bea75 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -52,6 +52,15 @@ config ASPEED_SOCINFO help Say yes to support decoding of ASPEED BMC information. +config ASPEED_UDMA + tristate "Aspeed UDMA Engine Driver" + default ARCH_ASPEED + help + Enable support for the Aspeed UDMA Engine found on the + Aspeed AST26xx SOCs. The UDMA engine provides UART DMA + operations between the memory buffer and UART/VUART + FIFO data. + endmenu endif diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile index b35d74592964..5aeabafee1d4 100644 --- a/drivers/soc/aspeed/Makefile +++ b/drivers/soc/aspeed/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o obj-$(CONFIG_ASPEED_SOCINFO) += aspeed-socinfo.o +obj-$(CONFIG_ASPEED_UDMA) += aspeed-udma.o diff --git a/drivers/soc/aspeed/aspeed-udma.c b/drivers/soc/aspeed/aspeed-udma.c new file mode 100644 index 000000000000..95898fbd6ed8 --- /dev/null +++ b/drivers/soc/aspeed/aspeed-udma.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Aspeed Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "aspeed-udma" + +/* UART DMA registers offset */ +#define UDMA_TX_DMA_EN 0x000 +#define UDMA_RX_DMA_EN 0x004 +#define UDMA_TIMEOUT_TIMER 0x00c +#define UDMA_TX_DMA_RST 0x020 +#define UDMA_RX_DMA_RST 0x024 +#define UDMA_TX_DMA_INT_EN 0x030 +#define UDMA_TX_DMA_INT_STAT 0x034 +#define UDMA_RX_DMA_INT_EN 0x038 +#define UDMA_RX_DMA_INT_STAT 0x03c + +#define UDMA_CHX_OFF(x) ((x) * 0x20) +#define UDMA_CHX_TX_RD_PTR(x) (0x040 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_TX_WR_PTR(x) (0x044 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_TX_BUF_BASE(x) (0x048 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_TX_CTRL(x) (0x04c + UDMA_CHX_OFF(x)) +#define UDMA_TX_CTRL_TMOUT_DISABLE BIT(4) +#define UDMA_TX_CTRL_BUFSZ_MASK GENMASK(3, 0) +#define UDMA_TX_CTRL_BUFSZ_SHIFT 0 +#define UDMA_CHX_RX_RD_PTR(x) (0x050 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_RX_WR_PTR(x) (0x054 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_RX_BUF_BASE(x) (0x058 + UDMA_CHX_OFF(x)) +#define UDMA_CHX_RX_CTRL(x) (0x05c + UDMA_CHX_OFF(x)) +#define UDMA_RX_CTRL_TMOUT_DISABLE BIT(4) +#define UDMA_RX_CTRL_BUFSZ_MASK GENMASK(3, 0) +#define UDMA_RX_CTRL_BUFSZ_SHIFT 0 + +#define UDMA_MAX_CHANNEL 14 +#define UDMA_TIMEOUT 0x200 + +enum aspeed_udma_bufsz_code { + UDMA_BUFSZ_CODE_1KB, + UDMA_BUFSZ_CODE_4KB, + UDMA_BUFSZ_CODE_16KB, + UDMA_BUFSZ_CODE_64KB, + + /* + * 128KB and above are supported ONLY for + * virtual UARTs. For physical UARTs, the + * size code is wrapped around at the 64K + * boundary. + */ + UDMA_BUFSZ_CODE_128KB, + UDMA_BUFSZ_CODE_256KB, + UDMA_BUFSZ_CODE_512KB, + UDMA_BUFSZ_CODE_1024KB, + UDMA_BUFSZ_CODE_2048KB, + UDMA_BUFSZ_CODE_4096KB, + UDMA_BUFSZ_CODE_8192KB, + UDMA_BUFSZ_CODE_16384KB, +}; + +struct aspeed_udma_chan { + dma_addr_t dma_addr; + + struct circ_buf *rb; + u32 rb_sz; + + aspeed_udma_cb_t cb; + void *cb_arg; + + bool dis_tmout; +}; + +struct aspeed_udma { + struct device *dev; + u8 __iomem *regs; + int irq; + struct aspeed_udma_chan tx_chs[UDMA_MAX_CHANNEL]; + struct aspeed_udma_chan rx_chs[UDMA_MAX_CHANNEL]; + spinlock_t lock; +}; + +struct aspeed_udma udma[1]; + +static int aspeed_udma_get_bufsz_code(u32 buf_sz) +{ + switch (buf_sz) { + case 0x400: + return UDMA_BUFSZ_CODE_1KB; + case 0x1000: + return UDMA_BUFSZ_CODE_4KB; + case 0x4000: + return UDMA_BUFSZ_CODE_16KB; + case 0x10000: + return UDMA_BUFSZ_CODE_64KB; + case 0x20000: + return UDMA_BUFSZ_CODE_128KB; + case 0x40000: + return UDMA_BUFSZ_CODE_256KB; + case 0x80000: + return UDMA_BUFSZ_CODE_512KB; + case 0x100000: + return UDMA_BUFSZ_CODE_1024KB; + case 0x200000: + return UDMA_BUFSZ_CODE_2048KB; + case 0x400000: + return UDMA_BUFSZ_CODE_4096KB; + case 0x800000: + return UDMA_BUFSZ_CODE_8192KB; + case 0x1000000: + return UDMA_BUFSZ_CODE_16384KB; + default: + return -1; + } + + return -1; +} + +static u32 aspeed_udma_get_tx_rptr(u32 ch_no) +{ + return readl(udma->regs + UDMA_CHX_TX_RD_PTR(ch_no)); +} + +static u32 aspeed_udma_get_rx_wptr(u32 ch_no) +{ + return readl(udma->regs + UDMA_CHX_RX_WR_PTR(ch_no)); +} + +static void aspeed_udma_set_ptr(u32 ch_no, u32 ptr, bool is_tx) +{ + writel(ptr, udma->regs + + ((is_tx) ? UDMA_CHX_TX_WR_PTR(ch_no) : UDMA_CHX_RX_RD_PTR(ch_no))); +} + +void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr) +{ + aspeed_udma_set_ptr(ch_no, wptr, true); +} +EXPORT_SYMBOL(aspeed_udma_set_tx_wptr); + +void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr) +{ + aspeed_udma_set_ptr(ch_no, rptr, false); +} +EXPORT_SYMBOL(aspeed_udma_set_rx_rptr); + +static int aspeed_udma_free_chan(u32 ch_no, bool is_tx) +{ + u32 reg; + unsigned long flags; + + if (ch_no > UDMA_MAX_CHANNEL) + return -EINVAL; + + spin_lock_irqsave(&udma->lock, flags); + + reg = readl(udma->regs + + ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); + reg &= ~(0x1 << ch_no); + + writel(reg, udma->regs + + ((is_tx) ? UDMA_TX_DMA_INT_EN : UDMA_RX_DMA_INT_EN)); + + spin_unlock_irqrestore(&udma->lock, flags); + + return 0; +} + +int aspeed_udma_free_tx_chan(u32 ch_no) +{ + return aspeed_udma_free_chan(ch_no, true); +} +EXPORT_SYMBOL(aspeed_udma_free_tx_chan); + +int aspeed_udma_free_rx_chan(u32 ch_no) +{ + return aspeed_udma_free_chan(ch_no, false); +} +EXPORT_SYMBOL(aspeed_udma_free_rx_chan); + +static int aspeed_udma_request_chan(u32 ch_no, dma_addr_t addr, + struct circ_buf *rb, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool dis_tmout, bool is_tx) +{ + int retval = 0; + int rbsz_code; + + u32 reg; + unsigned long flags; + struct aspeed_udma_chan *ch; + + if (ch_no > UDMA_MAX_CHANNEL) { + retval = -EINVAL; + goto out; + } + + if (IS_ERR_OR_NULL(rb) || IS_ERR_OR_NULL(rb->buf)) { + retval = -EINVAL; + goto out; + } + + rbsz_code = aspeed_udma_get_bufsz_code(rb_sz); + if (rbsz_code < 0) { + retval = -EINVAL; + goto out; + } + + spin_lock_irqsave(&udma->lock, flags); + + if (is_tx) { + reg = readl(udma->regs + UDMA_TX_DMA_INT_EN); + if (reg & (0x1 << ch_no)) { + retval = -EBUSY; + goto unlock_n_out; + } + + reg |= (0x1 << ch_no); + writel(reg, udma->regs + UDMA_TX_DMA_INT_EN); + + reg = readl(udma->regs + UDMA_CHX_TX_CTRL(ch_no)); + reg |= (dis_tmout) ? UDMA_TX_CTRL_TMOUT_DISABLE : 0; + reg |= (rbsz_code << UDMA_TX_CTRL_BUFSZ_SHIFT) & UDMA_TX_CTRL_BUFSZ_MASK; + writel(reg, udma->regs + UDMA_CHX_TX_CTRL(ch_no)); + + writel(addr, udma->regs + UDMA_CHX_TX_BUF_BASE(ch_no)); + } else { + reg = readl(udma->regs + UDMA_RX_DMA_INT_EN); + if (reg & (0x1 << ch_no)) { + retval = -EBUSY; + goto unlock_n_out; + } + + reg |= (0x1 << ch_no); + writel(reg, udma->regs + UDMA_RX_DMA_INT_EN); + + reg = readl(udma->regs + UDMA_CHX_RX_CTRL(ch_no)); + reg |= (dis_tmout) ? UDMA_RX_CTRL_TMOUT_DISABLE : 0; + reg |= (rbsz_code << UDMA_RX_CTRL_BUFSZ_SHIFT) & UDMA_RX_CTRL_BUFSZ_MASK; + writel(reg, udma->regs + UDMA_CHX_RX_CTRL(ch_no)); + + writel(addr, udma->regs + UDMA_CHX_RX_BUF_BASE(ch_no)); + } + + ch = (is_tx) ? &udma->tx_chs[ch_no] : &udma->rx_chs[ch_no]; + ch->rb = rb; + ch->rb_sz = rb_sz; + ch->cb = cb; + ch->cb_arg = id; + ch->dma_addr = addr; + ch->dis_tmout = dis_tmout; + +unlock_n_out: + spin_unlock_irqrestore(&udma->lock, flags); +out: + return 0; +} + +int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, + struct circ_buf *rb, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool dis_tmout) +{ + return aspeed_udma_request_chan(ch_no, addr, rb, rb_sz, cb, id, + dis_tmout, true); +} +EXPORT_SYMBOL(aspeed_udma_request_tx_chan); + +int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, + struct circ_buf *rb, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool dis_tmout) +{ + return aspeed_udma_request_chan(ch_no, addr, rb, rb_sz, cb, id, + dis_tmout, false); +} +EXPORT_SYMBOL(aspeed_udma_request_rx_chan); + +static void aspeed_udma_chan_ctrl(u32 ch_no, u32 op, bool is_tx) +{ + unsigned long flags; + u32 reg_en, reg_rst; + u32 reg_en_off = (is_tx) ? UDMA_TX_DMA_EN : UDMA_RX_DMA_EN; + u32 reg_rst_off = (is_tx) ? UDMA_TX_DMA_RST : UDMA_TX_DMA_RST; + + if (ch_no > UDMA_MAX_CHANNEL) + return; + + spin_lock_irqsave(&udma->lock, flags); + + reg_en = readl(udma->regs + reg_en_off); + reg_rst = readl(udma->regs + reg_rst_off); + + switch (op) { + case ASPEED_UDMA_OP_ENABLE: + reg_en |= (0x1 << ch_no); + writel(reg_en, udma->regs + reg_en_off); + break; + case ASPEED_UDMA_OP_DISABLE: + reg_en &= ~(0x1 << ch_no); + writel(reg_en, udma->regs + reg_en_off); + break; + case ASPEED_UDMA_OP_RESET: + reg_en &= ~(0x1 << ch_no); + writel(reg_en, udma->regs + reg_en_off); + + reg_rst |= (0x1 << ch_no); + writel(reg_rst, udma->regs + reg_rst_off); + + udelay(100); + + reg_rst &= ~(0x1 << ch_no); + writel(reg_rst, udma->regs + reg_rst_off); + break; + default: + break; + } + + spin_unlock_irqrestore(&udma->lock, flags); +} + +void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) +{ + aspeed_udma_chan_ctrl(ch_no, op, true); +} +EXPORT_SYMBOL(aspeed_udma_tx_chan_ctrl); + +void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op) +{ + aspeed_udma_chan_ctrl(ch_no, op, false); +} +EXPORT_SYMBOL(aspeed_udma_rx_chan_ctrl); + +static irqreturn_t aspeed_udma_isr(int irq, void *arg) +{ + u32 bit; + unsigned long tx_stat = readl(udma->regs + UDMA_TX_DMA_INT_STAT); + unsigned long rx_stat = readl(udma->regs + UDMA_RX_DMA_INT_STAT); + + if (udma != (struct aspeed_udma *)arg) + return IRQ_NONE; + + if (tx_stat == 0 && rx_stat == 0) + return IRQ_NONE; + + for_each_set_bit(bit, &tx_stat, UDMA_MAX_CHANNEL) { + writel((0x1 << bit), udma->regs + UDMA_TX_DMA_INT_STAT); + if (udma->tx_chs[bit].cb) + udma->tx_chs[bit].cb(aspeed_udma_get_tx_rptr(bit), + udma->tx_chs[bit].cb_arg); + } + + for_each_set_bit(bit, &rx_stat, UDMA_MAX_CHANNEL) { + writel((0x1 << bit), udma->regs + UDMA_RX_DMA_INT_STAT); + if (udma->rx_chs[bit].cb) + udma->rx_chs[bit].cb(aspeed_udma_get_rx_wptr(bit), + udma->rx_chs[bit].cb_arg); + } + + return IRQ_HANDLED; +} + +static int aspeed_udma_probe(struct platform_device *pdev) +{ + int i, rc; + struct resource *res; + struct device *dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR_OR_NULL(res)) { + dev_err(dev, "failed to get register base\n"); + return -ENODEV; + } + + udma->regs = devm_ioremap_resource(dev, res); + if (IS_ERR_OR_NULL(udma->regs)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(udma->regs); + } + + /* disable for safety */ + writel(0x0, udma->regs + UDMA_TX_DMA_EN); + writel(0x0, udma->regs + UDMA_RX_DMA_EN); + + udma->irq = platform_get_irq(pdev, 0); + if (udma->irq < 0) { + dev_err(dev, "failed to get IRQ number\n"); + return -ENODEV; + } + + rc = devm_request_irq(dev, udma->irq, aspeed_udma_isr, + IRQF_SHARED, DEVICE_NAME, udma); + if (rc) { + dev_err(dev, "failed to request IRQ handler\n"); + return rc; + } + + for (i = 0; i < UDMA_MAX_CHANNEL; ++i) { + writel(0, udma->regs + UDMA_CHX_TX_WR_PTR(i)); + writel(0, udma->regs + UDMA_CHX_RX_RD_PTR(i)); + } + + writel(0xffffffff, udma->regs + UDMA_TX_DMA_RST); + writel(0x0, udma->regs + UDMA_TX_DMA_RST); + + writel(0xffffffff, udma->regs + UDMA_RX_DMA_RST); + writel(0x0, udma->regs + UDMA_RX_DMA_RST); + + writel(0x0, udma->regs + UDMA_TX_DMA_INT_EN); + writel(0xffffffff, udma->regs + UDMA_TX_DMA_INT_STAT); + writel(0x0, udma->regs + UDMA_RX_DMA_INT_EN); + writel(0xffffffff, udma->regs + UDMA_RX_DMA_INT_STAT); + + writel(UDMA_TIMEOUT, udma->regs + UDMA_TIMEOUT_TIMER); + + spin_lock_init(&udma->lock); + + dev_set_drvdata(dev, udma); + + return 0; +} + +static const struct of_device_id aspeed_udma_match[] = { + { .compatible = "aspeed,ast2600-udma" }, + { }, +}; + +static struct platform_driver aspeed_udma_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = aspeed_udma_match, + + }, + .probe = aspeed_udma_probe, +}; + +module_platform_driver(aspeed_udma_driver); + +MODULE_AUTHOR("Chia-Wei Wang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Aspeed UDMA Engine Driver"); diff --git a/include/linux/soc/aspeed/aspeed-udma.h b/include/linux/soc/aspeed/aspeed-udma.h new file mode 100644 index 000000000000..4ec95d726ede --- /dev/null +++ b/include/linux/soc/aspeed/aspeed-udma.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) Aspeed Technology Inc. + */ +#ifndef __ASPEED_UDMA_H__ +#define __ASPEED_UDMA_H__ + +#include + +typedef void (*aspeed_udma_cb_t)(int rb_rwptr, void *id); + +enum aspeed_udma_ops { + ASPEED_UDMA_OP_ENABLE, + ASPEED_UDMA_OP_DISABLE, + ASPEED_UDMA_OP_RESET, +}; + +void aspeed_udma_set_tx_wptr(u32 ch_no, u32 wptr); +void aspeed_udma_set_rx_rptr(u32 ch_no, u32 rptr); + +void aspeed_udma_tx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); +void aspeed_udma_rx_chan_ctrl(u32 ch_no, enum aspeed_udma_ops op); + +int aspeed_udma_request_tx_chan(u32 ch_no, dma_addr_t addr, + struct circ_buf *rb, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool en_tmout); +int aspeed_udma_request_rx_chan(u32 ch_no, dma_addr_t addr, + struct circ_buf *rb, u32 rb_sz, + aspeed_udma_cb_t cb, void *id, bool en_tmout); + +int aspeed_udma_free_tx_chan(u32 ch_no); +int aspeed_udma_free_rx_chan(u32 ch_no); + +#endif From patchwork Fri Feb 10 07:26:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaWei Wang X-Patchwork-Id: 13135441 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0E0A6C636CD for ; Fri, 10 Feb 2023 07:29:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=oK6QxT6Bjr2TEXytFku852ZDr2GSO9BNo57bW60zeQU=; b=paaLubhayKpatK NavVzPAfRh2eeqMQyMZ9wCVQc6iVXeQO7zWpujvoeMGqOe0tT0DYbGTNO5qJ72uC9JEk5GCczkz+H kR1MqoCf65OeRfOyQ+54PdDJE2zrLFlz2yctOF6woQKHPrAnylf8GmuwXGZarM/+DQ3Vr68IaVs+D 9iGYYTpNutJt+1NGlJLz/2DxFhS06FnS/Ql+BXfdztQXTOzqKP5g/EXuE+4hk+l1SrMcv7ZymtaE1 toOi8ShCFMykJHPkCzSFjXBQWcoynnLJUIUEggXLcm7dMm2ZEd9tSk0Gwiucqw8Cf/CoaIg9i9s3E 4SVcbTtTYfvKHZqroqjg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNpI-004cBX-BS; Fri, 10 Feb 2023 07:28:08 +0000 Received: from twspam01.aspeedtech.com ([211.20.114.71]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNop-004byu-I1 for linux-arm-kernel@lists.infradead.org; Fri, 10 Feb 2023 07:27:43 +0000 Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 31A7EWrq068845; Fri, 10 Feb 2023 15:14:33 +0800 (GMT-8) (envelope-from chiawei_wang@aspeedtech.com) Received: from Chiawei-PC03.aspeed.com (192.168.2.66) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 10 Feb 2023 15:26:47 +0800 From: Chia-Wei Wang To: , , , , , , , , , , , Subject: [PATCH 3/4] serial: 8250: Add Aspeed UART driver Date: Fri, 10 Feb 2023 15:26:42 +0800 Message-ID: <20230210072643.2772-4-chiawei_wang@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> References: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.2.66] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 31A7EWrq068845 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230209_232740_289580_B56270A7 X-CRM114-Status: GOOD ( 27.85 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add the driver for Aspeed UART/VUART devices, which are 16550A compatible. It is an wrapper to cover the generic 16550A operation while exetending DMA feature for the devices. Signed-off-by: Chia-Wei Wang --- drivers/tty/serial/8250/8250_aspeed.c | 502 ++++++++++++++++++++++++++ drivers/tty/serial/8250/Kconfig | 8 + drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 511 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_aspeed.c diff --git a/drivers/tty/serial/8250/8250_aspeed.c b/drivers/tty/serial/8250/8250_aspeed.c new file mode 100644 index 000000000000..2eaa59ee6d27 --- /dev/null +++ b/drivers/tty/serial/8250/8250_aspeed.c @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +#define DEVICE_NAME "aspeed-uart" + +/* offsets for the aspeed virtual uart registers */ +#define VUART_GCRA 0x20 +#define VUART_GCRA_VUART_EN BIT(0) +#define VUART_GCRA_SIRQ_POLARITY BIT(1) +#define VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5) +#define VUART_GCRB 0x24 +#define VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4) +#define VUART_GCRB_HOST_SIRQ_SHIFT 4 +#define VUART_ADDRL 0x28 +#define VUART_ADDRH 0x2c + +#define DMA_TX_BUFSZ PAGE_SIZE +#define DMA_RX_BUFSZ (64 * 1024) + +struct uart_ops ast8250_pops; + +struct ast8250_vuart { + u32 port; + u32 sirq; + u32 sirq_pol; +}; + +struct ast8250_udma { + u32 ch; + + u32 tx_rbsz; + u32 rx_rbsz; + + dma_addr_t tx_addr; + dma_addr_t rx_addr; + + struct circ_buf *tx_rb; + struct circ_buf *rx_rb; + + bool tx_tmout_dis; + bool rx_tmout_dis; +}; + +struct ast8250_data { + int line; + + u8 __iomem *regs; + + bool is_vuart; + bool use_dma; + + struct reset_control *rst; + struct clk *clk; + + struct ast8250_vuart vuart; + struct ast8250_udma dma; +}; + +static void ast8250_dma_tx_complete(int tx_rb_rptr, void *id) +{ + u32 count; + unsigned long flags; + struct uart_port *port = (struct uart_port *)id; + struct ast8250_data *data = port->private_data; + + spin_lock_irqsave(&port->lock, flags); + + count = CIRC_CNT(tx_rb_rptr, port->state->xmit.tail, data->dma.tx_rbsz); + port->state->xmit.tail = tx_rb_rptr; + port->icount.tx += count; + + if (uart_circ_chars_pending(&port->state->xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void ast8250_dma_rx_complete(int rx_rb_wptr, void *id) +{ + unsigned long flags; + struct uart_port *up = (struct uart_port *)id; + struct tty_port *tp = &up->state->port; + struct ast8250_data *data = up->private_data; + struct ast8250_udma *dma = &data->dma; + struct circ_buf *rx_rb = dma->rx_rb; + u32 rx_rbsz = dma->rx_rbsz; + u32 count = 0; + + spin_lock_irqsave(&up->lock, flags); + + rx_rb->head = rx_rb_wptr; + + dma_sync_single_for_cpu(up->dev, + dma->rx_addr, dma->rx_rbsz, DMA_FROM_DEVICE); + + while (CIRC_CNT(rx_rb->head, rx_rb->tail, rx_rbsz)) { + count = CIRC_CNT_TO_END(rx_rb->head, rx_rb->tail, rx_rbsz); + + tty_insert_flip_string(tp, rx_rb->buf + rx_rb->tail, count); + + rx_rb->tail += count; + rx_rb->tail %= rx_rbsz; + + up->icount.rx += count; + } + + if (count) { + aspeed_udma_set_rx_rptr(data->dma.ch, rx_rb->tail); + tty_flip_buffer_push(tp); + } + + spin_unlock_irqrestore(&up->lock, flags); +} + +static void ast8250_dma_start_tx(struct uart_port *port) +{ + struct ast8250_data *data = port->private_data; + struct ast8250_udma *dma = &data->dma; + struct circ_buf *tx_rb = dma->tx_rb; + + dma_sync_single_for_device(port->dev, + dma->tx_addr, dma->tx_rbsz, DMA_TO_DEVICE); + + aspeed_udma_set_tx_wptr(dma->ch, tx_rb->head); +} + +static void ast8250_dma_pops_hook(struct uart_port *port) +{ + static int first = 1; + + if (first) { + ast8250_pops = *port->ops; + ast8250_pops.start_tx = ast8250_dma_start_tx; + } + + first = 0; + port->ops = &ast8250_pops; +} + +static void ast8250_vuart_init(struct ast8250_data *data) +{ + u8 reg; + struct ast8250_vuart *vuart = &data->vuart; + + /* IO port address */ + writeb((u8)(vuart->port >> 0), data->regs + VUART_ADDRL); + writeb((u8)(vuart->port >> 8), data->regs + VUART_ADDRH); + + /* SIRQ number */ + reg = readb(data->regs + VUART_GCRB); + reg &= ~VUART_GCRB_HOST_SIRQ_MASK; + reg |= ((vuart->sirq << VUART_GCRB_HOST_SIRQ_SHIFT) & VUART_GCRB_HOST_SIRQ_MASK); + writeb(reg, data->regs + VUART_GCRB); + + /* SIRQ polarity */ + reg = readb(data->regs + VUART_GCRA); + if (vuart->sirq_pol) + reg |= VUART_GCRA_SIRQ_POLARITY; + else + reg &= ~VUART_GCRA_SIRQ_POLARITY; + writeb(reg, data->regs + VUART_GCRA); +} + +static void ast8250_vuart_set_host_tx_discard(struct ast8250_data *data, bool discard) +{ + u8 reg; + + reg = readb(data->regs + VUART_GCRA); + if (discard) + reg &= ~VUART_GCRA_DISABLE_HOST_TX_DISCARD; + else + reg |= VUART_GCRA_DISABLE_HOST_TX_DISCARD; + writeb(reg, data->regs + VUART_GCRA); +} + +static void ast8250_vuart_set_enable(struct ast8250_data *data, bool enable) +{ + u8 reg; + + reg = readb(data->regs + VUART_GCRA); + if (enable) + reg |= VUART_GCRA_VUART_EN; + else + reg &= ~VUART_GCRA_VUART_EN; + writeb(reg, data->regs + VUART_GCRA); +} + +static int ast8250_handle_irq(struct uart_port *port) +{ + u32 iir = port->serial_in(port, UART_IIR); + + return serial8250_handle_irq(port, iir); +} + +static int ast8250_startup(struct uart_port *port) +{ + int rc = 0; + struct ast8250_data *data = port->private_data; + struct ast8250_udma *dma; + + if (data->is_vuart) + ast8250_vuart_set_host_tx_discard(data, false); + + if (data->use_dma) { + dma = &data->dma; + + dma->tx_rbsz = DMA_TX_BUFSZ; + dma->rx_rbsz = DMA_RX_BUFSZ; + + /* + * We take the xmit buffer passed from upper layers as + * the DMA TX buffer and allocate a new buffer for the + * RX use. + * + * To keep the TX/RX operation consistency, we use the + * streaming DMA interface instead of the coherent one + */ + dma->tx_rb = &port->state->xmit; + dma->rx_rb->buf = kzalloc(data->dma.rx_rbsz, GFP_KERNEL); + if (IS_ERR_OR_NULL(dma->rx_rb->buf)) { + dev_err(port->dev, "failed to allcoate RX DMA buffer\n"); + rc = -ENOMEM; + goto out; + } + + dma->tx_addr = dma_map_single(port->dev, dma->tx_rb->buf, + dma->tx_rbsz, DMA_TO_DEVICE); + if (dma_mapping_error(port->dev, dma->tx_addr)) { + dev_err(port->dev, "failed to map streaming TX DMA region\n"); + rc = -ENOMEM; + goto free_dma_n_out; + } + + dma->rx_addr = dma_map_single(port->dev, dma->rx_rb->buf, + dma->rx_rbsz, DMA_FROM_DEVICE); + if (dma_mapping_error(port->dev, dma->rx_addr)) { + dev_err(port->dev, "failed to map streaming RX DMA region\n"); + rc = -ENOMEM; + goto free_dma_n_out; + } + + rc = aspeed_udma_request_tx_chan(dma->ch, dma->tx_addr, dma->tx_rb, + dma->tx_rbsz, ast8250_dma_tx_complete, + port, dma->tx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA TX channel\n"); + goto free_dma_n_out; + } + + rc = aspeed_udma_request_rx_chan(dma->ch, dma->rx_addr, dma->rx_rb, + dma->rx_rbsz, ast8250_dma_rx_complete, + port, dma->rx_tmout_dis); + if (rc) { + dev_err(port->dev, "failed to request DMA RX channel\n"); + goto free_dma_n_out; + } + + ast8250_dma_pops_hook(port); + + aspeed_udma_tx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_ENABLE); + aspeed_udma_rx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_ENABLE); + } + + memset(&port->icount, 0, sizeof(port->icount)); + return serial8250_do_startup(port); + +free_dma_n_out: + kfree(dma->rx_rb->buf); +out: + return rc; +} + +static void ast8250_shutdown(struct uart_port *port) +{ + int rc; + struct ast8250_data *data = port->private_data; + struct ast8250_udma *dma; + + if (data->use_dma) { + dma = &data->dma; + + aspeed_udma_tx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_RESET); + aspeed_udma_rx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_RESET); + + aspeed_udma_tx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_DISABLE); + aspeed_udma_rx_chan_ctrl(dma->ch, ASPEED_UDMA_OP_DISABLE); + + rc = aspeed_udma_free_tx_chan(dma->ch); + if (rc) + dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc); + + rc = aspeed_udma_free_rx_chan(dma->ch); + if (rc) + dev_err(port->dev, "failed to free DMA TX channel, rc=%d\n", rc); + + dma_unmap_single(port->dev, dma->tx_addr, + dma->tx_rbsz, DMA_TO_DEVICE); + dma_unmap_single(port->dev, dma->rx_addr, + dma->rx_rbsz, DMA_FROM_DEVICE); + + kfree(dma->rx_rb->buf); + } + + if (data->is_vuart) + ast8250_vuart_set_host_tx_discard(data, true); + + serial8250_do_shutdown(port); +} + +static int __maybe_unused ast8250_suspend(struct device *dev) +{ + struct ast8250_data *data = dev_get_drvdata(dev); + + serial8250_suspend_port(data->line); + + return 0; +} + +static int __maybe_unused ast8250_resume(struct device *dev) +{ + struct ast8250_data *data = dev_get_drvdata(dev); + + serial8250_resume_port(data->line); + + return 0; +} + +static int ast8250_probe(struct platform_device *pdev) +{ + int rc; + struct uart_8250_port uart = {}; + struct uart_port *port = &uart.port; + struct device *dev = &pdev->dev; + struct ast8250_data *data; + + struct resource *res; + u32 irq; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + data->dma.rx_rb = devm_kzalloc(dev, sizeof(data->dma.rx_rb), GFP_KERNEL); + if (data->dma.rx_rb == NULL) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "failed to get register base\n"); + return -ENODEV; + } + + data->regs = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(data->regs)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(data->regs); + } + + data->clk = devm_clk_get(dev, NULL); + if (IS_ERR(data->clk)) { + dev_err(dev, "failed to get clocks\n"); + return -ENODEV; + } + + rc = clk_prepare_enable(data->clk); + if (rc) { + dev_err(dev, "failed to enable clock\n"); + return rc; + } + + data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); + if (!IS_ERR(data->rst)) + reset_control_deassert(data->rst); + + data->is_vuart = of_property_read_bool(dev->of_node, "virtual"); + if (data->is_vuart) { + rc = of_property_read_u32(dev->of_node, "port", &data->vuart.port); + if (rc) { + dev_err(dev, "failed to get VUART port address\n"); + return -ENODEV; + } + + rc = of_property_read_u32(dev->of_node, "sirq", &data->vuart.sirq); + if (rc) { + dev_err(dev, "failed to get VUART SIRQ number\n"); + return -ENODEV; + } + + rc = of_property_read_u32(dev->of_node, "sirq-polarity", &data->vuart.sirq_pol); + if (rc) { + dev_err(dev, "failed to get VUART SIRQ polarity\n"); + return -ENODEV; + } + + ast8250_vuart_init(data); + ast8250_vuart_set_host_tx_discard(data, true); + ast8250_vuart_set_enable(data, true); + } + + data->use_dma = of_property_read_bool(dev->of_node, "dma-mode"); + if (data->use_dma) { + rc = of_property_read_u32(dev->of_node, "dma-channel", &data->dma.ch); + if (rc) { + dev_err(dev, "failed to get DMA channel\n"); + return -ENODEV; + } + + data->dma.tx_tmout_dis = of_property_read_bool(dev->of_node, + "dma-tx-timeout-disable"); + data->dma.rx_tmout_dis = of_property_read_bool(dev->of_node, + "dma-rx-timeout-disable"); + } + + spin_lock_init(&port->lock); + port->dev = dev; + port->type = PORT_16550A; + port->irq = irq; + port->line = of_alias_get_id(dev->of_node, "serial"); + port->handle_irq = ast8250_handle_irq; + port->mapbase = res->start; + port->mapsize = resource_size(res); + port->membase = data->regs; + port->uartclk = clk_get_rate(data->clk); + port->regshift = 2; + port->iotype = UPIO_MEM32; + port->flags = UPF_FIXED_TYPE | UPF_FIXED_PORT | UPF_SHARE_IRQ; + port->startup = ast8250_startup; + port->shutdown = ast8250_shutdown; + port->private_data = data; + uart.bugs |= UART_BUG_TXRACE; + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) { + dev_err(dev, "failed to register 8250 port\n"); + return data->line; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + platform_set_drvdata(pdev, data); + return 0; +} + +static int ast8250_remove(struct platform_device *pdev) +{ + struct ast8250_data *data = platform_get_drvdata(pdev); + + if (data->is_vuart) + ast8250_vuart_set_enable(data, false); + + serial8250_unregister_port(data->line); + return 0; +} + +static const struct dev_pm_ops ast8250_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ast8250_suspend, ast8250_resume) +}; + +static const struct of_device_id ast8250_of_match[] = { + { .compatible = "aspeed,ast2600-uart" }, +}; + +static struct platform_driver ast8250_platform_driver = { + .driver = { + .name = DEVICE_NAME, + .pm = &ast8250_pm_ops, + .of_match_table = ast8250_of_match, + }, + .probe = ast8250_probe, + .remove = ast8250_remove, +}; + +module_platform_driver(ast8250_platform_driver); + +MODULE_AUTHOR("Chia-Wei Wang "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Aspeed UART Driver"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index b0f62345bc84..d8ecc261d8c4 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -538,6 +538,14 @@ config SERIAL_8250_BCM7271 including DMA support and high accuracy BAUD rates, say Y to this option. If unsure, say N. +config SERIAL_8250_ASPEED + tristate "Aspeed serial port support" + depends on SERIAL_8250 && ARCH_ASPEED + help + If you have a system using an Aspeed AST26xx SoCs and wish to + make use of its UARTs and VUARTs, which are 16550A compatible + and include DMA support, say Y to this option. If unsure, say N. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 1615bfdde2a0..7f05b7ed422b 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_SERIAL_8250_PERICOM) += 8250_pericom.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o +obj-$(CONFIG_SERIAL_8250_ASPEED) += 8250_aspeed.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt From patchwork Fri Feb 10 07:26:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ChiaWei Wang X-Patchwork-Id: 13135437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6719EC636CD for ; Fri, 10 Feb 2023 07:28:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=fiiLj5XWNV61U9f8fqWtYHNQQ0dAON9pKnt6GsOiFzI=; b=UPmnR2lsxUHFzz D//49Lf7garxVggOL4BTjdOUtNdndFlKjEolk7w0bcC6NsydHLtZd0WLZR0mGACKbmaFCGLo6vUW3 7RKDk7uMGR5VDJCPPGl0eqLhmkqq4eEqy3IOa4Ae+qH6lqZ4N+OnaySeP1f4pnn6s0ZLkve7I+A8j McShF5pWoshnCa5RKIaJcWLZUHvL9Fhmm631JAQag8aF0ZoauaHPHZg4wOP7q6zfW0PgVaFD7svE2 UkVNVNqU6Ojy1btIBmmYhxcuy8HzrxMQGutZPNfwXoDsNc5rMxyPlq7T1TSaKw6oPdek5631WLf/8 /WOdfFJ/F/CP+J3tnyWQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNos-004c1L-33; Fri, 10 Feb 2023 07:27:42 +0000 Received: from twspam01.aspeedtech.com ([211.20.114.71]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pQNop-004byj-O5 for linux-arm-kernel@lists.infradead.org; Fri, 10 Feb 2023 07:27:41 +0000 Received: from mail.aspeedtech.com ([192.168.0.24]) by twspam01.aspeedtech.com with ESMTP id 31A7EWrr068845; Fri, 10 Feb 2023 15:14:33 +0800 (GMT-8) (envelope-from chiawei_wang@aspeedtech.com) Received: from Chiawei-PC03.aspeed.com (192.168.2.66) by TWMBX02.aspeed.com (192.168.0.24) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 10 Feb 2023 15:26:48 +0800 From: Chia-Wei Wang To: , , , , , , , , , , , Subject: [PATCH 4/4] ARM: dts: aspeed-g6: Add UDMA node Date: Fri, 10 Feb 2023 15:26:43 +0800 Message-ID: <20230210072643.2772-5-chiawei_wang@aspeedtech.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> References: <20230210072643.2772-1-chiawei_wang@aspeedtech.com> MIME-Version: 1.0 X-Originating-IP: [192.168.2.66] X-ClientProxiedBy: TWMBX02.aspeed.com (192.168.0.24) To TWMBX02.aspeed.com (192.168.0.24) X-DNSRBL: X-MAIL: twspam01.aspeedtech.com 31A7EWrr068845 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230209_232740_241466_1BCBFB15 X-CRM114-Status: UNSURE ( 9.14 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add the device tree node for UART DMA controller. Signed-off-by: Chia-Wei Wang --- arch/arm/boot/dts/aspeed-g6.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index cc2f8b785917..3f4e9da8f6c7 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -850,6 +850,13 @@ fsim1: fsi@1e79b100 { clocks = <&syscon ASPEED_CLK_GATE_FSICLK>; status = "disabled"; }; + + udma: uart-dma@1e79e000 { + compatible = "aspeed,ast2600-udma"; + reg = <0x1e79e000 0x400>; + interrupts = ; + status = "disabled"; + }; }; }; };