From patchwork Sun Apr 28 23:02:08 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julien Grall X-Patchwork-Id: 16491 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-qe0-f69.google.com (mail-qe0-f69.google.com [209.85.128.69]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D78262395E for ; Sun, 28 Apr 2013 23:03:52 +0000 (UTC) Received: by mail-qe0-f69.google.com with SMTP id a11sf3958826qen.4 for ; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:mime-version:x-beenthere:x-received:received-spf :x-received:x-forwarded-to:x-forwarded-for:delivered-to:x-received :received-spf:x-received:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :x-google-group-id:list-post:list-help:list-archive:list-unsubscribe; bh=JHCrhXKR2wZpSgdPqq63mZXqIqdSMACk4mvzCX7Lh44=; b=C56iUDubNOc7zg1RDloqzj0tbZ7HzjAMuNy8hUWvBxf+SwNJqlNrOJd/BGS2A3RYQu GzvD4vERm0ZVaxmOIcUyQa17JPKKb/L7OBrsMIS4xI0CiSVlu6rXNdTMYS6WakZlnxPG Dzn1atavXZ2VZ2lZv7HdouRyo/ppJLpEGXG2w6xNS7eXTcAG0moKqzXH4/HGwzbOoi8R zFDu3QoU5bmhwPVoFdjOGC4Dm+KmG+Bz3s8AdwOSAkmxA6y2+JtLGZQA/qsWLKH0SBVn S3p66A2By6fmzETXanQp5Jzl5CFrwGaFTEF+PLZS6RwE01mC25HLXBNggN8SrYO+7End jjDQ== X-Received: by 10.224.18.133 with SMTP id w5mr8499180qaa.1.1367190171740; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.14.103 with SMTP id o7ls1104696qec.9.gmail; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) X-Received: by 10.52.26.209 with SMTP id n17mr28012155vdg.26.1367190171575; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) Received: from mail-vb0-x22f.google.com (mail-vb0-x22f.google.com [2607:f8b0:400c:c02::22f]) by mx.google.com with ESMTPS id da5si8960429vdc.89.2013.04.28.16.02.51 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 28 Apr 2013 16:02:51 -0700 (PDT) Received-SPF: neutral (google.com: 2607:f8b0:400c:c02::22f is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=2607:f8b0:400c:c02::22f; Received: by mail-vb0-f47.google.com with SMTP id x14so204734vbb.20 for ; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) X-Received: by 10.220.39.69 with SMTP id f5mr32709359vce.45.1367190171388; Sun, 28 Apr 2013 16:02:51 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.58.127.98 with SMTP id nf2csp33809veb; Sun, 28 Apr 2013 16:02:50 -0700 (PDT) X-Received: by 10.194.133.130 with SMTP id pc2mr11081724wjb.35.1367190170360; Sun, 28 Apr 2013 16:02:50 -0700 (PDT) Received: from mail-we0-x22e.google.com (mail-we0-x22e.google.com [2a00:1450:400c:c03::22e]) by mx.google.com with ESMTPS id e13si1402091wjr.101.2013.04.28.16.02.50 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 28 Apr 2013 16:02:50 -0700 (PDT) Received-SPF: neutral (google.com: 2a00:1450:400c:c03::22e is neither permitted nor denied by best guess record for domain of julien.grall@linaro.org) client-ip=2a00:1450:400c:c03::22e; Received: by mail-we0-f174.google.com with SMTP id t9so4431049wey.33 for ; Sun, 28 Apr 2013 16:02:50 -0700 (PDT) X-Received: by 10.180.13.166 with SMTP id i6mr14190095wic.21.1367190169897; Sun, 28 Apr 2013 16:02:49 -0700 (PDT) Received: from belegaer.uk.xensource.com. (firewall.ctxuk.citrix.com. [46.33.159.2]) by mx.google.com with ESMTPSA id k5sm18711393wiy.5.2013.04.28.16.02.48 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sun, 28 Apr 2013 16:02:49 -0700 (PDT) From: Julien Grall To: xen-devel@lists.xen.org Cc: ian.campbell@citrix.com, patches@linaro.org, anthony.perard@citrix.com, stefano.stabellini@eu.citrix.com, Julien Grall Subject: [RFC 25/29] xen/arm: Add exynos 4210 UART support Date: Mon, 29 Apr 2013 00:02:08 +0100 Message-Id: X-Mailer: git-send-email 1.7.10.4 In-Reply-To: References: X-Gm-Message-State: ALoCoQk2EjiStWiDs0HDvXllf5IRWFrcTUhQz+V0Z6OJS8h4xKfORrwAy/La3cIAAke50W5DnSR6 X-Original-Sender: julien.grall@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 2607:f8b0:400c:c02::22f is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , Signed-off-by: Julien Grall --- config/arm32.mk | 1 + xen/drivers/char/Makefile | 1 + xen/drivers/char/exynos5-uart.c | 346 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 xen/drivers/char/exynos5-uart.c diff --git a/config/arm32.mk b/config/arm32.mk index 83a7767..593a1d1 100644 --- a/config/arm32.mk +++ b/config/arm32.mk @@ -19,6 +19,7 @@ CFLAGS += -marm # - pl011: printk with PL011 UART CONFIG_EARLY_PRINTK := none HAS_PL011 := y +HAS_EXYNOS5 := y # Use only if calling $(LD) directly. #LDFLAGS_DIRECT_OpenBSD = _obsd diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile index e68a54a..12a4b49 100644 --- a/xen/drivers/char/Makefile +++ b/xen/drivers/char/Makefile @@ -1,6 +1,7 @@ obj-y += console.o obj-$(HAS_NS16550) += ns16550.o obj-$(HAS_PL011) += pl011.o +obj-$(HAS_EXYNOS5) += exynos5-uart.o obj-$(HAS_EHCI) += ehci-dbgp.o obj-$(CONFIG_ARM) += arm-uart.o obj-y += serial.o diff --git a/xen/drivers/char/exynos5-uart.c b/xen/drivers/char/exynos5-uart.c new file mode 100644 index 0000000..1bae153 --- /dev/null +++ b/xen/drivers/char/exynos5-uart.c @@ -0,0 +1,346 @@ +/* + * xen/drivers/char/exynos5-uart.c + * + * Driver for Exynos 4210 UART. + * + * Anthony PERARD + * Copyright (c) 2012 Citrix Systems. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct exynos5_uart { + unsigned int baud, clock_hz, data_bits, parity, stop_bits; + struct dt_irq irq; + volatile uint32_t *regs; + struct irqaction irqaction; +} exynos5_com[2] = {{0}}; + +/* register addresses */ +#define ULCON (0x00/4) +#define UCON (0x04/4) +#define UFCON (0x08/4) +#define UMCON (0x0c/4) +#define UTRSTAT (0x10/4) +#define UERSTAT (0x14/4) +#define UFSTAT (0x18/4) +#define UMSTAT (0x1c/4) +#define UTXH (0x20/4) +#define URXH (0x24/4) +#define UBRDIV (0x28/4) +#define UFRACVAL (0x2c/4) +#define UINTP (0x30/4) +#define UINTS (0x34/4) +#define UINTM (0x38/4) + +/* ULCON */ +#define RXIRQ (0x1<<0) +#define RXDMA (0x2<<0) +#define TXIRQ (0x1<<2) +#define TXDMA (0x2<<2) + +/* UFCON */ +#define FIFO_TX_RESET (1<<2) +#define FIFO_RX_RESET (1<<1) +#define FIFO_EN (1<<0) + +/* UMCON */ +#define INT_EN (1<<3) + +/* UTRSTAT */ +#define TXE (1<<2) +#define TXFE (1<<1) +#define RXDR (1<<0) + +/* Interrupt bits (UINTP, UINTS, UINTM) */ +#define MODEM (1<<3) +#define TXD (1<<2) +#define ERROR (1<<1) +#define RXD (1<<0) +#define ALLI (MODEM|TXD|ERROR|RXD) + +/* These parity settings can be ORed directly into the ULCON. */ +#define PARITY_NONE (0) +#define PARITY_ODD (0x4) +#define PARITY_EVEN (0x5) +#define FORCED_CHECKED_AS_ONE (0x6) +#define FORCED_CHECKED_AS_ZERO (0x7) + +static void exynos5_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs) +{ + struct serial_port *port = data; + struct exynos5_uart *uart = port->uart; + unsigned int status = uart->regs[UINTP]; + + if ( status ) + { + do + { + // clear all pending interrept + // but should take care of ERROR and MODEM + + if ( status & ERROR ) + { + int error_bit = uart->regs[UERSTAT] & 0xf; + if ( error_bit & (1 << 0) ) + printk(XENLOG_ERR "uart: overrun error\n"); + if ( error_bit & (1 << 1) ) + printk(XENLOG_ERR "uart: parity error\n"); + if ( error_bit & (1 << 2) ) + printk(XENLOG_ERR "uart: frame error\n"); + if ( error_bit & (1 << 3) ) + printk(XENLOG_ERR "uart: break detected\n"); + uart->regs[UINTP] = ERROR; + } + + + if ( status & (RXD|ERROR) ) + { + /* uart->regs[UINTM] |= RXD|ERROR; */ + serial_rx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(RXD|ERROR); */ + uart->regs[UINTP] = RXD|ERROR; + } + + if ( status & (TXD|MODEM) ) + { + /* uart->regs[UINTM] |= TXD|MODEM; */ + serial_tx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(TXD|MODEM); */ + uart->regs[UINTP] = TXD|MODEM; + } + + status = uart->regs[UINTP]; + } while ( status != 0 ); + } +} + +static void __init exynos5_uart_init_preirq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + unsigned int divisor; + + /* reset, TX/RX disables */ + uart->regs[UCON] = 0x0; + + /* No Interrupt, auto flow control */ + uart->regs[UMCON] = 0x0; + + /* Line control and baud-rate generator. */ + if ( uart->baud != BAUD_AUTO ) + { + /* Baud rate specified: program it into the divisor latch. */ + // div_val = ubrdiv + ufracval/16 + // or + // div_val = (clock_uart/(baud*16))-1 + divisor = ((uart->clock_hz) / (uart->baud)) - 1; + // FIXME will use a hacked divisor, assuming the src clock and bauds + uart->regs[UFRACVAL] = 53; + uart->regs[UBRDIV] = 4; + /* uart->regs[UFRACVAL] = divisor & 0xf; */ + /* uart->regs[UBRDIV] = divisor >> 4; */ + } + else + { + // TODO, should be updated + /* Baud rate already set: read it out from the divisor latch. */ + //divisor = (uart->regs[IBRD] << 6) | uart->regs[FBRD]; + //uart->baud = (uart->clock_hz << 2) / divisor; + } + uart->regs[ULCON] = ( (uart->data_bits - 5) << 0 + | ((uart->stop_bits - 1) << 2) + | uart->parity << 3 ); + + /* Mask and clear the interrupts */ + uart->regs[UINTM] = ALLI; + uart->regs[UINTP] = ALLI; + + /* enable FIFO */ + uart->regs[UFCON] = FIFO_TX_RESET | FIFO_RX_RESET; + while ( uart->regs[UFCON] & (FIFO_TX_RESET | FIFO_RX_RESET) ) + ; + // reset FIFO_TX_RESET | FIFO_RX_RESET | + uart->regs[UFCON] = (0x6 << 8) | FIFO_EN; + + /* Enable the UART for RX and TX */ + // level tx/rx interrupt,only rx + // enable rx timeout interrupt + uart->regs[UCON] = (0 << 9) | (0 << 8) | RXIRQ | TXIRQ | ( 1 << 7); +} + +static void __init exynos5_uart_init_postirq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + int rc; + + if ( uart->irq.irq > 0 ) + { + uart->irqaction.handler = exynos5_uart_interrupt; + uart->irqaction.name = "exynos5_uart"; + uart->irqaction.dev_id = port; + if ( (rc = setup_irq(uart->irq.irq, &uart->irqaction)) != 0 ) + printk("ERROR: Failed to allocate exynos5_uart IRQ %d\n", + uart->irq.irq); + + /* Unmask interrupts */ + uart->regs[UINTM] = 0; //MODEM|TXD|ERROR; // only have rx interrupt + + /* Clear pending error interrupts */ + uart->regs[UINTP] = ALLI; + + /* Enable interrupts */ + uart->regs[UMCON] |= INT_EN; + } +} + +static void exynos5_uart_suspend(struct serial_port *port) +{ + BUG(); // XXX +} + +static void exynos5_uart_resume(struct serial_port *port) +{ + BUG(); // XXX +} + +static unsigned int exynos5_uart_tx_ready(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + + // Tx FIFO full + if ( uart->regs[UFSTAT] & (1 << 24) ) + return 0; + else + { + int x = 16 - ((uart->regs[UFSTAT] >> 16) & 0xff); + // Tx FIFO count + if ( x > 0 ) + return x; + else if ( x == 0 ) + return 0; + else { + panic("unwanted value: %d\n", x); + return 0; + } + } +} + +static void exynos5_uart_putc(struct serial_port *port, char c) +{ + struct exynos5_uart *uart = port->uart; + uart->regs[UTXH] = (uint32_t) (unsigned char) c; +} + +static int exynos5_uart_getc(struct serial_port *port, char *pc) +{ + struct exynos5_uart *uart = port->uart; + + // check if rx fifo is full or if there is something in it + if ( (uart->regs[UFSTAT] & (1 << 8)) || (uart->regs[UFSTAT] & 0xff) ) + { + *pc = uart->regs[URXH] & 0xff; + return 1; + } + else + return 0; +} + +static int __init exynos5_uart_irq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + if ( uart->irq.irq > 0 ) + return uart->irq.irq; + else + return -1; +} + +static const struct dt_irq __init *exynos5_uart_dt_irq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + + return &uart->irq; +} + +static struct uart_driver __read_mostly exynos5_uart_driver = { + .init_preirq = exynos5_uart_init_preirq, + .init_postirq = exynos5_uart_init_postirq, + .endboot = NULL, + .suspend = exynos5_uart_suspend, + .resume = exynos5_uart_resume, + .tx_ready = exynos5_uart_tx_ready, + .putc = exynos5_uart_putc, + .getc = exynos5_uart_getc, + .irq = exynos5_uart_irq, + .dt_irq_get = exynos5_uart_dt_irq, +}; + +static int __init exynos5_uart_init(struct dt_device_node *dev, + const void *data) +{ + const struct serial_arm_defaults *defaults = data; + struct exynos5_uart *uart; + int res; + + if ( (defaults->index < 0) || (defaults->index > 1) ) + return -EINVAL; + + uart = &exynos5_com[defaults->index]; + + /* uart->clock_hz = 0x16e3600; */ + uart->baud = BAUD_AUTO;//115200; + uart->data_bits = 8; + uart->parity = PARITY_NONE; + uart->stop_bits = 1; + uart->regs = (uint32_t *) defaults->register_base_address; + + res = dt_device_get_irq(dev, 0, &uart->irq); + if ( res ) + { + early_printk("exynos5: Unable to retrieve the IRQ\n"); + return res; + } + + /* Register with generic serial driver. */ + serial_register_uart(uart - exynos5_com, &exynos5_uart_driver, uart); + + dt_device_set_used_by(dev, DT_USED_BY_XEN); + + return 0; +} + +static const char const *exynos5_dt_compat[] __initdata = +{ + "samsung,exynos4210-uart", + NULL +}; + +DT_DEVICE_START(exynos5, "Exynos5 UART", DEVICE_SERIAL) + .compatible = exynos5_dt_compat, + .init = exynos5_uart_init, +DT_DEVICE_END + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */