apm88xxxx: implement kernel serial driver.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 11 Jun 2015 14:06:13 +0000 (16:06 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Thu, 11 Jun 2015 14:06:13 +0000 (16:06 +0200)
Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

devices/Hakefile
devices/apm88xxxx/apm88xxxx_pc16550.dev [new file with mode: 0644]
kernel/Hakefile
kernel/arch/apm88xxxx/uart.c

index 756e6d0..fa18f1e 100644 (file)
@@ -62,6 +62,7 @@
            "ti_i2c",
            "ti_twl6030",
            "sdhc",
+           "apm88xxxx/apm88xxxx_pc16550",
            "omap/ehci",
            "omap/ohci",
            "omap/omap_uart",
diff --git a/devices/apm88xxxx/apm88xxxx_pc16550.dev b/devices/apm88xxxx/apm88xxxx_pc16550.dev
new file mode 100644 (file)
index 0000000..76bc360
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * apm88xxxx/apm88xxxx_pc16550.dev
+ *
+ * DESCRIPTION: APM88xxxx PC16550 UART
+ *
+ * This is derived from:
+ *
+ * APM88xx0x Processor Family Register Reference -- Volume 1
+ * Document Issue 0.98 (APM 2012-0052-1)
+ *
+ * This file only incorporates the parts relevant for UART operation.
+ * Registers relevant for IrDA, CIR, and other modes are not yet
+ * described. 
+ */
+device apm88xxxx_pc16550 msbfirst (addr base) "APM88xxxx UART" {
+
+    constants data_len "Data Length" {
+        bits5   = 0b00   "5 Bits";
+        bits6   = 0b01   "6 Bits";
+        bits7   = 0b10   "7 Bits";
+        bits8   = 0b11   "8 Bits";
+    };
+
+    register RBR ro addr (base, 0x0) "Receive Buffer" {
+        _       24;
+        rbr     8 ro        "Receive buffer register";
+    };
+
+    register THR wo also addr (base, 0x0) "Transmit Register" {
+        _       24;
+        thr     8 wo        "Transmit register";
+    };
+
+    register IIR ro addr (base, 0x8) "Interrupt Identity" type(uint32);
+
+    register lcr rw addr (base, 0xc) "Line control" {
+        _       24;
+        dlab    1           "Divisor latch access bit";
+        bc      1           "Break control bit";
+        sp      1 rsvd      "Stick parity";
+        eps     1           "Even parity select";
+        pen     1           "Parity enable";
+        stop    1           "stop bit";
+        dls     2 type(data_len) "Data length select";
+    };
+
+    register LSR ro addr (base, 0x14) "Line Status" {
+        _       24;
+        rfe      1          "Receive FIFO error";
+        temt     1          "Transmitter empty";
+        thre     1          "Transmit holding register empty";
+        bi       1          "Break interrupt";
+        fe       1          "Framing error";
+        pe       1          "Parity error";
+        oe       1          "Overrun error";
+        dr       1          "Data ready";
+    };
+
+
+};
index ab4e6d2..e70bb72 100644 (file)
@@ -484,7 +484,9 @@ let
                 "arch/apm88xxxx/init.c",
                 "arch/apm88xxxx/paging.c",
                 "arch/apm88xxxx/uart.c" ],
-     mackerelDevices = [ "arm" ],
+     mackerelDevices = [ "arm",
+                         "apm88xxxx/apm88xxxx_pc16550"
+                       ],
      addLibraries = [ "elf", "cpio" ]
      }
   ]
index fe16432..1352e4f 100644 (file)
@@ -1,26 +1,51 @@
 #include <kernel.h>
 #include <serial.h>
+#include <dev/apm88xxxx/apm88xxxx_pc16550_dev.h>
 
 #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
 
 // base addrs
-#define UART0_BASE 0x1C020000
-#define UART1_BASE 0x1C021000
-#define UART2_BASE 0x1C022000
-#define UART3_BASE 0x1C023000
+#define UART0_BASE ((mackerel_addr_t)0x1C020000)
+#define UART1_BASE ((mackerel_addr_t)0x1C021000)
+#define UART2_BASE ((mackerel_addr_t)0x1C022000)
+#define UART3_BASE ((mackerel_addr_t)0x1C023000)
+
+// #ports
+#define NUM_PORTS 4
 
 unsigned serial_console_port, serial_debug_port;
 
+// port base addresses for lookup by port no
+static const mackerel_addr_t portbases[NUM_PORTS] =
+    { UART0_BASE, UART1_BASE, UART2_BASE, UART3_BASE };
+// the mackerel devices
+static apm88xxxx_pc16550_t ports[NUM_PORTS];
+
 errval_t serial_init(unsigned port, bool initialize_hw)
 {
+    if (port >= NUM_PORTS) {
+        return SYS_ERR_SERIAL_PORT_INVALID;
+    }
+
+    apm88xxxx_pc16550_t *uart = &ports[port];
+    apm88xxxx_pc16550_initialize(uart, portbases[port]);
+
+    if (!initialize_hw) {
+        // hw initialized, this is for non-bsp cores, where hw has been
+        // initialized by bsp core and we come through here just to setup our
+        // local apm88xxxx_pc16550 struct for the port.
+        return SYS_ERR_OK;
+    }
 
-    panic("NYI");
+    panic("device init NYI");
+    return SYS_ERR_OK;
 }
 
 errval_t serial_early_init(unsigned port)
 {
-
-    panic("NYI");
+    // XXX: early init we don't need to do anything?
+    // NOTE: adapted from x86/serial.c
+    return SYS_ERR_OK;
 }
 
 /**
@@ -28,8 +53,12 @@ errval_t serial_early_init(unsigned port)
  */
 void serial_putchar(unsigned port, char c)
 {
-
-    panic("NYI");
+    assert(port < NUM_PORTS);
+    assert(ports[port].base != 0);
+    // Wait until FIFO can hold more characters
+    while(!apm88xxxx_pc16550_LSR_thre_rdf(&ports[port]));
+    // Write character
+    apm88xxxx_pc16550_THR_thr_wrf(&ports[port], c);
 }
 
 /** 
@@ -38,5 +67,11 @@ void serial_putchar(unsigned port, char c)
  */
 char serial_getchar(unsigned port)
 {
-    panic("NYI");
+    assert(port < NUM_PORTS);
+    assert(ports[port].base != 0);
+
+    // Wait until character available
+    while(!apm88xxxx_pc16550_LSR_dr_rdf(&ports[port]));
+    // Read a character from FIFO
+    return apm88xxxx_pc16550_RBR_rbr_rdf(&ports[port]);
 }