<p>Jonathan Neuschäfer has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/25768">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">drivers/uart: Add a driver for SiFive's UART<br><br>This UART is used in the SiFive FU540 SoC.<br><br>Change-Id: I915edf39666b7a5f9550e3b7e743e97fe3cacfd3<br>Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net><br>---<br>M src/drivers/uart/Kconfig<br>M src/drivers/uart/Makefile.inc<br>A src/drivers/uart/sifive.c<br>3 files changed, 125 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/68/25768/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/drivers/uart/Kconfig b/src/drivers/uart/Kconfig</span><br><span>index 54f591d..bfc5cce 100644</span><br><span>--- a/src/drivers/uart/Kconfig</span><br><span>+++ b/src/drivers/uart/Kconfig</span><br><span>@@ -61,6 +61,11 @@</span><br><span>  default n</span><br><span>    select HAVE_UART_SPECIAL</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+config DRIVERS_UART_SIFIVE</span><br><span style="color: hsl(120, 100%, 40%);">+      bool</span><br><span style="color: hsl(120, 100%, 40%);">+  select HAVE_UART_SPECIAL</span><br><span style="color: hsl(120, 100%, 40%);">+      select UART_OVERRIDE_INPUT_CLOCK_DIVIDER</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> config UART_USE_REFCLK_AS_INPUT_CLOCK</span><br><span>  bool</span><br><span>         default n</span><br><span>diff --git a/src/drivers/uart/Makefile.inc b/src/drivers/uart/Makefile.inc</span><br><span>index ebaa5d4..c7aa1ae 100644</span><br><span>--- a/src/drivers/uart/Makefile.inc</span><br><span>+++ b/src/drivers/uart/Makefile.inc</span><br><span>@@ -42,4 +42,11 @@</span><br><span> verstage-y += pl011.c</span><br><span> endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ifeq ($(CONFIG_DRIVERS_UART_SIFIVE),y)</span><br><span style="color: hsl(120, 100%, 40%);">+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += sifive.c</span><br><span style="color: hsl(120, 100%, 40%);">+romstage-y += sifive.c</span><br><span style="color: hsl(120, 100%, 40%);">+postcar-y += sifive.c</span><br><span style="color: hsl(120, 100%, 40%);">+ramstage-y += sifive.c</span><br><span style="color: hsl(120, 100%, 40%);">+endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> endif</span><br><span>diff --git a/src/drivers/uart/sifive.c b/src/drivers/uart/sifive.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8e54d16</span><br><span>--- /dev/null</span><br><span>+++ b/src/drivers/uart/sifive.c</span><br><span>@@ -0,0 +1,113 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This file is part of the coreboot project.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2018 Jonathan Neuschäfer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; version 2 of the License.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <arch/io.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <boot/coreboot_tables.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <console/uart.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <types.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is a driver for SiFive's own UART, documented in the FU540 manual:</span><br><span style="color: hsl(120, 100%, 40%);">+ * https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct sifive_uart_registers {</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t txdata;        /* Transmit data register */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t rxdata;        /* Receive data register */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t txctrl;        /* Transmit control register */</span><br><span style="color: hsl(120, 100%, 40%);">+       uint32_t rxctrl;        /* Receive control register */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t ie;            /* UART interrupt enable */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint32_t ip;            /* UART interrupt pending */</span><br><span style="color: hsl(120, 100%, 40%);">+  uint32_t div;           /* Baud rate divisor */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXDATA_FULL              BIT(31)</span><br><span style="color: hsl(120, 100%, 40%);">+#define RXDATA_EMPTY           BIT(31)</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXCTRL_TXEN            BIT(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXCTRL_NSTOP_SHIFT      1</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXCTRL_NSTOP(x)              (((x)-1) << TXCTRL_NSTOP_SHIFT)</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXCTRL_TXCNT_SHIFT       16</span><br><span style="color: hsl(120, 100%, 40%);">+#define TXCTRL_TXCNT(x)             ((x) << TXCTRL_TXCNT_SHIFT)</span><br><span style="color: hsl(120, 100%, 40%);">+#define RXCTRL_RXEN          BIT(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#define RXCTRL_RXCNT_SHIFT      16</span><br><span style="color: hsl(120, 100%, 40%);">+#define RXCTRL_RXCNT(x)             ((x) << RXCTRL_RXCNT_SHIFT)</span><br><span style="color: hsl(120, 100%, 40%);">+#define IP_TXWM                      BIT(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#define IP_RXWM                 BIT(1)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void uart_init(int idx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sifive_uart_registers *regs = uart_platform_baseptr(idx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: Configure the divisor */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Enable transmission, one stop bit, transmit watermark at 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+      write32(&regs->txctrl, TXCTRL_TXEN|TXCTRL_NSTOP(1)|TXCTRL_TXCNT(1));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Enable reception, receive watermark at 0 */</span><br><span style="color: hsl(120, 100%, 40%);">+        write32(&regs->rxctrl, RXCTRL_RXEN|RXCTRL_RXCNT(0));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static bool uart_can_tx(struct sifive_uart_registers *regs)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return !(read32(&regs->txdata) & TXDATA_FULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void uart_tx_byte(int idx, unsigned char data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sifive_uart_registers *regs = uart_platform_baseptr(idx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    while (!uart_can_tx(regs))</span><br><span style="color: hsl(120, 100%, 40%);">+            ; /* TODO: implement a timeout */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   write32(&regs->txdata, data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void uart_tx_flush(int idx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct sifive_uart_registers *regs = uart_platform_baseptr(idx);</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t ip;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Use the TX watermark bit to find out if the TX FIFO is empty */</span><br><span style="color: hsl(120, 100%, 40%);">+    do {</span><br><span style="color: hsl(120, 100%, 40%);">+          ip = read32(&regs->ip);</span><br><span style="color: hsl(120, 100%, 40%);">+        } while(!(ip & IP_TXWM));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned char uart_rx_byte(int idx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct sifive_uart_registers *regs = uart_platform_baseptr(idx);</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t rxdata = read32(&regs->rxdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rxdata & RXDATA_EMPTY)</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          return rxdata & 0xff;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int uart_input_clock_divider(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * The SiFive UART handles oversampling internally. The divided clock</span><br><span style="color: hsl(120, 100%, 40%);">+  * is the baud clock.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef __PRE_RAM__</span><br><span style="color: hsl(120, 100%, 40%);">+void uart_fill_lb(void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span></span><br></pre><p>To view, visit <a href="https://review.coreboot.org/25768">change 25768</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/25768"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I915edf39666b7a5f9550e3b7e743e97fe3cacfd3 </div>
<div style="display:none"> Gerrit-Change-Number: 25768 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Jonathan Neuschäfer <j.neuschaefer@gmx.net> </div>