From patchwork Wed Sep 14 12:15:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zhichang Yuan X-Patchwork-Id: 9331289 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 9E72C60231 for ; Wed, 14 Sep 2016 12:03:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8E43629D10 for ; Wed, 14 Sep 2016 12:03:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 824AD29D1C; Wed, 14 Sep 2016 12:03:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 82A3E29D18 for ; Wed, 14 Sep 2016 12:03:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1761900AbcINMDB (ORCPT ); Wed, 14 Sep 2016 08:03:01 -0400 Received: from szxga02-in.huawei.com ([119.145.14.65]:57964 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1761918AbcINMC4 (ORCPT ); Wed, 14 Sep 2016 08:02:56 -0400 Received: from 172.24.1.136 (EHLO szxeml425-hub.china.huawei.com) ([172.24.1.136]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DNB40047; Wed, 14 Sep 2016 19:58:06 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by szxeml425-hub.china.huawei.com (10.82.67.180) with Microsoft SMTP Server id 14.3.235.1; Wed, 14 Sep 2016 19:57:54 +0800 From: Zhichang Yuan To: , , CC: , , , , , , , , , , , , , , , , "zhichang.yuan" Subject: [PATCH V3 4/4] ARM64 LPC: support earlycon for UART connected to LPC Date: Wed, 14 Sep 2016 20:15:54 +0800 Message-ID: <1473855354-150093-5-git-send-email-yuanzhichang@hisilicon.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com> References: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020203.57D93B4E.01B7, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 846f5b5ce11f8fa2f16c2811bc3bf71d Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: "zhichang.yuan" This patch support the earlycon for UART connected to LPC on Hip06. This patch is depended on the LPC driver. Signed-off-by: zhichang.yuan --- drivers/bus/hisi_lpc.c | 113 +++++++++++++++++++++++++++++++++++ drivers/tty/serial/8250/8250_early.c | 26 +++++++- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index 9b364d0..2269828 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -360,6 +360,119 @@ void hisilpc_comm_outb(void *devobj, unsigned long ptaddr, /** + * hisilpc_early_in - read/input operation specific for hisi LPC earlycon. + * @devobj: pointer to device relevant information of the caller. + * @inbuf: the buffer where the read back data is populated. + * + * for earlycon, dlen and count should be one. + * + * Return the data read from earlycon on success, error ID on fail. + * + */ +static unsigned int __init hisilpc_early_in(struct uart_port *port, int offset) +{ + unsigned int backval = 0; + unsigned int ret = 0; + struct lpc_cycle_para para; + struct hisilpc_dev lpcdev; + + if (!port->mapbase || !port->iobase || !port->membase) + return -EINVAL; + + para.opflags = FG_EARLYCON_LPC; + para.csize = 1; + lpcdev.membase = port->membase; + + ret = hisilpc_target_in(&lpcdev, ¶, + port->iobase + (offset << port->regshift), + (unsigned char *)&backval, 1); + return (ret) ? : backval; +} + +/** + * hisilpc_early_out - write/output operation specific for hisi LPC earlycon. + * @port: pointer to uart_port of eralycon + * + * for earlycon, dlen and count should be one. + * + */ +static void __init hisilpc_early_out(struct uart_port *port, int offset, + int value) +{ + struct lpc_cycle_para para; + struct hisilpc_dev lpcdev; + + if (!port->mapbase || !port->iobase || !port->membase) + return; + + para.opflags = FG_EARLYCON_LPC; + para.csize = 1; + lpcdev.membase = port->membase; + + (void)hisilpc_target_out(&lpcdev, ¶, + port->iobase + (offset << port->regshift), + (unsigned char *)&value, 1); +} + + +/** + * early_hisilpc8250_setup - initilize the lpc earlycon + * @device: pointer to the elarycon device + * @options: a option string from earlycon kernel-parameter + * + * Returns 0 on success, non-zero on fail. + * + */ +static int __init early_hisilpc8250_setup(struct earlycon_device *device, + const char *options) +{ + char *p; + int ret; + + if (!device->port.membase) + return -ENODEV; + + if (device->port.iotype != UPIO_MEM) + return -EINVAL; + + if (device->options) { + p = strchr(device->options, ','); + if (p && (p + 1) != '\0') { + ret = kstrtoul(++p, 0, + (unsigned long *)&device->port.iobase); + if (ret || device->port.iobase == 0) + return ret ?: -EFAULT; + } else + device->port.iobase = 0x2f8; + } else { + device->port.iobase = 0x2f8; + device->baud = 0; + } + + device->port.serial_in = hisilpc_early_in; + device->port.serial_out = hisilpc_early_out; + /* must convert iotype to UPIO_PORT for Hip06 indirect-io */ + device->port.iotype = UPIO_PORT; + + /* disable interrupts from LPC */ + writel(LPC_IRQ_CLEAR, device->port.membase + LPC_REG_IRQ_ST); + /* ensure the LPC is available */ + while (!(readl(device->port.membase + LPC_REG_OP_STATUS) & + LPC_STATUS_IDLE)) + cpu_relax(); + + return early_serial8250_setup(device, options); +} + + + +EARLYCON_DECLARE(hisilpcuart, early_hisilpc8250_setup); +OF_EARLYCON_DECLARE(hisilpcuart, "hisilicon,lpc-uart", + early_hisilpc8250_setup); + + + +/** * hisilpc_ischild_ipmi - check whether the designated device is ipmi * @dev: the device to be checked. * @data: the value used to match the acpi device in checking. diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 85a12f0..3b5d0a8 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -37,7 +37,7 @@ #include #include -static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) +static unsigned int __init serial8250_early_in_raw(struct uart_port *port, int offset) { offset <<= port->regshift; @@ -57,7 +57,7 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse } } -static void __init serial8250_early_out(struct uart_port *port, int offset, int value) +static void __init serial8250_early_out_raw(struct uart_port *port, int offset, int value) { offset <<= port->regshift; @@ -80,6 +80,28 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int } } +static inline void __init serial8250_early_out(struct uart_port *port, + int offset, int value) +{ + if (port->serial_out) + port->serial_out(port, offset, value); + else { + port->serial_out = serial8250_early_out_raw; + serial8250_early_out_raw(port, offset, value); + } +} + +static inline unsigned int __init serial8250_early_in(struct uart_port *port, + int offset) +{ + if (port->serial_in) + return port->serial_in(port, offset); + + port->serial_in = serial8250_early_in_raw; + return serial8250_early_in_raw(port, offset); +} + + #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) static void __init serial_putc(struct uart_port *port, int c)