From patchwork Wed Dec 10 05:44:49 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nobuhiro Iwamatsu X-Patchwork-Id: 419428 X-Patchwork-Delegate: iwamatsu@nigauri.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 9745C1400B7 for ; Wed, 10 Dec 2014 16:45:11 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3CAD94B601; Wed, 10 Dec 2014 06:45:10 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kZ4fxgWyPToJ; Wed, 10 Dec 2014 06:45:10 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id D78AB4B5F5; Wed, 10 Dec 2014 06:45:09 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AC4F34B5F5 for ; Wed, 10 Dec 2014 06:45:05 +0100 (CET) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yPw91OzerPpm for ; Wed, 10 Dec 2014 06:45:05 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pd0-f182.google.com (mail-pd0-f182.google.com [209.85.192.182]) by theia.denx.de (Postfix) with ESMTPS id 18D5A4B5E4 for ; Wed, 10 Dec 2014 06:45:00 +0100 (CET) Received: by mail-pd0-f182.google.com with SMTP id p10so2098795pdj.13 for ; Tue, 09 Dec 2014 21:44:59 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=0jzbyISJTD7eIP7rU0s+42S8xzhhCfprHbNOlnpGDlA=; b=jpTSMkwva2tiZYfWuftYpHr+XBASGU5heyR6yhGsFakvDDeDk4Q/6mHW/gtckxV+bE o1RrGus0sjcu0rQ/BB9APNjrJMlOeRF1kzp9KvODov0Dj+Mm587/6jUdWADEUE6EPhMP j3nskwtxXahr2mDaBnKMwzA5AvfkUzVqE8co37U5+r8nBWyRSdLHJwFX/GsQ99RfPmS4 +I74uv28ZrFBQeaVidx7zoFLrJDRIzRATAVFKAGmPG0DRUeJacDFK84T9pgeJjkjLf07 rf2bbImMc2SPwxY44hNZhvqYy/MjhlC4acpVqbTEdkGKTQQ54zkGaCmKG0o2KEX8UKg3 iL2w== X-Gm-Message-State: ALoCoQl1pa08/+Iq/hR0rYSDx04ygDJ9RWXmD7wX+ud1gG8EwOntaUSqEnWj345r5rq4qKCS3Cpr X-Received: by 10.66.254.232 with SMTP id al8mr3970344pad.76.1418190299060; Tue, 09 Dec 2014 21:44:59 -0800 (PST) Received: from xps-iwamatsu.renesas.com (49.14.32.202.bf.2iij.net. [202.32.14.49]) by mx.google.com with ESMTPSA id v4sm3020851pdc.61.2014.12.09.21.44.56 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 09 Dec 2014 21:44:57 -0800 (PST) From: Nobuhiro Iwamatsu To: u-boot@lists.denx.de, Simon Glass Date: Wed, 10 Dec 2014 14:44:49 +0900 Message-Id: <1418190289-18354-1-git-send-email-nobuhiro.iwamatsu.yj@renesas.com> X-Mailer: git-send-email 2.1.3 Cc: Nobuhiro Iwamatsu Subject: [U-Boot] [PATCH] dm: sh: serial: Add support driver model X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.13 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This adds driver model support with this driver. This was tested by Koelsch board and Gose board. Signed-off-by: Nobuhiro Iwamatsu --- drivers/serial/serial_sh.c | 299 ++++++++++++++++++++++++----------- drivers/serial/serial_sh.h | 10 +- include/dm/platform_data/serial_sh.h | 37 +++++ 3 files changed, 245 insertions(+), 101 deletions(-) create mode 100644 include/dm/platform_data/serial_sh.h diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 7c1f271..dd5f9bf 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -1,78 +1,20 @@ /* * SuperH SCIF device driver. * Copyright (C) 2013 Renesas Electronics Corporation - * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu + * Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu * Copyright (C) 2002 - 2008 Paul Mundt * * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include #include -#include "serial_sh.h" #include #include - -#if defined(CONFIG_CONS_SCIF0) -# define SCIF_BASE SCIF0_BASE -#elif defined(CONFIG_CONS_SCIF1) -# define SCIF_BASE SCIF1_BASE -#elif defined(CONFIG_CONS_SCIF2) -# define SCIF_BASE SCIF2_BASE -#elif defined(CONFIG_CONS_SCIF3) -# define SCIF_BASE SCIF3_BASE -#elif defined(CONFIG_CONS_SCIF4) -# define SCIF_BASE SCIF4_BASE -#elif defined(CONFIG_CONS_SCIF5) -# define SCIF_BASE SCIF5_BASE -#elif defined(CONFIG_CONS_SCIF6) -# define SCIF_BASE SCIF6_BASE -#elif defined(CONFIG_CONS_SCIF7) -# define SCIF_BASE SCIF7_BASE -#else -# error "Default SCIF doesn't set....." -#endif - -#if defined(CONFIG_SCIF_A) - #define SCIF_BASE_PORT PORT_SCIFA -#else - #define SCIF_BASE_PORT PORT_SCIF -#endif - -static struct uart_port sh_sci = { - .membase = (unsigned char*)SCIF_BASE, - .mapbase = SCIF_BASE, - .type = SCIF_BASE_PORT, -}; - -static void sh_serial_setbrg(void) -{ - DECLARE_GLOBAL_DATA_PTR; -#ifdef CONFIG_SCIF_USE_EXT_CLK - unsigned short dl = DL_VALUE(gd->baudrate, CONFIG_SH_SCIF_CLK_FREQ); - sci_out(&sh_sci, DL, dl); - /* Need wait: Clock * 1/dl × 1/16 */ - udelay((1000000 * dl * 16 / CONFIG_SYS_CLK_FREQ) * 1000 + 1); -#else - sci_out(&sh_sci, SCBRR, - SCBRR_VALUE(gd->baudrate, CONFIG_SH_SCIF_CLK_FREQ)); -#endif -} - -static int sh_serial_init(void) -{ - sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); - sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); - sci_out(&sh_sci, SCSMR, 0); - sci_out(&sh_sci, SCSMR, 0); - sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST); - sci_in(&sh_sci, SCFCR); - sci_out(&sh_sci, SCFCR, 0); - - serial_setbrg(); - return 0; -} +#include +#include "serial_sh.h" #if defined(CONFIG_CPU_SH7760) || \ defined(CONFIG_CPU_SH7780) || \ @@ -109,83 +51,249 @@ static int scif_rxfill(struct uart_port *port) } #endif -static int serial_rx_fifo_level(void) +static void sh_serial_init_generic(struct uart_port *port) +{ + sci_out(port, SCSCR , SCSCR_INIT(port)); + sci_out(port, SCSCR , SCSCR_INIT(port)); + sci_out(port, SCSMR, 0); + sci_out(port, SCSMR, 0); + sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST); + sci_in(port, SCFCR); + sci_out(port, SCFCR, 0); +} + +static void +sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate) { - return scif_rxfill(&sh_sci); + if (port->clk_mode == EXT_CLK) { + unsigned short dl = DL_VALUE(baudrate, clk); + sci_out(port, DL, dl); + /* Need wait: Clock * 1/dl × 1/16 */ + udelay((1000000 * dl * 16 / clk) * 1000 + 1); + } else { + sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk)); + } } -static void handle_error(void) +static void handle_error(struct uart_port *port) { - sci_in(&sh_sci, SCxSR); - sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci)); - sci_in(&sh_sci, SCLSR); - sci_out(&sh_sci, SCLSR, 0x00); + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_in(port, SCLSR); + sci_out(port, SCLSR, 0x00); } -static void serial_raw_putc(const char c) +static void serial_raw_putc(struct uart_port *port, const char c) { while (1) { /* Tx fifo is empty */ - if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci)) + if (sci_in(port, SCxSR) & SCxSR_TEND(port)) break; } - sci_out(&sh_sci, SCxTDR, c); - sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); + sci_out(port, SCxTDR, c); + sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port)); } -static void sh_serial_putc(const char c) +static void sh_serial_putc_generic(struct uart_port *port, const char c) { if (c == '\n') - serial_raw_putc('\r'); - serial_raw_putc(c); + serial_raw_putc(port, '\r'); + serial_raw_putc(port, c); } -static int sh_serial_tstc(void) +static int serial_rx_fifo_level(struct uart_port *port) { - if (sci_in(&sh_sci, SCxSR) & SCIF_ERRORS) { - handle_error(); + return scif_rxfill(port); +} + +static int sh_serial_tstc_generic(struct uart_port *port) +{ + if (sci_in(port, SCxSR) & SCIF_ERRORS) { + handle_error(port); return 0; } - return serial_rx_fifo_level() ? 1 : 0; + return serial_rx_fifo_level(port) ? 1 : 0; } - -static int serial_getc_check(void) +static int serial_getc_check(struct uart_port *port) { unsigned short status; - status = sci_in(&sh_sci, SCxSR); + status = sci_in(port, SCxSR); if (status & SCIF_ERRORS) - handle_error(); - if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) - handle_error(); - return status & (SCIF_DR | SCxSR_RDxF(&sh_sci)); + handle_error(port); + if (sci_in(port, SCLSR) & SCxSR_ORER(port)) + handle_error(port); + return status & (SCIF_DR | SCxSR_RDxF(port)); } -static int sh_serial_getc(void) +static int sh_serial_getc_generic(struct uart_port *port) { unsigned short status; char ch; - while (!serial_getc_check()) + while (!serial_getc_check(port)) ; - ch = sci_in(&sh_sci, SCxRDR); - status = sci_in(&sh_sci, SCxSR); + ch = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); - sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci)); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); if (status & SCIF_ERRORS) - handle_error(); + handle_error(port); + + if (sci_in(port, SCLSR) & SCxSR_ORER(port)) + handle_error(port); - if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) - handle_error(); return ch; } +#ifdef CONFIG_DM_SERIAL + +static int sh_serial_pending(struct udevice *dev, bool input) +{ + struct uart_port *priv = dev_get_priv(dev); + + return sh_serial_tstc_generic(priv); +} + +static int sh_serial_putc(struct udevice *dev, const char ch) +{ + struct uart_port *priv = dev_get_priv(dev); + + sh_serial_putc_generic(priv, ch); + + return 0; +} + +static int sh_serial_getc(struct udevice *dev) +{ + struct uart_port *priv = dev_get_priv(dev); + + return sh_serial_getc_generic(priv); +} + +static int sh_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct sh_serial_platdata *plat = dev_get_platdata(dev); + struct uart_port *priv = dev_get_priv(dev); + + sh_serial_setbrg_generic(priv, plat->clk, baudrate); + + return 0; +} + +static int sh_serial_probe(struct udevice *dev) +{ + struct sh_serial_platdata *plat = dev_get_platdata(dev); + struct uart_port *priv = dev_get_priv(dev); + + priv->membase = (unsigned char *)plat->base; + priv->mapbase = plat->base; + priv->type = plat->type; + priv->clk_mode = plat->clk_mode; + + sh_serial_init_generic(priv); + + return 0; +} + +static const struct dm_serial_ops sh_serial_ops = { + .putc = sh_serial_putc, + .pending = sh_serial_pending, + .getc = sh_serial_getc, + .setbrg = sh_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_sh) = { + .name = "serial_sh", + .id = UCLASS_SERIAL, + .probe = sh_serial_probe, + .ops = &sh_serial_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct uart_port), +}; + +#else /* CONFIG_DM_SERIAL */ + +#if defined(CONFIG_CONS_SCIF0) +# define SCIF_BASE SCIF0_BASE +#elif defined(CONFIG_CONS_SCIF1) +# define SCIF_BASE SCIF1_BASE +#elif defined(CONFIG_CONS_SCIF2) +# define SCIF_BASE SCIF2_BASE +#elif defined(CONFIG_CONS_SCIF3) +# define SCIF_BASE SCIF3_BASE +#elif defined(CONFIG_CONS_SCIF4) +# define SCIF_BASE SCIF4_BASE +#elif defined(CONFIG_CONS_SCIF5) +# define SCIF_BASE SCIF5_BASE +#elif defined(CONFIG_CONS_SCIF6) +# define SCIF_BASE SCIF6_BASE +#elif defined(CONFIG_CONS_SCIF7) +# define SCIF_BASE SCIF7_BASE +#else +# error "Default SCIF doesn't set....." +#endif + +#if defined(CONFIG_SCIF_A) + #define SCIF_BASE_PORT PORT_SCIFA +#else + #define SCIF_BASE_PORT PORT_SCIF +#endif + +static struct uart_port sh_sci = { + .membase = (unsigned char *)SCIF_BASE, + .mapbase = SCIF_BASE, + .type = SCIF_BASE_PORT, +#ifdef CONFIG_SCIF_USE_EXT_CLK + .clk_mode = EXT_CLK, +#endif +}; + +static void sh_serial_setbrg(void) +{ + DECLARE_GLOBAL_DATA_PTR; + struct uart_port *port = &sh_sci; + + sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate); +} + +static int sh_serial_init(void) +{ + struct uart_port *port = &sh_sci; + + sh_serial_init_generic(port); + serial_setbrg(); + + return 0; +} + +static void sh_serial_putc(const char c) +{ + struct uart_port *port = &sh_sci; + + sh_serial_putc_generic(port, c); +} + +static int sh_serial_tstc(void) +{ + struct uart_port *port = &sh_sci; + + return sh_serial_tstc_generic(port); +} + +static int sh_serial_getc(void) +{ + struct uart_port *port = &sh_sci; + + return sh_serial_getc_generic(port); +} + static struct serial_device sh_serial_drv = { .name = "sh_serial", .start = sh_serial_init, @@ -206,3 +314,4 @@ __weak struct serial_device *default_serial_console(void) { return &sh_serial_drv; } +#endif /* CONFIG_DM_SERIAL */ diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index ef88c8f..4b6199a 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -2,18 +2,16 @@ * Copy and modify from linux/drivers/serial/sh-sci.h */ +#include + struct uart_port { unsigned long iobase; /* in/out[bwl] */ unsigned char *membase; /* read/write[bwl] */ unsigned long mapbase; /* for ioremap */ - unsigned int type; /* port type */ + enum sh_serial_type type; /* port type */ + enum sh_clk_mode clk_mode; /* clock mode */ }; -#define PORT_SCI 52 -#define PORT_SCIF 53 -#define PORT_SCIFA 83 -#define PORT_SCIFB 93 - #if defined(CONFIG_H83007) || defined(CONFIG_H83068) #include #endif diff --git a/include/dm/platform_data/serial_sh.h b/include/dm/platform_data/serial_sh.h new file mode 100644 index 0000000..0271ad6 --- /dev/null +++ b/include/dm/platform_data/serial_sh.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 Nobuhiro Iwamatsu + * Copyright (c) 2014 Renesas Electronics Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __serial_sh_h +#define __serial_sh_h + +enum sh_clk_mode { + INT_CLK, + EXT_CLK, +}; + +enum sh_serial_type { + PORT_SCI, + PORT_SCIF, + PORT_SCIFA, + PORT_SCIFB, +}; + +/* + * Information about SCIF port + * + * @base: Register base address + * @clk: Input clock rate, used for calculating the baud rate divisor + * @clk_mode: Clock mode, set internal (INT) or external (EXT) + * @type: Type of SCIF + */ +struct sh_serial_platdata { + unsigned long base; + unsigned int clk; + enum sh_clk_mode clk_mode; + enum sh_serial_type type; +}; +#endif /* __serial_sh_h */