+ return 0;
+}
+
+static int serial_rx_fifo_level(struct uart_port *port)
+{
+ 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(port) ? 1 : 0;
+}
+
+static int serial_getc_check(struct uart_port *port)
+{
+ unsigned short status;
+
+ status = sci_in(port, SCxSR);
+
+ if (status & SCIF_ERRORS)
+ 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_generic(struct uart_port *port)
+{
+ unsigned short status;
+ char ch;
+
+ if (!serial_getc_check(port))
+ return -EAGAIN;
+
+ ch = sci_in(port, SCxRDR);
+ status = sci_in(port, SCxSR);
+
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+ if (status & SCIF_ERRORS)
+ handle_error(port);
+
+ if (sci_in(port, SCLSR) & SCxSR_ORER(port))
+ handle_error(port);
+
+ 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);
+
+ return serial_raw_putc(priv, ch);
+}
+
+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 */