From patchwork Tue Nov 17 05:45:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jun Nie X-Patchwork-Id: 56702 Delivered-To: patch@linaro.org Received: by 10.112.155.196 with SMTP id vy4csp1730088lbb; Mon, 16 Nov 2015 21:45:54 -0800 (PST) X-Received: by 10.68.239.67 with SMTP id vq3mr755853pbc.47.1447739153967; Mon, 16 Nov 2015 21:45:53 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ot9si55636592pbb.222.2015.11.16.21.45.53; Mon, 16 Nov 2015 21:45:53 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-serial-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-serial-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-serial-owner@vger.kernel.org; dkim=neutral (body hash did not verify) header.i=@linaro_org.20150623.gappssmtp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751220AbbKQFpx (ORCPT + 1 other); Tue, 17 Nov 2015 00:45:53 -0500 Received: from mail-pa0-f48.google.com ([209.85.220.48]:33826 "EHLO mail-pa0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751132AbbKQFpw (ORCPT ); Tue, 17 Nov 2015 00:45:52 -0500 Received: by padhx2 with SMTP id hx2so199984166pad.1 for ; Mon, 16 Nov 2015 21:45:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro_org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=xdpbEwfrWMEo2ElmfA26JxM0yiIxzI7FoXhbcCnInis=; b=BkOmA3xgox4QIJd5YH/+4XO2RsqiAE4Yy+TrTnsEvIWRBy5ebjhDzBB5hI0KcsSFio tP3UcosovByTZcHbeomrGioHVytlbGhgw6bZD/7ACBcDhzNEJ2Xn9FePOPDoog6jFM9c BiBPFaIjkqiN1s86KgiEnh27JGfCOiViWcDV/Wuj7SHXEYLssP3ZXwUxcrbn4QyLJL0V uxkiPBn2A39F9hlbncEgkLk9dXk7DVuJIw3ZNtZ2Ux0fJK3pjjTARdxnZLRvvuxxXFcL 3jqJ2uhPRUlWcMO6jtj+jOeuqCO1qfTCzk2P1T6CtZQQOiJTWkUoT/KJhG/hqmDESklF bbPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=xdpbEwfrWMEo2ElmfA26JxM0yiIxzI7FoXhbcCnInis=; b=RN5QWcw4cxjmXG+St+KZ9Nl3sYN3XHMvbhLX4akdED75FEgjH3Q9TgQ/KqtHrkKtq4 O+vRpEXU5Ru9k77mikBVlXKow1V00bC5OU6lnv9hTjtaBy+lbrkrWDBjeyyOBGBvOtMb GQucVYlXzyMO3siTcmGVZyliKx23YXFWyGxiOWuMk09HhFLiWOeimgCHJ+BCwUt4eUsY Qs2g1SMFp+r5KQ95oDVw/WzpMPGpnbBmjbw/XWnJSgIFcvJsXiWOrIAQ+d6gjtl2jo5d iZN05EWWVDvsKMFo/JSxJGK09rpRFIvH1LJwKXNcovjSxRm4dHMNfNUf4sOtpKmYweM3 FskA== X-Gm-Message-State: ALoCoQnrQFWQEz8qWWAbLpMo5tG1j7VzbqLPtcJqwc+RdlyDgVDFus72WXNmNLckgyMaad1M35YG X-Received: by 10.68.217.2 with SMTP id ou2mr59967013pbc.81.1447739151720; Mon, 16 Nov 2015 21:45:51 -0800 (PST) Received: from localhost.localdomain ([107.6.117.179]) by smtp.gmail.com with ESMTPSA id ur1sm4951501pbc.44.2015.11.16.21.45.44 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 16 Nov 2015 21:45:50 -0800 (PST) From: Jun Nie To: linux@arm.linux.org.uk, graeme.gregory@linaro.org, peter@hurleysoftware.com, linux-serial@vger.kernel.org, shawn.guo@linaro.org Cc: jason.liu@linaro.org, leif.lindholm@linaro.org, wan.zhijun@zte.com.cn, Jun Nie Subject: [PATCH] tty: amba-pl011: add support for ZTE UART Date: Tue, 17 Nov 2015 13:45:20 +0800 Message-Id: <1447739120-11772-1-git-send-email-jun.nie@linaro.org> X-Mailer: git-send-email 1.9.1 Sender: linux-serial-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-serial@vger.kernel.org Add complete support for the ZTE UART to the AMBA PL011 driver based on Russell King's Nov 16's patch serial for preparing ZTE UART. ZTE UART is similar to the ARM and ST variants, except it has a different register address layout, some function bits layout and requires 32-bit accesses to the registers. Use the newly introduced register bit tables support to complete support for it. Signed-off-by: Jun Nie --- drivers/tty/serial/amba-pl011.c | 133 +++++++++++++++++++++++++++++++++++++--- include/linux/amba/serial.h | 4 ++ 2 files changed, 127 insertions(+), 10 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 9e757b0..c6e1a47 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -93,6 +93,10 @@ static u16 pl011_std_offsets[REG_ARRAY_SIZE] = { struct vendor_data { const u16 *reg_offset; unsigned int ifls; + unsigned int fr_busy; + unsigned int fr_dsr; + unsigned int fr_cts; + unsigned int fr_ri; bool access_32b; bool oversampling; bool dma_threshold; @@ -111,6 +115,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .reg_offset = pl011_std_offsets, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -121,6 +129,10 @@ static struct vendor_data vendor_arm = { static struct vendor_data vendor_sbsa = { .reg_offset = pl011_std_offsets, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -163,6 +175,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .reg_offset = pl011_st_offsets, .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -191,7 +207,15 @@ static struct vendor_data vendor_zte = { .reg_offset = pl011_zte_offsets, .access_32b = true, .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .get_fifosize = get_fifosize_arm, + .fr_busy = ZX_UART01x_FR_BUSY, + .fr_dsr = ZX_UART01x_FR_DSR, + .fr_cts = ZX_UART01x_FR_CTS, + .fr_ri = ZX_UART011_FR_RI, + .oversampling = false, + .dma_threshold = false, + .cts_event_workaround = false, + .always_enabled = false, + .fixed_options = false, }; /* Deals with DMA transactions */ @@ -236,6 +260,10 @@ struct uart_amba_port { unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ + unsigned int fr_busy; /* vendor-specific */ + unsigned int fr_dsr; /* vendor-specific */ + unsigned int fr_cts; /* vendor-specific */ + unsigned int fr_ri; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ bool autorts; bool access_32b; @@ -1166,7 +1194,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (pl011_read(uap, REG_FR) & UART01x_FR_BUSY) + while (pl011_read(uap, REG_FR) & uap->fr_busy) barrier(); spin_lock_irq(&uap->port.lock); @@ -1415,11 +1443,11 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_DCD) uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - if (delta & UART01x_FR_DSR) + if (delta & uap->fr_dsr) uap->port.icount.dsr++; - if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + if (delta & uap->fr_cts) + uart_handle_cts_change(&uap->port, status & uap->fr_cts); wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } @@ -1492,7 +1520,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int status = pl011_read(uap, REG_FR); - return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; + return status & (uap->fr_busy|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } static unsigned int pl011_get_mctrl(struct uart_port *port) @@ -1507,9 +1535,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) result |= tiocmbit TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); - TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); - TIOCMBIT(UART011_FR_RI, TIOCM_RNG); + TIOCMBIT(uap->fr_dsr, TIOCM_DSR); + TIOCMBIT(uap->fr_cts, TIOCM_CTS); + TIOCMBIT(uap->fr_ri, TIOCM_RNG); #undef TIOCMBIT return result; } @@ -2190,7 +2218,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) */ do { status = pl011_read(uap, REG_FR); - } while (status & UART01x_FR_BUSY); + } while (status & uap->fr_busy); if (!uap->vendor->always_enabled) pl011_write(old_cr, uap, REG_CR); @@ -2472,6 +2500,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->reg_offset = vendor->reg_offset; uap->access_32b = vendor->access_32b; uap->vendor = vendor; + uap->fr_busy = vendor->fr_busy; + uap->fr_dsr = vendor->fr_dsr; + uap->fr_cts = vendor->fr_cts; + uap->fr_ri = vendor->fr_ri; uap->fifosize = vendor->get_fifosize(dev); uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; @@ -2553,6 +2585,10 @@ static int sbsa_uart_probe(struct platform_device *pdev) uap->reg_offset = vendor_sbsa.reg_offset; uap->access_32b = vendor_sbsa.access_32b; uap->vendor = &vendor_sbsa; + uap->fr_busy = vendor_sbsa.fr_busy; + uap->fr_dsr = vendor_sbsa.fr_dsr; + uap->fr_cts = vendor_sbsa.fr_cts; + uap->fr_ri = vendor_sbsa.fr_ri; uap->fifosize = 32; uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; @@ -2580,6 +2616,63 @@ static int sbsa_uart_remove(struct platform_device *pdev) return 0; } +static int zx_uart_probe(struct platform_device *pdev) +{ + struct uart_amba_port *uap; + struct vendor_data *vendor = &vendor_zte; + struct resource *res; + int portnr, ret; + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) { + ret = -ENOMEM; + goto out; + } + + uap->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(uap->clk)) { + ret = PTR_ERR(uap->clk); + goto out; + } + + uap->reg_offset = vendor->reg_offset; + uap->access_32b = vendor->access_32b; + uap->vendor = vendor; + uap->fr_busy = vendor->fr_busy; + uap->fr_dsr = vendor->fr_dsr; + uap->fr_cts = vendor->fr_cts; + uap->fr_ri = vendor->fr_ri; + uap->fifosize = 16; + uap->port.irq = platform_get_irq(pdev, 0); + uap->port.ops = &amba_pl011_pops; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ret = pl011_setup_port(&pdev->dev, uap, res, portnr); + if (ret) + return ret; + + platform_set_drvdata(pdev, uap); + + return pl011_register_port(uap); +out: + return ret; +} + +static int zx_uart_remove(struct platform_device *pdev) +{ + struct uart_amba_port *uap = platform_get_drvdata(pdev); + + uart_remove_one_port(&amba_reg, &uap->port); + pl011_unregister_port(uap); + return 0; +} + static const struct of_device_id sbsa_uart_of_match[] = { { .compatible = "arm,sbsa-uart", }, {}, @@ -2628,18 +2721,38 @@ static struct amba_driver pl011_driver = { .remove = pl011_remove, }; +static const struct of_device_id zx_uart_dt_ids[] = { + { .compatible = "zte,zx296702-uart", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, zx_uart_dt_ids); + +static struct platform_driver zx_uart_driver = { + .driver = { + .name = "zx-uart", + .owner = THIS_MODULE, + .pm = &pl011_dev_pm_ops, + .of_match_table = zx_uart_dt_ids, + }, + .probe = zx_uart_probe, + .remove = zx_uart_remove, +}; + static int __init pl011_init(void) { printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); + if (platform_driver_register(&zx_uart_driver)) + pr_warn("could not register ZX UART platform driver\n"); return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { platform_driver_unregister(&arm_sbsa_uart_platform_driver); + platform_driver_unregister(&zx_uart_driver); amba_driver_unregister(&pl011_driver); } diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index d76a19b..750f2ef 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -103,6 +103,10 @@ #define UART01x_FR_DSR 0x002 #define UART01x_FR_CTS 0x001 #define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) +#define ZX_UART01x_FR_BUSY 0x300 +#define ZX_UART01x_FR_DSR 0x008 +#define ZX_UART01x_FR_CTS 0x002 +#define ZX_UART011_FR_RI 0x001 #define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ #define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */