summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2011-05-15 07:56:25 -0700
committerSimon Glass <sjg@chromium.org>2011-08-24 10:01:33 -0700
commit3a47c614c2f5f204ee9a6428df03df3e85fe0b51 (patch)
treeb320ae1cb0ec40fc99d737f9a86b3bfbfa042737 /drivers
parent16016e7f644ba2301848f7769af6192cafc45c20 (diff)
fdt: Add serial port controlled by device tree
This adds a new console serial port which is implemented by the driver selected in the device tree. BUG=chromium-os:11623 TEST=build and boot U-Boot on Seaboard Change-Id: I0e41f795a78d165c2907a9f8faeeabe1a2639a18 Reviewed-on: http://gerrit.chromium.org/gerrit/958 Reviewed-by: Simon Glass <sjg@chromium.org> Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_fdt.c179
2 files changed, 180 insertions, 0 deletions
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 7d221fc40d..6e96d7addc 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -56,6 +56,7 @@ COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o
COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
COBJS-$(CONFIG_USB_TTY) += usbtty.o
+COBJS-$(CONFIG_OF_CONTROL) += serial_fdt.o
COBJS := $(sort $(COBJS-y))
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/serial/serial_fdt.c b/drivers/serial/serial_fdt.c
new file mode 100644
index 0000000000..eadc9b3e7f
--- /dev/null
+++ b/drivers/serial/serial_fdt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * This is a serial port provided by the flattened device tree. It works
+ * by selecting a compiled in driver according to the setting in the FDT.
+ */
+
+#include <common.h>
+#include <fdt_decode.h>
+#include <ns16550.h>
+#include <serial.h>
+#include <serial_fdt.h>
+
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * We need these structures to be outside BSS since they are accessed before
+ * relocation.
+ */
+static struct serial_device console = {
+ "not_in_bss"
+};
+
+struct fdt_uart console_uart = {
+ -1U
+};
+
+/* Access the console - this may need to be a function */
+#define DECLARE_CONSOLE struct fdt_uart *uart = &console_uart
+
+/* Initialize the serial port */
+static int fserial_init(void)
+{
+ DECLARE_CONSOLE;
+
+ switch (uart->compat) {
+#ifdef CONFIG_SYS_NS16550
+ case COMPAT_SERIAL_NS16550:
+ NS16550_init((NS16550_t)uart->reg, uart->divisor);
+ break;
+#endif
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void fserial_putc(const char c)
+{
+ DECLARE_CONSOLE;
+
+ if (c == '\n')
+ fserial_putc('\r');
+ switch (uart->compat) {
+#ifdef CONFIG_SYS_NS16550
+ case COMPAT_SERIAL_NS16550 :
+ NS16550_putc((NS16550_t)uart->reg, c);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+static void fserial_puts(const char *s)
+{
+ while (*s)
+ fserial_putc(*s++);
+}
+
+static int fserial_getc(void)
+{
+ DECLARE_CONSOLE;
+
+ switch (uart->compat) {
+#ifdef CONFIG_SYS_NS16550
+ case COMPAT_SERIAL_NS16550 :
+ return NS16550_getc((NS16550_t)uart->reg, uart->id);
+#endif
+ default:
+ break;
+ }
+ /* hang */
+ for (;;) ;
+}
+
+static int fserial_tstc(void)
+{
+ DECLARE_CONSOLE;
+
+ switch (uart->compat) {
+#ifdef CONFIG_SYS_NS16550
+ case COMPAT_SERIAL_NS16550 :
+ return NS16550_tstc((NS16550_t)uart->reg, uart->id);
+#endif
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void fserial_setbrg(void)
+{
+ DECLARE_CONSOLE;
+
+ uart->baudrate = gd->baudrate;
+ fdt_decode_uart_calc_divisor(uart);
+ switch (uart->compat) {
+#ifdef CONFIG_SYS_NS16550
+ case COMPAT_SERIAL_NS16550 :
+ NS16550_reinit((NS16550_t)uart->reg, uart->divisor);
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+static struct serial_device *get_console(void)
+{
+ if (fdt_decode_uart_console(gd->blob, &console_uart,
+ gd->baudrate))
+ return NULL;
+ strcpy(console.name, "serial");
+ strcpy(console.ctlr, "fdt");
+ console.init = fserial_init;
+ console.uninit = NULL;
+ console.setbrg = fserial_setbrg;
+ console.getc = fserial_getc;
+ console.tstc = fserial_tstc;
+ console.putc = fserial_putc;
+ console.puts = fserial_puts;
+ return &console;
+}
+
+struct serial_device *serial_fdt_get_console_f(void)
+{
+ /* if the uart isn't already set up, do it now */
+ if (console_uart.reg == -1U)
+ return get_console();
+
+ /* otherwise just return the current information */
+ return &console;
+}
+
+
+struct serial_device *serial_fdt_get_console_r(void)
+{
+ /*
+ * Relocation moves all our function pointers, so we need to set up
+ * things again. This function will only be called once.
+ *
+ * We cannot do the -1 check as in serial_fdt_get_console_f
+ * because it will be -1 if that function has been ever been called.
+ * However, the function pointers set up by serial_fdt_get_console_f
+ * will be pre-relocation values, so we must re-calculate them.
+ */
+ return get_console();
+}