[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/pc/uart.c b/src/bsp/lk/platform/pc/uart.c
new file mode 100644
index 0000000..be94bf6
--- /dev/null
+++ b/src/bsp/lk/platform/pc/uart.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dev/driver.h>
+#include <dev/class/uart.h>
+#include <debug.h>
+#include <assert.h>
+#include <malloc.h>
+#include <err.h>
+#include <lib/cbuf.h>
+#include <platform/uart.h>
+#include <arch/x86.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+
+struct device_class uart_device_class = {
+ .name = "uart",
+};
+
+struct uart_driver_state {
+ struct cbuf rx_buf;
+ struct cbuf tx_buf;
+};
+
+static status_t uart_init(struct device *dev);
+
+static enum handler_return uart_irq_handler(void *arg);
+static int uart_write_thread(void *arg);
+
+static ssize_t uart_read(struct device *dev, void *buf, size_t len);
+static ssize_t uart_write(struct device *dev, const void *buf, size_t len);
+
+static struct uart_ops the_ops = {
+ .std = {
+ .device_class = &uart_device_class,
+ .init = uart_init,
+ },
+ .read = uart_read,
+ .write = uart_write,
+};
+
+DRIVER_EXPORT(uart, &the_ops.std);
+
+static status_t uart_init(struct device *dev)
+{
+ status_t res = NO_ERROR;
+
+ if (!dev)
+ return ERR_INVALID_ARGS;
+
+ if (!dev->config)
+ return ERR_NOT_CONFIGURED;
+
+ const struct platform_uart_config *config = dev->config;
+
+ struct uart_driver_state *state = malloc(sizeof(struct uart_driver_state));
+ if (!state) {
+ res = ERR_NO_MEMORY;
+ goto done;
+ }
+
+ dev->state = state;
+
+ /* set up the driver state */
+ cbuf_initialize(&state->rx_buf, config->rx_buf_len);
+ cbuf_initialize(&state->tx_buf, config->tx_buf_len);
+
+ /* configure the uart */
+ int divisor = 115200 / config->baud_rate;
+
+ outp(config->io_port + 3, 0x80); // set up to load divisor latch
+ outp(config->io_port + 0, divisor & 0xff); // lsb
+ outp(config->io_port + 1, divisor >> 8); // msb
+ outp(config->io_port + 3, 3); // 8N1
+ outp(config->io_port + 2, 0x07); // enable FIFO, clear, 14-byte threshold
+
+ register_int_handler(config->irq, uart_irq_handler, dev);
+ unmask_interrupt(config->irq);
+
+ //outp(config->io_port + 1, 0x3); // enable rx data available and tx holding empty interrupts
+ outp(config->io_port + 1, 0x1); // enable rx data available interrupts
+
+ thread_resume(thread_create("[uart writer]", uart_write_thread, dev, DEFAULT_PRIORITY,
+ DEFAULT_STACK_SIZE));
+
+done:
+ return res;
+}
+
+static enum handler_return uart_irq_handler(void *arg)
+{
+ bool resched = false;
+ struct device *dev = arg;
+
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->config);
+ DEBUG_ASSERT(dev->state);
+
+ const struct platform_uart_config *config = dev->config;
+ struct uart_driver_state *state = dev->state;
+
+ while (inp(config->io_port + 5) & (1<<0)) {
+ char c = inp(config->io_port + 0);
+ cbuf_write(&state->rx_buf, &c, 1, false);
+ resched = true;
+ }
+
+ return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE;
+}
+
+static int uart_write_thread(void *arg)
+{
+ struct device *dev = arg;
+
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(dev->config);
+ DEBUG_ASSERT(dev->state);
+
+ const struct platform_uart_config *config = dev->config;
+ struct uart_driver_state *state = dev->state;
+
+ return 0;
+
+ while (true) {
+ char c = cbuf_read(&state->tx_buf, &c, 1, true);
+
+ while ((inp(config->io_port + 5) & (1<<6)) == 0)
+ ;
+
+ outp(config->io_port + 0, c);
+ }
+
+ return 0;
+}
+
+static ssize_t uart_read(struct device *dev, void *buf, size_t len)
+{
+ if (!dev || !buf)
+ return ERR_INVALID_ARGS;
+
+ DEBUG_ASSERT(dev->state);
+ struct uart_driver_state *state = dev->state;
+
+ return cbuf_read(&state->rx_buf, buf, len, true);
+}
+
+static ssize_t uart_write(struct device *dev, const void *buf, size_t len)
+{
+ if (!dev || !buf)
+ return ERR_INVALID_ARGS;
+
+ DEBUG_ASSERT(dev->state);
+ struct uart_driver_state *state = dev->state;
+
+ return cbuf_write(&state->tx_buf, buf, len, true);
+}
+