[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/app/lkboot/dcc.c b/src/bsp/lk/app/lkboot/dcc.c
new file mode 100644
index 0000000..e12b99b
--- /dev/null
+++ b/src/bsp/lk/app/lkboot/dcc.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2015 Travis Geiselbrecht
+ *
+ * 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 "lkboot.h"
+
+#include <stdio.h>
+#include <debug.h>
+#include <string.h>
+#include <compiler.h>
+#include <err.h>
+#include <assert.h>
+#include <trace.h>
+#include <stdlib.h>
+#include <lib/cbuf.h>
+#include <app/lkboot.h>
+#include <arch/arm/dcc.h>
+#include <arch/mmu.h>
+#include <kernel/mutex.h>
+
+#include "pdcc.h"
+
+#define LOCAL_TRACE 0
+
+static struct pdcc_buffer_descriptor buffer_desc __ALIGNED(256);
+static paddr_t buffer_desc_phys;
+
+#define DCC_BUFLEN 256
+
+static uint8_t htod_buffer[DCC_BUFLEN] __ALIGNED(CACHE_LINE);
+static uint8_t dtoh_buffer[DCC_BUFLEN] __ALIGNED(CACHE_LINE);
+
+static uint htod_index;
+static uint htod_pos;
+static bool dtoh_filled;
+
+static void send_pdcc_command(uint32_t opcode, uint32_t data)
+{
+    uint32_t word;
+
+    word = PDCC_VALID |
+        ((opcode & 0x7f) << PDCC_OPCODE_SHIFT) |
+        (data & 0x00ffffff);
+
+    // XXX may block forever
+    LTRACEF("sending 0x%x\n", word);
+    arm_dcc_write(&word, 1, INFINITE_TIME);
+}
+
+static void send_buffer_header(void)
+{
+    send_pdcc_command(PDCC_OP_BUF_HEADER, buffer_desc_phys / 256);
+}
+
+static void send_reset(void)
+{
+    send_pdcc_command(PDCC_OP_RESET, 0);
+}
+
+static void send_out_index_update(uint32_t index)
+{
+    send_pdcc_command(PDCC_OP_UPDATE_OUT_INDEX, index);
+}
+
+static void send_buffer_consumed(void)
+{
+    send_pdcc_command(PDCC_OP_CONSUMED_IN, 0);
+}
+
+#define DCC_PROCESS_RESET 1
+static int dcc_process_opcode(uint32_t word)
+{
+    int ret = 0;
+
+    if (word & PDCC_VALID) {
+        uint32_t opcode = PDCC_OPCODE(word);
+        uint32_t data = PDCC_DATA(word);
+        LTRACEF("word 0x%x, opcode 0x%x, data 0x%x\n", word, opcode, data);
+        switch (opcode) {
+            case PDCC_OP_RESET:
+                htod_index = 0;
+                htod_pos = 0;
+                dtoh_filled = false;
+
+                // try to send the buffer header
+                send_buffer_header();
+                ret = DCC_PROCESS_RESET;
+                break;
+            case PDCC_OP_BUF_HEADER:
+                // we shouldn't get this
+                break;
+
+            case PDCC_OP_UPDATE_OUT_INDEX:
+                if (data > DCC_BUFLEN) {
+                    // out of range
+                    send_reset();
+                } else {
+                    htod_index = data;
+                    htod_pos = 0;
+                    arch_invalidate_cache_range((vaddr_t)htod_buffer, DCC_BUFLEN);
+                }
+                break;
+
+            case PDCC_OP_CONSUMED_IN:
+                arch_invalidate_cache_range((vaddr_t)dtoh_buffer, DCC_BUFLEN);
+                dtoh_filled = false;
+                break;
+            default:
+                TRACEF("bad opcode from host 0x%x\n", opcode);
+                send_reset();
+        }
+    }
+
+    return ret;
+}
+
+static ssize_t dcc_read(void *unused, void *_data, size_t len)
+{
+    unsigned char *data = _data;
+    size_t pos = 0;
+    uint32_t dcc;
+
+    LTRACEF("buf %p, len %zu, htod_pos %u, htod_index %u\n", _data, len, htod_pos, htod_index);
+
+    lk_time_t timeout = 0; // first dcc command should be with no timeout
+    while (pos < len) {
+        // process a dcc command
+        ssize_t err = arm_dcc_read(&dcc, 1, timeout);
+        if (err > 0) {
+            err = dcc_process_opcode(dcc);
+            if (err == DCC_PROCESS_RESET) {
+                return ERR_IO;
+            }
+        }
+
+        // see if there is any data in the incoming buffer
+        if (htod_index > 0) {
+            size_t tocopy = MIN(htod_index - htod_pos, len - pos);
+
+            memcpy(&data[pos], &htod_buffer[htod_pos], tocopy);
+            pos += tocopy;
+            htod_pos += tocopy;
+
+            // if we consumed everything, tell the host we're done with the buffer
+            if (htod_pos == htod_index) {
+                send_buffer_consumed();
+                htod_index = 0;
+                htod_pos = 0;
+                arch_invalidate_cache_range((vaddr_t)htod_buffer, DCC_BUFLEN);
+            }
+        }
+
+        timeout = 1000;
+    }
+
+    return 0;
+}
+
+static ssize_t dcc_write(void *unused, const void *_data, size_t len)
+{
+    const unsigned char *data = _data;
+    size_t pos = 0;
+
+    LTRACEF("buf %p, len %zu\n", _data, len);
+
+    while (pos < len) {
+        LTRACEF("pos %zu, len %zu, dtoh_filled %d\n", pos, len, dtoh_filled);
+        if (!dtoh_filled) {
+            // put as much data as we can in the outgoing buffer
+            size_t tocopy = MIN(len, DCC_BUFLEN);
+
+            LTRACEF("tocopy %zu\n", tocopy);
+            memcpy(dtoh_buffer, data, tocopy);
+            arch_clean_cache_range((vaddr_t)dtoh_buffer, DCC_BUFLEN);
+            send_out_index_update(tocopy);
+            dtoh_filled = true;
+
+            pos += tocopy;
+        }
+
+        // process a dcc command
+        uint32_t dcc;
+        ssize_t err = arm_dcc_read(&dcc, 1, 1000);
+        if (err > 0) {
+            err = dcc_process_opcode(dcc);
+            if (err == DCC_PROCESS_RESET) {
+                return ERR_IO;
+            }
+        }
+    }
+
+    return pos;
+}
+
+lkb_t *lkboot_check_dcc_open(void)
+{
+    lkb_t *lkb = NULL;
+
+    // read a dcc op and process it
+    {
+        uint32_t dcc;
+        ssize_t err = arm_dcc_read(&dcc, 1, 0);
+        if (err > 0) {
+            err = dcc_process_opcode(dcc);
+        }
+    }
+
+    if (htod_index > 0) {
+        // we have data, construct a lkb and return it
+        LTRACEF("we have data on dcc, starting command handler\n");
+        lkb = lkboot_create_lkb(NULL, dcc_read, dcc_write);
+    }
+
+    return lkb;
+}
+
+void lkboot_dcc_init(void)
+{
+    paddr_t pa;
+    __UNUSED status_t err;
+
+    buffer_desc.version = PDCC_VERSION;
+
+    err = arch_mmu_query((vaddr_t)htod_buffer, &pa, NULL);
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    buffer_desc.htod_buffer_phys = pa;
+    buffer_desc.htod_buffer_len = DCC_BUFLEN;
+
+    err = arch_mmu_query((vaddr_t)dtoh_buffer, &pa, NULL);
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    buffer_desc.dtoh_buffer_phys = pa;
+    buffer_desc.dtoh_buffer_len = DCC_BUFLEN;
+
+    err = arch_mmu_query((vaddr_t)&buffer_desc, &buffer_desc_phys, NULL);
+    DEBUG_ASSERT(err == NO_ERROR);
+
+    arch_clean_cache_range((vaddr_t)&buffer_desc, sizeof(buffer_desc));
+}
+