From nobody Wed Oct 8 13:27:05 2025 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E4A392512D7; Sat, 28 Jun 2025 11:57:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751111847; cv=none; b=S+kt9y8pVc1Ke3F+uQDNrqjw7pXgLxM9TnuLTKlQ4uZXcP5AYnIF8DalGVJL46s+2dP3TYqNol7HOop6bzL2YiygKS+z+Q/Ko+w1HSzSjhjLd0NjyShettgWILvwlt5E0KxDGt51/ePzlpdIYdpYTO+UJ6JyboxZq6PAWXjHdv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751111847; c=relaxed/simple; bh=5+oN6k0QIsiPQQSamlGR1JN2kYiXirxdPBC77ez6ftE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=r6gT51q6AxqUD/uEvKfWJvL+t60BUHTNh4rBS8T39mXPftNIR3b4Eynxuyoyss8UrVTMM4ulhq3YV8j5VpvzSfX8BropM2LApp2QRRg+JkumTfouePbgKpfw4l2Y1wQEqshDOFDvRDv9p42aAfitKJ/MGy6lTWXxfc8E3v8dpP4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=KeNnxxsH; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="KeNnxxsH" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-3a6e8b1fa37so606228f8f.2; Sat, 28 Jun 2025 04:57:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1751111843; x=1751716643; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rcAnSzNjmk4w2RyV4jIIs/EVLnef9xQevQsqDg9T7fY=; b=KeNnxxsHD24DsDSRsxZKdKWMVHsG24querb017407qEFvk09CgXKjXVC5jhhUXjuoB EXfSuI4nIt6eB7mKCCerMnN03kvEDMOj36/Zt3GxyrOhMIyYurViiHndkLYtWkkSBcsm L2DtHAiVuJv/+Sq/VW/mVWuI+VJet78fHKEjze+BvLITVG2/OsUsigTw4BnMdxY9o+0c 8TK7DVDr53V6+ksvQxK32Yneo5UyDIUFATm1pTOPdlszaXwQand0ZszGAs3cphmyWsh0 1l1PrwMLcBmpnlSUPtwfa5inlFoV7XvPdU7TP+MTQAIatjauk4Iv8UUPXXBnpzHZF9XT CBKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1751111843; x=1751716643; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rcAnSzNjmk4w2RyV4jIIs/EVLnef9xQevQsqDg9T7fY=; b=KhAWJu+38M+uIoKldjiWWAocbhdf19+cfRNF0YSppf0K7z1SsyeehjNblr6vHERwAc kRsRqCSpL+4lf7u8VHmgzMk/IjoT3NBg6IdOzUr84wV+885g+ai/qdj1B+sRAgpsdE8/ zyF+4lm/SWRPZnUToCYzB15EzptVyziqyBidJv3Z1k2Z12Jiy7HaXdNIU6o5qvRW9+w8 w4fbkYC5D3v8S5qxuCcY84zI1AHzrlXJKaIt6OpKl3zl4XUbyYivaww9j4f55IoqH1KI /lHaGqwZ3DM3qhfn6tRrMPPs77+cV1wFk5Jk6FBOZTGPNK2aD26wtzHP6yPlCkiQXkLE mqrQ== X-Forwarded-Encrypted: i=1; AJvYcCUNLsFgOZNf1uMUeGGFVb8QgDDVAUB143jNtuwPDNJcC+klCUsxCR3fekOCNwBz8qvaqaPxrSOhO2DqsQcTdBpGTKc=@vger.kernel.org, AJvYcCVzv3T4lhvr5pljyx30dikbESNPDlwqYuwmOOL9Fa3RgjfY8pQLlGAnMEZcUOMfJaVn5y3f/Q9dJeLAPu5s@vger.kernel.org, AJvYcCXAPmA7i7YRYCg8ZGwM6dKu3waODYnkDDkObmxieM51v5s7ctQEQI3NFxegbiQyCwtHGU8rH/uhB/ru@vger.kernel.org X-Gm-Message-State: AOJu0YxwJ0F4grpRgaKCjwThxsaKs/QOIY5rlVBMEFWaESjz3Ga5OfCI tcxrjFWOipnusdSc+R1Ty8un18zbJ2iyYj0ReBFl3dBRQhXOVZHZzCyL X-Gm-Gg: ASbGnctuhwZxwD8SK24nqd5R2fGT9NBizC6kO1E41Qq1eZVrZBKOBvI1dQwHUs7rD9o 93S51IlBuP7GRmcy5emcsRnmqApJg7rQQxVGD60as2mmxyLlJycbpYkcz2yRjwYWp9xgCYDXRyC i+115hqDe+TDpcb4xFPxu2uWjf/Skw1AprYINcYOHrBBZSEdAosXMwB1zlMwSTlCVBoeyc8CNiS HSWaIrHJQuHj+Z8VIYiRt0GN4bZ/V6MtMVPyMRq1Mg124ARueyQbwfEMFyIl5HWtv5kHXvHH1NW wGZ1s6jTagF7Mdy+TBDfV8LCWudkBCQVdbr2G9jTGdIBK79+tzgbAH3wly/SRAaInw+K/KuwnOA PxyaGBSVlp63Ry+nckbDwrMFCoxSCTWU= X-Google-Smtp-Source: AGHT+IHfIPzHGp4eRJrtjbO7iUse9tJSXUAliGqw/P8quLHaMIBpEV+oUPIXYSGXxKjU8T26Tda5ng== X-Received: by 2002:a05:6000:25e8:b0:3a4:d31e:4af3 with SMTP id ffacd0b85a97d-3a8fee64e2fmr4541459f8f.37.1751111843017; Sat, 28 Jun 2025 04:57:23 -0700 (PDT) Received: from iku.example.org ([2a06:5906:61b:2d00:dca0:b0f1:f055:ea37]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a88c7e7310sm5247818f8f.18.2025.06.28.04.57.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 28 Jun 2025 04:57:22 -0700 (PDT) From: Prabhakar X-Google-Original-From: Prabhakar To: Greg Kroah-Hartman , Jiri Slaby , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Geert Uytterhoeven , Magnus Damm , Wolfram Sang , linux-serial@vger.kernel.org, devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Prabhakar , Biju Das , Fabrizio Castro , Lad Prabhakar Subject: [PATCH v13 5/5] serial: sh-sci: Add support for RZ/T2H SCI Date: Sat, 28 Jun 2025 12:57:15 +0100 Message-ID: <20250628115715.102338-6-prabhakar.mahadev-lad.rj@bp.renesas.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250628115715.102338-1-prabhakar.mahadev-lad.rj@bp.renesas.com> References: <20250628115715.102338-1-prabhakar.mahadev-lad.rj@bp.renesas.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Thierry Bultel Define a new RSCI port type, and the RSCI 32 bits registers set. The RZ/T2H SCI has a a fifo, and a quite different set of registers from the original SH SCI ones. DMA is not supported yet. Signed-off-by: Thierry Bultel Signed-off-by: Lad Prabhakar Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven --- v12-> v13: - No changes --- drivers/tty/serial/Kconfig | 7 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/rsci.c | 477 +++++++++++++++++++++++++++++ drivers/tty/serial/rsci.h | 10 + drivers/tty/serial/sh-sci-common.h | 5 + drivers/tty/serial/sh-sci.c | 53 +++- 6 files changed, 543 insertions(+), 10 deletions(-) create mode 100644 drivers/tty/serial/rsci.c create mode 100644 drivers/tty/serial/rsci.h diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 79a8186d3361..44427415a80d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -675,6 +675,13 @@ config SERIAL_SH_SCI_DMA depends on SERIAL_SH_SCI && DMA_ENGINE default ARCH_RENESAS =20 +config SERIAL_RSCI + tristate "Support for Renesas RZ/T2H SCI variant" + depends on SERIAL_SH_SCI + help + Support for the RZ/T2H SCI variant with fifo. + Say Y if you want to be able to use the RZ/T2H SCI serial port. + config SERIAL_HS_LPC32XX tristate "LPC32XX high speed serial port support" depends on ARCH_LPC32XX || COMPILE_TEST diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index d58d9f719889..a2ccbc508ec5 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_SERIAL_QCOM_GENI) +=3D qcom_geni_serial.o obj-$(CONFIG_SERIAL_QE) +=3D ucc_uart.o obj-$(CONFIG_SERIAL_RDA) +=3D rda-uart.o obj-$(CONFIG_SERIAL_RP2) +=3D rp2.o +obj-$(CONFIG_SERIAL_RSCI) +=3D rsci.o obj-$(CONFIG_SERIAL_SA1100) +=3D sa1100.o obj-$(CONFIG_SERIAL_SAMSUNG) +=3D samsung_tty.o obj-$(CONFIG_SERIAL_SB1250_DUART) +=3D sb1250-duart.o diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c new file mode 100644 index 000000000000..8274dbbd7cc2 --- /dev/null +++ b/drivers/tty/serial/rsci.c @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Renesas Electronics Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "rsci.h" + +/* RSCI registers */ +#define RDR 0x00 +#define TDR 0x04 +#define CCR0 0x08 +#define CCR1 0x0C +#define CCR2 0x10 +#define CCR3 0x14 +#define CCR4 0x18 +#define FCR 0x24 +#define DCR 0x30 +#define CSR 0x48 +#define FRSR 0x50 +#define FTSR 0x54 +#define CFCLR 0x68 +#define FFCLR 0x70 + +/* RDR (Receive Data Register) */ +#define RDR_FFER BIT(12) /* FIFO Framing Error */ +#define RDR_FPER BIT(11) /* FIFO Parity Error */ +#define RDR_RDAT_MSK GENMASK(8, 0) + +/* TDR (Transmit Data Register) */ +#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */ +#define TDR_TDAT_9BIT_LSHIFT 0 +#define TDR_TDAT_9BIT_VAL 0x1FF +#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT) + +/* CCR0 (Common Control Register 0) */ +#define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */ +#define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */ +#define CCR0_TIE BIT(20) /* Transmit Interrupt Enable */ +#define CCR0_RIE BIT(16) /* Receive Interrupt Enable */ +#define CCR0_IDSEL BIT(10) /* ID Frame Select */ +#define CCR0_DCME BIT(9) /* Data Compare Match Enable */ +#define CCR0_MPIE BIT(8) /* Multiprocessor Interrupt Enable */ +#define CCR0_TE BIT(4) /* Transmit Enable */ +#define CCR0_RE BIT(0) /* Receive Enable */ + +/* CCR1 (Common Control Register 1) */ +#define CCR1_NFEN BIT(28) /* Digital Noise Filter Function */ +#define CCR1_SHARPS BIT(20) /* Half -duplex Communication Select */ +#define CCR1_SPLP BIT(16) /* Loopback Control */ +#define CCR1_RINV BIT(13) /* RxD invert */ +#define CCR1_TINV BIT(12) /* TxD invert */ +#define CCR1_PM BIT(9) /* Parity Mode */ +#define CCR1_PE BIT(8) /* Parity Enable */ +#define CCR1_SPB2IO BIT(5) /* Serial Port Break I/O */ +#define CCR1_SPB2DT BIT(4) /* Serial Port Break Data Select */ +#define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */ +#define CCR1_CTSE BIT(0) /* CTS Enable */ + +/* FCR (FIFO Control Register) */ +#define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */ +#define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */ +#define FCR_DRES BIT(0) /* Incoming Data Ready Error Select */ +#define FCR_RTRG4_0 GENMASK(20, 16) +#define FCR_TTRG GENMASK(12, 8) + +/* CSR (Common Status Register) */ +#define CSR_RDRF BIT(31) /* Receive Data Full */ +#define CSR_TEND BIT(30) /* Transmit End Flag */ +#define CSR_TDRE BIT(29) /* Transmit Data Empty */ +#define CSR_FER BIT(28) /* Framing Error */ +#define CSR_PER BIT(27) /* Parity Error */ +#define CSR_MFF BIT(26) /* Mode Fault Error */ +#define CSR_ORER BIT(24) /* Overrun Error */ +#define CSR_DFER BIT(18) /* Data Compare Match Framing Error */ +#define CSR_DPER BIT(17) /* Data Compare Match Parity Error */ +#define CSR_DCMF BIT(16) /* Data Compare Match */ +#define CSR_RXDMON BIT(15) /* Serial Input Data Monitor */ +#define CSR_ERS BIT(4) /* Error Signal Status */ + +#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask) +#define SCxSR_ERROR_CLEAR(port) (to_sci_port(port)->params->error_clear) + +#define RSCI_DEFAULT_ERROR_MASK (CSR_PER | CSR_FER) + +#define RSCI_RDxF_CLEAR (CFCLR_RDRFC) +#define RSCI_ERROR_CLEAR (CFCLR_PERC | CFCLR_FERC) +#define RSCI_TDxE_CLEAR (CFCLR_TDREC) +#define RSCI_BREAK_CLEAR (CFCLR_PERC | CFCLR_FERC | CFCLR_ORERC) + +/* FRSR (FIFO Receive Status Register) */ +#define FRSR_R5_0 GENMASK(13, 8) /* Receive FIFO Data Count */ +#define FRSR_DR BIT(0) /* Receive Data Ready */ + +/* CFCLR (Common Flag CLear Register) */ +#define CFCLR_RDRFC BIT(31) /* RDRF Clear */ +#define CFCLR_TDREC BIT(29) /* TDRE Clear */ +#define CFCLR_FERC BIT(28) /* FER Clear */ +#define CFCLR_PERC BIT(27) /* PER Clear */ +#define CFCLR_MFFC BIT(26) /* MFF Clear */ +#define CFCLR_ORERC BIT(24) /* ORER Clear */ +#define CFCLR_DFERC BIT(18) /* DFER Clear */ +#define CFCLR_DPERC BIT(17) /* DPER Clear */ +#define CFCLR_DCMFC BIT(16) /* DCMF Clear */ +#define CFCLR_ERSC BIT(4) /* ERS Clear */ +#define CFCLR_CLRFLAG (CFCLR_RDRFC | CFCLR_FERC | CFCLR_PERC | \ + CFCLR_MFFC | CFCLR_ORERC | CFCLR_DFERC | \ + CFCLR_DPERC | CFCLR_DCMFC | CFCLR_ERSC) + +/* FFCLR (FIFO Flag CLear Register) */ +#define FFCLR_DRC BIT(0) /* DR Clear */ + +#define DCR_DEPOL BIT(0) + +static u32 rsci_serial_in(struct uart_port *p, int offset) +{ + return readl(p->membase + offset); +} + +static void rsci_serial_out(struct uart_port *p, int offset, int value) +{ + writel(value, p->membase + offset); +} + +static void rsci_clear_DRxC(struct uart_port *port) +{ + rsci_serial_out(port, CFCLR, CFCLR_RDRFC); + rsci_serial_out(port, FFCLR, FFCLR_DRC); +} + +static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask) +{ + rsci_serial_out(port, CFCLR, mask); +} + +static void rsci_start_rx(struct uart_port *port) +{ + unsigned int ctrl; + + ctrl =3D rsci_serial_in(port, CCR0); + ctrl |=3D CCR0_RIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_set_termios(struct uart_port *port, struct ktermios *term= ios, + const struct ktermios *old) +{ + struct sci_port *s =3D to_sci_port(port); + unsigned long flags; + + sci_port_enable(s); + uart_port_lock_irqsave(port, &flags); + + /* For now, only RX enabling is supported */ + if (termios->c_cflag & CREAD) + rsci_start_rx(port); + + uart_port_unlock_irqrestore(port, flags); + sci_port_disable(s); +} + +static int rsci_txfill(struct uart_port *port) +{ + return rsci_serial_in(port, FTSR); +} + +static int rsci_rxfill(struct uart_port *port) +{ + u32 val =3D rsci_serial_in(port, FRSR); + + return FIELD_GET(FRSR_R5_0, val); +} + +static unsigned int rsci_tx_empty(struct uart_port *port) +{ + unsigned int status =3D rsci_serial_in(port, CSR); + unsigned int in_tx_fifo =3D rsci_txfill(port); + + return (status & CSR_TEND) && !in_tx_fifo ? TIOCSER_TEMT : 0; +} + +static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* Not supported yet */ +} + +static unsigned int rsci_get_mctrl(struct uart_port *port) +{ + /* Not supported yet */ + return 0; +} + +static void rsci_clear_CFC(struct uart_port *port, unsigned int mask) +{ + rsci_serial_out(port, CFCLR, mask); +} + +static void rsci_start_tx(struct uart_port *port) +{ + struct sci_port *sp =3D to_sci_port(port); + u32 ctrl; + + if (sp->chan_tx) + return; + + /* + * TE (Transmit Enable) must be set after setting TIE + * (Transmit Interrupt Enable) or in the same instruction + * to start the transmit process. + */ + ctrl =3D rsci_serial_in(port, CCR0); + ctrl |=3D CCR0_TIE | CCR0_TE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_stop_tx(struct uart_port *port) +{ + u32 ctrl; + + ctrl =3D rsci_serial_in(port, CCR0); + ctrl &=3D ~CCR0_TIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static void rsci_stop_rx(struct uart_port *port) +{ + u32 ctrl; + + ctrl =3D rsci_serial_in(port, CCR0); + ctrl &=3D ~CCR0_RIE; + rsci_serial_out(port, CCR0, ctrl); +} + +static int rsci_txroom(struct uart_port *port) +{ + return port->fifosize - rsci_txfill(port); +} + +static void rsci_transmit_chars(struct uart_port *port) +{ + unsigned int stopped =3D uart_tx_stopped(port); + struct tty_port *tport =3D &port->state->port; + u32 status, ctrl; + int count; + + status =3D rsci_serial_in(port, CSR); + if (!(status & CSR_TDRE)) { + ctrl =3D rsci_serial_in(port, CCR0); + if (kfifo_is_empty(&tport->xmit_fifo)) + ctrl &=3D ~CCR0_TIE; + else + ctrl |=3D CCR0_TIE; + rsci_serial_out(port, CCR0, ctrl); + return; + } + + count =3D rsci_txroom(port); + + do { + unsigned char c; + + if (port->x_char) { + c =3D port->x_char; + port->x_char =3D 0; + } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) { + break; + } + + rsci_clear_CFC(port, CFCLR_TDREC); + rsci_serial_out(port, TDR, c); + + port->icount.tx++; + } while (--count > 0); + + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (kfifo_is_empty(&tport->xmit_fifo)) { + ctrl =3D rsci_serial_in(port, CCR0); + ctrl &=3D ~CCR0_TIE; + ctrl |=3D CCR0_TEIE; + rsci_serial_out(port, CCR0, ctrl); + } +} + +static void rsci_receive_chars(struct uart_port *port) +{ + struct tty_port *tport =3D &port->state->port; + u32 rdat, status, frsr_status =3D 0; + int i, count, copied =3D 0; + unsigned char flag; + + status =3D rsci_serial_in(port, CSR); + frsr_status =3D rsci_serial_in(port, FRSR); + + if (!(status & CSR_RDRF) && !(frsr_status & FRSR_DR)) + return; + + while (1) { + /* Don't copy more bytes than there is room for in the buffer */ + count =3D tty_buffer_request_room(tport, rsci_rxfill(port)); + + /* If for any reason we can't copy more data, we're done! */ + if (count =3D=3D 0) + break; + + for (i =3D 0; i < count; i++) { + char c; + + rdat =3D rsci_serial_in(port, RDR); + /* 9-bits data is not supported yet */ + c =3D rdat & RDR_RDAT_MSK; + + if (uart_handle_sysrq_char(port, c)) { + count--; + i--; + continue; + } + + /* Store data and status. + * Non FIFO mode is not supported + */ + if (rdat & RDR_FFER) { + flag =3D TTY_FRAME; + port->icount.frame++; + } else if (rdat & RDR_FPER) { + flag =3D TTY_PARITY; + port->icount.parity++; + } else { + flag =3D TTY_NORMAL; + } + + tty_insert_flip_char(tport, c, flag); + } + + rsci_serial_in(port, CSR); /* dummy read */ + rsci_clear_DRxC(port); + + copied +=3D count; + port->icount.rx +=3D count; + } + + if (copied) { + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tport); + } else { + /* TTY buffers full; read from RX reg to prevent lockup */ + rsci_serial_in(port, RDR); + rsci_serial_in(port, CSR); /* dummy read */ + rsci_clear_DRxC(port); + } +} + +static void rsci_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 status; + int ret; + + ret =3D readl_relaxed_poll_timeout_atomic(port->membase + CSR, status, + (status & CSR_TDRE), 100, + USEC_PER_SEC); + if (ret !=3D 0) { + dev_err(port->dev, + "Error while sending data in UART TX : %d\n", ret); + goto done; + } + rsci_serial_out(port, TDR, c); +done: + rsci_clear_SCxSR(port, CFCLR_TDREC); +} + +static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl) +{ + struct sci_port *s =3D to_sci_port(port); + u32 ctrl_temp =3D + s->params->param_bits->rxtx_enable | CCR0_TIE | + s->hscif_tot; + rsci_serial_out(port, CCR0, ctrl_temp); +} + +static const char *rsci_type(struct uart_port *port) +{ + return "rsci"; +} + +static size_t rsci_suspend_regs_size(void) +{ + return 0; +} + +static void rsci_shutdown_complete(struct uart_port *port) +{ + /* + * Stop RX and TX, disable related interrupts, keep clock source + */ + rsci_serial_out(port, CCR0, 0); +} + +static const struct sci_common_regs rsci_common_regs =3D { + .status =3D CSR, + .control =3D CCR0, +}; + +static const struct sci_port_params_bits rsci_port_param_bits =3D { + .rxtx_enable =3D CCR0_RE | CCR0_TE, + .te_clear =3D CCR0_TE | CCR0_TEIE, + .poll_sent_bits =3D CSR_TDRE | CSR_TEND, +}; + +static const struct sci_port_params rsci_port_params =3D { + .fifosize =3D 16, + .overrun_reg =3D CSR, + .overrun_mask =3D CSR_ORER, + .sampling_rate_mask =3D SCI_SR(32), + .error_mask =3D RSCI_DEFAULT_ERROR_MASK, + .error_clear =3D RSCI_ERROR_CLEAR, + .param_bits =3D &rsci_port_param_bits, + .common_regs =3D &rsci_common_regs, +}; + +static const struct uart_ops rsci_uart_ops =3D { + .tx_empty =3D rsci_tx_empty, + .set_mctrl =3D rsci_set_mctrl, + .get_mctrl =3D rsci_get_mctrl, + .start_tx =3D rsci_start_tx, + .stop_tx =3D rsci_stop_tx, + .stop_rx =3D rsci_stop_rx, + .startup =3D sci_startup, + .shutdown =3D sci_shutdown, + .set_termios =3D rsci_set_termios, + .pm =3D sci_pm, + .type =3D rsci_type, + .release_port =3D sci_release_port, + .request_port =3D sci_request_port, + .config_port =3D sci_config_port, + .verify_port =3D sci_verify_port, +}; + +static const struct sci_port_ops rsci_port_ops =3D { + .read_reg =3D rsci_serial_in, + .write_reg =3D rsci_serial_out, + .clear_SCxSR =3D rsci_clear_SCxSR, + .transmit_chars =3D rsci_transmit_chars, + .receive_chars =3D rsci_receive_chars, + .poll_put_char =3D rsci_poll_put_char, + .prepare_console_write =3D rsci_prepare_console_write, + .suspend_regs_size =3D rsci_suspend_regs_size, + .shutdown_complete =3D rsci_shutdown_complete, +}; + +struct sci_of_data of_sci_rsci_data =3D { + .type =3D SCI_PORT_RSCI, + .ops =3D &rsci_port_ops, + .uart_ops =3D &rsci_uart_ops, + .params =3D &rsci_port_params, +}; + +#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON + +static int __init rsci_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return scix_early_console_setup(device, &of_sci_rsci_data); +} + +OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_set= up); + +#endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */ + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RSCI serial driver"); diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h new file mode 100644 index 000000000000..2af3f28b465a --- /dev/null +++ b/drivers/tty/serial/rsci.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __RSCI_H__ +#define __RSCI_H__ + +#include "sh-sci-common.h" + +extern struct sci_of_data of_sci_rsci_data; + +#endif /* __RSCI_H__ */ diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci= -common.h index fcddf66780c9..e3c028df14f1 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -5,6 +5,11 @@ =20 #include =20 +/* Private port IDs */ +enum SCI_PORT_TYPE { + SCI_PORT_RSCI =3D BIT(7) | 0, +}; + enum SCI_CLKS { SCI_FCK, /* Functional Clock */ SCI_SCK, /* Optional External Clock */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 26536ff2eda1..6867ccfa5ac6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -54,6 +54,7 @@ #include #endif =20 +#include "rsci.h" #include "serial_mctrl_gpio.h" #include "sh-sci.h" #include "sh-sci-common.h" @@ -550,6 +551,7 @@ void sci_port_enable(struct sci_port *sci_port) } sci_port->port.uartclk =3D sci_port->clk_rates[SCI_FCK]; } +EXPORT_SYMBOL(sci_port_enable); =20 void sci_port_disable(struct sci_port *sci_port) { @@ -563,6 +565,7 @@ void sci_port_disable(struct sci_port *sci_port) =20 pm_runtime_put_sync(sci_port->port.dev); } +EXPORT_SYMBOL(sci_port_disable); =20 static inline unsigned long port_rx_irq_mask(struct uart_port *port) { @@ -1828,7 +1831,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void= *ptr) unsigned long flags; u32 ctrl; =20 - if (s->type !=3D PORT_SCI) + if (s->type !=3D PORT_SCI && s->type !=3D SCI_PORT_RSCI) return sci_tx_interrupt(irq, ptr); =20 uart_port_lock_irqsave(port, &flags); @@ -2289,6 +2292,7 @@ int sci_startup(struct uart_port *port) =20 return 0; } +EXPORT_SYMBOL(sci_startup); =20 void sci_shutdown(struct uart_port *port) { @@ -2319,6 +2323,7 @@ void sci_shutdown(struct uart_port *port) sci_free_irq(s); sci_free_dma(port); } +EXPORT_SYMBOL(sci_shutdown); =20 static int sci_sck_calc(struct sci_port *s, unsigned int bps, unsigned int *srr) @@ -2750,6 +2755,7 @@ void sci_pm(struct uart_port *port, unsigned int stat= e, break; } } +EXPORT_SYMBOL(sci_pm); =20 static const char *sci_type(struct uart_port *port) { @@ -2812,6 +2818,7 @@ void sci_release_port(struct uart_port *port) =20 release_mem_region(port->mapbase, sport->reg_size); } +EXPORT_SYMBOL(sci_release_port); =20 int sci_request_port(struct uart_port *port) { @@ -2834,6 +2841,7 @@ int sci_request_port(struct uart_port *port) =20 return 0; } +EXPORT_SYMBOL(sci_request_port); =20 void sci_config_port(struct uart_port *port, int flags) { @@ -2843,6 +2851,7 @@ void sci_config_port(struct uart_port *port, int flag= s) sci_request_port(port); } } +EXPORT_SYMBOL(sci_config_port); =20 int sci_verify_port(struct uart_port *port, struct serial_struct *ser) { @@ -2852,6 +2861,7 @@ int sci_verify_port(struct uart_port *port, struct se= rial_struct *ser) =20 return 0; } +EXPORT_SYMBOL(sci_verify_port); =20 static void sci_prepare_console_write(struct uart_port *port, u32 ctrl) { @@ -2977,14 +2987,27 @@ static int sci_init_clocks(struct sci_port *sci_por= t, struct device *dev) struct clk *clk; unsigned int i; =20 - if (sci_port->type =3D=3D PORT_HSCIF) + if (sci_port->type =3D=3D PORT_HSCIF) { clk_names[SCI_SCK] =3D "hsck"; + } else if (sci_port->type =3D=3D SCI_PORT_RSCI) { + clk_names[SCI_FCK] =3D "operation"; + clk_names[SCI_BRG_INT] =3D "bus"; + } =20 for (i =3D 0; i < SCI_NUM_CLKS; i++) { - clk =3D devm_clk_get_optional(dev, clk_names[i]); + const char *name =3D clk_names[i]; + + clk =3D devm_clk_get_optional(dev, name); if (IS_ERR(clk)) return PTR_ERR(clk); =20 + if (!clk && sci_port->type =3D=3D SCI_PORT_RSCI && + (i =3D=3D SCI_FCK || i =3D=3D SCI_BRG_INT)) { + return dev_err_probe(dev, -ENODEV, + "failed to get %s\n", + name); + } + if (!clk && i =3D=3D SCI_FCK) { /* * Not all SH platforms declare a clock lookup entry @@ -2995,13 +3018,13 @@ static int sci_init_clocks(struct sci_port *sci_por= t, struct device *dev) if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to get %s\n", - clk_names[i]); + name); } =20 if (!clk) - dev_dbg(dev, "failed to get %s\n", clk_names[i]); + dev_dbg(dev, "failed to get %s\n", name); else - dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], + dev_dbg(dev, "clk %s is %pC rate %lu\n", name, clk, clk_get_rate(clk)); sci_port->clks[i] =3D clk; } @@ -3085,10 +3108,10 @@ static int sci_init_single(struct platform_device *= dev, } =20 /* - * The fourth interrupt on SCI port is transmit end interrupt, so + * The fourth interrupt on SCI and RSCI port is transmit end interrupt, so * shuffle the interrupts. */ - if (p->type =3D=3D PORT_SCI) + if (p->type =3D=3D PORT_SCI || p->type =3D=3D SCI_PORT_RSCI) swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]); =20 /* The SCI generates several interrupts. They can be muxed together or @@ -3122,6 +3145,9 @@ static int sci_init_single(struct platform_device *de= v, else sci_port->rx_trigger =3D 8; break; + case SCI_PORT_RSCI: + sci_port->rx_trigger =3D 15; + break; default: sci_port->rx_trigger =3D 1; break; @@ -3346,7 +3372,8 @@ static void sci_remove(struct platform_device *dev) =20 if (s->port.fifosize > 1) device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); - if (type =3D=3D PORT_SCIFA || type =3D=3D PORT_SCIFB || type =3D=3D PORT_= HSCIF) + if (type =3D=3D PORT_SCIFA || type =3D=3D PORT_SCIFB || type =3D=3D PORT_= HSCIF || + type =3D=3D SCI_PORT_RSCI) device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); } =20 @@ -3440,6 +3467,12 @@ static const struct of_device_id of_sci_match[] __ma= ybe_unused =3D { .compatible =3D "renesas,scif-r9a09g057", .data =3D &of_sci_scif_rzv2h, }, +#ifdef CONFIG_SERIAL_RSCI + { + .compatible =3D "renesas,r9a09g077-rsci", + .data =3D &of_sci_rsci_data, + }, +#endif /* CONFIG_SERIAL_RSCI */ /* Family-specific types */ { .compatible =3D "renesas,rcar-gen1-scif", @@ -3699,7 +3732,7 @@ static int sci_probe(struct platform_device *dev) return ret; } if (sp->type =3D=3D PORT_SCIFA || sp->type =3D=3D PORT_SCIFB || - sp->type =3D=3D PORT_HSCIF) { + sp->type =3D=3D PORT_HSCIF || sp->type =3D=3D SCI_PORT_RSCI) { ret =3D device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout); if (ret) { if (sp->port.fifosize > 1) { --=20 2.49.0