--- /dev/null
+/*
+ * 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";
+ };
+
+
+};
#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;
}
/**
*/
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);
}
/**
*/
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]);
}