129592ecbSNobuhiro Iwamatsu /* 229592ecbSNobuhiro Iwamatsu * SuperH SCIF device driver. 33f6c8e36SNobuhiro Iwamatsu * Copyright (C) 2007,2008,2010 Nobuhiro Iwamatsu 43f6c8e36SNobuhiro Iwamatsu * Copyright (C) 2002 - 2008 Paul Mundt 529592ecbSNobuhiro Iwamatsu * 629592ecbSNobuhiro Iwamatsu * This program is free software; you can redistribute it and/or modify 729592ecbSNobuhiro Iwamatsu * it under the terms of the GNU General Public License as published by 829592ecbSNobuhiro Iwamatsu * the Free Software Foundation; either version 2 of the License, or 929592ecbSNobuhiro Iwamatsu * (at your option) any later version. 1029592ecbSNobuhiro Iwamatsu * 1129592ecbSNobuhiro Iwamatsu * This program is distributed in the hope that it will be useful, 1229592ecbSNobuhiro Iwamatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 1329592ecbSNobuhiro Iwamatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1429592ecbSNobuhiro Iwamatsu * GNU General Public License for more details. 1529592ecbSNobuhiro Iwamatsu * 1629592ecbSNobuhiro Iwamatsu * You should have received a copy of the GNU General Public License 1729592ecbSNobuhiro Iwamatsu * along with this program; if not, write to the Free Software 1829592ecbSNobuhiro Iwamatsu * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1929592ecbSNobuhiro Iwamatsu */ 2029592ecbSNobuhiro Iwamatsu 2129592ecbSNobuhiro Iwamatsu #include <common.h> 22fc83c927SJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 2329592ecbSNobuhiro Iwamatsu #include <asm/processor.h> 243f6c8e36SNobuhiro Iwamatsu #include "serial_sh.h" 258bdd7efaSMarek Vasut #include <serial.h> 268bdd7efaSMarek Vasut #include <linux/compiler.h> 2729565326SJohn Rigby 2829592ecbSNobuhiro Iwamatsu #if defined(CONFIG_CONS_SCIF0) 2929592ecbSNobuhiro Iwamatsu # define SCIF_BASE SCIF0_BASE 3029592ecbSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF1) 3129592ecbSNobuhiro Iwamatsu # define SCIF_BASE SCIF1_BASE 3208c5fabeSNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF2) 3308c5fabeSNobuhiro Iwamatsu # define SCIF_BASE SCIF2_BASE 34ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF3) 35ab09f433SNobuhiro Iwamatsu # define SCIF_BASE SCIF3_BASE 36ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF4) 37ab09f433SNobuhiro Iwamatsu # define SCIF_BASE SCIF4_BASE 38ab09f433SNobuhiro Iwamatsu #elif defined(CONFIG_CONS_SCIF5) 39ab09f433SNobuhiro Iwamatsu # define SCIF_BASE SCIF5_BASE 4099744b7eSPhil Edworthy #elif defined(CONFIG_CONS_SCIF6) 4199744b7eSPhil Edworthy # define SCIF_BASE SCIF6_BASE 4299744b7eSPhil Edworthy #elif defined(CONFIG_CONS_SCIF7) 4399744b7eSPhil Edworthy # define SCIF_BASE SCIF7_BASE 4429592ecbSNobuhiro Iwamatsu #else 4529592ecbSNobuhiro Iwamatsu # error "Default SCIF doesn't set....." 4629592ecbSNobuhiro Iwamatsu #endif 4729592ecbSNobuhiro Iwamatsu 48a03c09c5SNobuhiro Iwamatsu #if defined(CONFIG_SCIF_A) 493f6c8e36SNobuhiro Iwamatsu #define SCIF_BASE_PORT PORT_SCIFA 50ab09f433SNobuhiro Iwamatsu #else 513f6c8e36SNobuhiro Iwamatsu #define SCIF_BASE_PORT PORT_SCIF 52ac331da0SNobuhiro Iwamatsu #endif 53ac331da0SNobuhiro Iwamatsu 543f6c8e36SNobuhiro Iwamatsu static struct uart_port sh_sci = { 553f6c8e36SNobuhiro Iwamatsu .membase = (unsigned char*)SCIF_BASE, 563f6c8e36SNobuhiro Iwamatsu .mapbase = SCIF_BASE, 573f6c8e36SNobuhiro Iwamatsu .type = SCIF_BASE_PORT, 583f6c8e36SNobuhiro Iwamatsu }; 5929592ecbSNobuhiro Iwamatsu 608bdd7efaSMarek Vasut static void sh_serial_setbrg(void) 6129592ecbSNobuhiro Iwamatsu { 623f6c8e36SNobuhiro Iwamatsu DECLARE_GLOBAL_DATA_PTR; 633f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCBRR, SCBRR_VALUE(gd->baudrate, CONFIG_SYS_CLK_FREQ)); 6429592ecbSNobuhiro Iwamatsu } 6529592ecbSNobuhiro Iwamatsu 668bdd7efaSMarek Vasut static int sh_serial_init(void) 6729592ecbSNobuhiro Iwamatsu { 683f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); 693f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCSCR , SCSCR_INIT(&sh_sci)); 703f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCSMR, 0); 713f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCSMR, 0); 723f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCFCR, SCFCR_RFRST|SCFCR_TFRST); 733f6c8e36SNobuhiro Iwamatsu sci_in(&sh_sci, SCFCR); 743f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCFCR, 0); 7529592ecbSNobuhiro Iwamatsu 7629592ecbSNobuhiro Iwamatsu serial_setbrg(); 7729592ecbSNobuhiro Iwamatsu return 0; 7829592ecbSNobuhiro Iwamatsu } 7929592ecbSNobuhiro Iwamatsu 803f6c8e36SNobuhiro Iwamatsu #if defined(CONFIG_CPU_SH7760) || \ 813f6c8e36SNobuhiro Iwamatsu defined(CONFIG_CPU_SH7780) || \ 823f6c8e36SNobuhiro Iwamatsu defined(CONFIG_CPU_SH7785) || \ 833f6c8e36SNobuhiro Iwamatsu defined(CONFIG_CPU_SH7786) 843f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port) 853f6c8e36SNobuhiro Iwamatsu { 863f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCRFDR) & 0xff; 873f6c8e36SNobuhiro Iwamatsu } 883f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_CPU_SH7763) 893f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port) 903f6c8e36SNobuhiro Iwamatsu { 913f6c8e36SNobuhiro Iwamatsu if ((port->mapbase == 0xffe00000) || 923f6c8e36SNobuhiro Iwamatsu (port->mapbase == 0xffe08000)) { 933f6c8e36SNobuhiro Iwamatsu /* SCIF0/1*/ 943f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCRFDR) & 0xff; 953f6c8e36SNobuhiro Iwamatsu } else { 963f6c8e36SNobuhiro Iwamatsu /* SCIF2 */ 973f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; 983f6c8e36SNobuhiro Iwamatsu } 993f6c8e36SNobuhiro Iwamatsu } 1003f6c8e36SNobuhiro Iwamatsu #elif defined(CONFIG_ARCH_SH7372) 1013f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port) 1023f6c8e36SNobuhiro Iwamatsu { 1033f6c8e36SNobuhiro Iwamatsu if (port->type == PORT_SCIFA) 1043f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCFDR) & SCIF_RFDC_MASK; 1053f6c8e36SNobuhiro Iwamatsu else 1063f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCRFDR); 1073f6c8e36SNobuhiro Iwamatsu } 1083f6c8e36SNobuhiro Iwamatsu #else 1093f6c8e36SNobuhiro Iwamatsu static int scif_rxfill(struct uart_port *port) 1103f6c8e36SNobuhiro Iwamatsu { 1113f6c8e36SNobuhiro Iwamatsu return sci_in(port, SCFDR) & SCIF_RFDC_MASK; 1123f6c8e36SNobuhiro Iwamatsu } 1133f6c8e36SNobuhiro Iwamatsu #endif 1143f6c8e36SNobuhiro Iwamatsu 11529592ecbSNobuhiro Iwamatsu static int serial_rx_fifo_level(void) 11629592ecbSNobuhiro Iwamatsu { 1173f6c8e36SNobuhiro Iwamatsu return scif_rxfill(&sh_sci); 11829592ecbSNobuhiro Iwamatsu } 11929592ecbSNobuhiro Iwamatsu 12029592ecbSNobuhiro Iwamatsu void serial_raw_putc(const char c) 12129592ecbSNobuhiro Iwamatsu { 12229592ecbSNobuhiro Iwamatsu while (1) { 1233f6c8e36SNobuhiro Iwamatsu /* Tx fifo is empty */ 1243f6c8e36SNobuhiro Iwamatsu if (sci_in(&sh_sci, SCxSR) & SCxSR_TEND(&sh_sci)) 12529592ecbSNobuhiro Iwamatsu break; 12629592ecbSNobuhiro Iwamatsu } 12729592ecbSNobuhiro Iwamatsu 1283f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCxTDR, c); 1293f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCxSR, sci_in(&sh_sci, SCxSR) & ~SCxSR_TEND(&sh_sci)); 13029592ecbSNobuhiro Iwamatsu } 13129592ecbSNobuhiro Iwamatsu 1328bdd7efaSMarek Vasut static void sh_serial_putc(const char c) 13329592ecbSNobuhiro Iwamatsu { 13429592ecbSNobuhiro Iwamatsu if (c == '\n') 13529592ecbSNobuhiro Iwamatsu serial_raw_putc('\r'); 13629592ecbSNobuhiro Iwamatsu serial_raw_putc(c); 13729592ecbSNobuhiro Iwamatsu } 13829592ecbSNobuhiro Iwamatsu 1398bdd7efaSMarek Vasut static int sh_serial_tstc(void) 14029592ecbSNobuhiro Iwamatsu { 14129592ecbSNobuhiro Iwamatsu return serial_rx_fifo_level() ? 1 : 0; 14229592ecbSNobuhiro Iwamatsu } 14329592ecbSNobuhiro Iwamatsu 14408c5fabeSNobuhiro Iwamatsu void handle_error(void) 14508c5fabeSNobuhiro Iwamatsu { 1463f6c8e36SNobuhiro Iwamatsu sci_in(&sh_sci, SCxSR); 1473f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCxSR, SCxSR_ERROR_CLEAR(&sh_sci)); 1483f6c8e36SNobuhiro Iwamatsu sci_in(&sh_sci, SCLSR); 1493f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCLSR, 0x00); 15029592ecbSNobuhiro Iwamatsu } 15129592ecbSNobuhiro Iwamatsu 15208c5fabeSNobuhiro Iwamatsu int serial_getc_check(void) 15308c5fabeSNobuhiro Iwamatsu { 15429592ecbSNobuhiro Iwamatsu unsigned short status; 15529592ecbSNobuhiro Iwamatsu 1563f6c8e36SNobuhiro Iwamatsu status = sci_in(&sh_sci, SCxSR); 15729592ecbSNobuhiro Iwamatsu 1583f6c8e36SNobuhiro Iwamatsu if (status & SCIF_ERRORS) 15929592ecbSNobuhiro Iwamatsu handle_error(); 1603f6c8e36SNobuhiro Iwamatsu if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) 16129592ecbSNobuhiro Iwamatsu handle_error(); 1623f6c8e36SNobuhiro Iwamatsu return status & (SCIF_DR | SCxSR_RDxF(&sh_sci)); 16329592ecbSNobuhiro Iwamatsu } 16429592ecbSNobuhiro Iwamatsu 1658bdd7efaSMarek Vasut static int sh_serial_getc(void) 16629592ecbSNobuhiro Iwamatsu { 16729592ecbSNobuhiro Iwamatsu unsigned short status; 16829592ecbSNobuhiro Iwamatsu char ch; 169ab09f433SNobuhiro Iwamatsu 170ab09f433SNobuhiro Iwamatsu while (!serial_getc_check()) 171ab09f433SNobuhiro Iwamatsu ; 17229592ecbSNobuhiro Iwamatsu 1733f6c8e36SNobuhiro Iwamatsu ch = sci_in(&sh_sci, SCxRDR); 1743f6c8e36SNobuhiro Iwamatsu status = sci_in(&sh_sci, SCxSR); 17529592ecbSNobuhiro Iwamatsu 1763f6c8e36SNobuhiro Iwamatsu sci_out(&sh_sci, SCxSR, SCxSR_RDxF_CLEAR(&sh_sci)); 17729592ecbSNobuhiro Iwamatsu 1783f6c8e36SNobuhiro Iwamatsu if (status & SCIF_ERRORS) 17929592ecbSNobuhiro Iwamatsu handle_error(); 18029592ecbSNobuhiro Iwamatsu 1813f6c8e36SNobuhiro Iwamatsu if (sci_in(&sh_sci, SCLSR) & SCxSR_ORER(&sh_sci)) 18229592ecbSNobuhiro Iwamatsu handle_error(); 18329592ecbSNobuhiro Iwamatsu return ch; 18429592ecbSNobuhiro Iwamatsu } 1858bdd7efaSMarek Vasut 1868bdd7efaSMarek Vasut static struct serial_device sh_serial_drv = { 1878bdd7efaSMarek Vasut .name = "sh_serial", 1888bdd7efaSMarek Vasut .start = sh_serial_init, 1898bdd7efaSMarek Vasut .stop = NULL, 1908bdd7efaSMarek Vasut .setbrg = sh_serial_setbrg, 1918bdd7efaSMarek Vasut .putc = sh_serial_putc, 192*ec3fd689SMarek Vasut .puts = default_serial_puts, 1938bdd7efaSMarek Vasut .getc = sh_serial_getc, 1948bdd7efaSMarek Vasut .tstc = sh_serial_tstc, 1958bdd7efaSMarek Vasut }; 1968bdd7efaSMarek Vasut 1978bdd7efaSMarek Vasut void sh_serial_initialize(void) 1988bdd7efaSMarek Vasut { 1998bdd7efaSMarek Vasut serial_register(&sh_serial_drv); 2008bdd7efaSMarek Vasut } 2018bdd7efaSMarek Vasut 2028bdd7efaSMarek Vasut __weak struct serial_device *default_serial_console(void) 2038bdd7efaSMarek Vasut { 2048bdd7efaSMarek Vasut return &sh_serial_drv; 2058bdd7efaSMarek Vasut } 206