[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/platform/pc/pci.c b/src/bsp/lk/platform/pc/pci.c
new file mode 100644
index 0000000..87aac3b
--- /dev/null
+++ b/src/bsp/lk/platform/pc/pci.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2009 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 <debug.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/spinlock.h>
+#include <arch/x86/descriptor.h>
+#include <dev/pci.h>
+
+static int last_bus = 0;
+static spin_lock_t lock;
+
+typedef struct {
+    uint16_t size;
+    void *offset;
+    uint16_t selector;
+} __PACKED irq_routing_options_t;
+
+static int pci_type1_detect(void);
+static int pci_bios_detect(void);
+
+int pci_get_last_bus(void)
+{
+    return last_bus;
+}
+
+/*
+ * pointers to installed PCI routines
+ */
+int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
+int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index);
+
+int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value);
+int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value);
+int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value);
+
+int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value);
+int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value);
+int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value);
+
+int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs);
+int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
+
+
+int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_find_pci_device(state, device_id, vendor_id, index);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_find_pci_class_code(state, class_code, index);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_read_config_byte(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_read_config_half(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_read_config_word(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_write_config_byte(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_write_config_half(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_write_config_word(state, reg, value);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+
+int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs)
+{
+    irq_routing_options_t options;
+    options.size = sizeof(irq_routing_entry) **count;
+    options.selector = DATA_SELECTOR;
+    options.offset = entries;
+
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_get_irq_routing_options(&options, pci_irqs);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    *count = options.size / sizeof(irq_routing_entry);
+
+    return res;
+}
+
+int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+    spin_lock_saved_state_t irqstate;
+    spin_lock_irqsave(&lock, irqstate);
+
+    int res = g_pci_set_irq_hw_int(state, int_pin, irq);
+
+    spin_unlock_irqrestore(&lock, irqstate);
+
+    return res;
+}
+
+void pci_init(void)
+{
+    if (!pci_bios_detect()) {
+        dprintf(INFO, "pci bios functions installed\n");
+        dprintf(INFO, "last pci bus is %d\n", last_bus);
+    }
+}
+
+#define PCIBIOS_PRESENT                 0xB101
+#define PCIBIOS_FIND_PCI_DEVICE         0xB102
+#define PCIBIOS_FIND_PCI_CLASS_CODE     0xB103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE  0xB106
+#define PCIBIOS_READ_CONFIG_BYTE        0xB108
+#define PCIBIOS_READ_CONFIG_WORD        0xB109
+#define PCIBIOS_READ_CONFIG_DWORD       0xB10A
+#define PCIBIOS_WRITE_CONFIG_BYTE       0xB10B
+#define PCIBIOS_WRITE_CONFIG_WORD       0xB10C
+#define PCIBIOS_WRITE_CONFIG_DWORD      0xB10D
+#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E
+#define PCIBIOS_PCI_SET_IRQ_HW_INT      0xB10F
+
+#define PCIBIOS_SUCCESSFUL              0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED      0x81
+#define PCIBIOS_BAD_VENDOR_ID           0x83
+#define PCIBIOS_DEVICE_NOT_FOUND        0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER     0x87
+#define PCIBIOS_SET_FAILED              0x88
+#define PCIBIOS_BUFFER_TOO_SMALL        0x89
+
+/*
+ * far call structure used by BIOS32 routines
+ */
+static struct {
+    uint32_t offset;
+    uint16_t selector;
+} __PACKED bios32_entry;
+
+/*
+ * BIOS32 entry header
+ */
+typedef struct {
+    uint8_t magic[4];   // "_32_"
+    void * entry;       // entry point
+    uint8_t revision;
+    uint8_t length;
+    uint8_t checksum;
+    uint8_t reserved[5];
+} __PACKED pci_bios_info;
+
+/*
+ * scan for pci bios
+ */
+static const char * pci_bios_magic = "_32_";
+static pci_bios_info *find_pci_bios_info(void)
+{
+    uint32_t *head = (uint32_t *) 0x000e0000;
+    int8_t sum, *b;
+    uint i;
+
+    while (head < (uint32_t *) 0x000ffff0) {
+        if (*head == *(uint32_t *) pci_bios_magic) {
+            // perform the checksum
+            sum = 0;
+            b = (int8_t *) head;
+            for (i=0; i < sizeof(pci_bios_info); i++) {
+                sum += b[i];
+            }
+
+            if (sum == 0) {
+                return (pci_bios_info *) head;
+            }
+        }
+
+        head += 4;
+    }
+
+    return NULL;
+}
+
+/*
+ * local BIOS32 PCI routines
+ */
+static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+    uint32_t bx, ret;
+
+    __asm__(
+        "lcall *(%%edi)		\n\t"
+        "jc 1f				\n\t"
+        "xor %%ah,%%ah		\n"
+        "1:"
+        : "=b"(bx),
+        "=a"(ret)
+        : "1"(PCIBIOS_FIND_PCI_DEVICE),
+        "c"(device_id),
+        "d"(vendor_id),
+        "S"(index),
+        "D"(&bios32_entry));
+
+    state->bus = bx >> 8;
+    state->dev_fn = bx & 0xFF;
+
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+    uint32_t bx, ret;
+
+    __asm__(
+        "lcall *(%%edi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=b"(bx),
+        "=a"(ret)
+        : "1"(PCIBIOS_FIND_PCI_CLASS_CODE),
+        "c"(class_code),
+        "S"(index),
+        "D"(&bios32_entry));
+
+    state->bus = bx >> 8;
+    state->dev_fn = bx & 0xFF;
+
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+
+static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=c"(*value),
+        "=a"(ret)
+        : "1"(PCIBIOS_READ_CONFIG_BYTE),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=c"(*value),
+        "=a"(ret)
+        : "1"(PCIBIOS_READ_CONFIG_WORD),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=c"(*value),
+        "=a"(ret)
+        : "1"(PCIBIOS_READ_CONFIG_DWORD),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=a"(ret)
+        : "0"(PCIBIOS_WRITE_CONFIG_BYTE),
+        "c"(value),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)	\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=a"(ret)
+        : "0"(PCIBIOS_WRITE_CONFIG_WORD),
+        "c"(value),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+    uint32_t bx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=a"(ret)
+        : "0"(PCIBIOS_WRITE_CONFIG_DWORD),
+        "c"(value),
+        "b"(bx),
+        "D"(reg),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs)
+{
+    uint32_t ret;
+
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=b"(*pciIrqs),
+        "=a"(ret)
+        : "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS),
+        "b"(0),
+        "D"(route_buffer),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xff;
+}
+
+static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+    uint32_t bx, cx, ret;
+
+    bx = state->bus;
+    bx <<= 8;
+    bx |= state->dev_fn;
+    cx = irq;
+    cx <<= 8;
+    cx |= int_pin;
+    __asm__(
+        "lcall *(%%esi)			\n\t"
+        "jc 1f					\n\t"
+        "xor %%ah,%%ah			\n"
+        "1:"
+        : "=a"(ret)
+        : "0"(PCIBIOS_PCI_SET_IRQ_HW_INT),
+        "b"(bx),
+        "c"(cx),
+        "S"(&bios32_entry));
+    ret >>= 8;
+    return ret & 0xFF;
+}
+
+static const char *pci_signature = "PCI ";
+static int pci_bios_detect(void)
+{
+    pci_bios_info * pci = find_pci_bios_info();
+
+    if (pci != NULL) {
+        /*printf("Found PCI structure at %08x\n", (uint32_t) pci);
+
+        printf("\nPCI header info:\n");
+        printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
+            pci->magic[3]);
+        printf("%08x\n", (uint32_t) pci->entry);
+        printf("%d\n", pci->length * 16);
+        printf("%d\n", pci->checksum);*/
+
+        uint32_t adr, temp, len;
+        uint8_t err;
+
+        bios32_entry.offset = (uint32_t) pci->entry;
+        bios32_entry.selector = CODE_SELECTOR;
+
+        __asm__(
+            "lcall *(%%edi)"
+            : "=a"(err),    /* AL out=status */
+            "=b"(adr),    /* EBX out=code segment base adr */
+            "=c"(len),    /* ECX out=code segment size */
+            "=d"(temp)    /* EDX out=entry pt offset in code */
+            : "0"(0x49435024),/* EAX in=service="$PCI" */
+            "1"(0),   /* EBX in=0=get service entry pt */
+            "D"(&bios32_entry)
+        );
+
+        if (err == 0x80) {
+            dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
+            return -1;
+        }
+
+        if (err != 0) {
+            dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
+            return -1;
+        }
+
+        bios32_entry.offset = adr + temp;
+
+        // now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
+        uint16_t present, version, busses;
+        uint32_t signature;
+        __asm__(
+            "lcall *(%%edi)		\n\t"
+            "jc 1f				\n\t"
+            "xor %%ah,%%ah		\n"
+            "1:"
+            : "=a"(present),
+            "=b"(version),
+            "=c"(busses),
+            "=d"(signature)
+            : "0"(PCIBIOS_PRESENT),
+            "D"(&bios32_entry)
+        );
+
+        if (present & 0xff00) {
+            dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
+            return -1;
+        }
+
+        if (signature != *(uint32_t *)pci_signature) {
+            dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
+            return -1;
+        }
+
+        //dprintf(DEBUG, "busses=%04x\n", busses);
+        last_bus = busses & 0xff;
+
+        g_pci_find_pci_device = bios_find_pci_device;
+        g_pci_find_pci_class_code = bios_find_pci_class_code;
+
+        g_pci_read_config_word = bios_read_config_word;
+        g_pci_read_config_half = bios_read_config_half;
+        g_pci_read_config_byte = bios_read_config_byte;
+
+        g_pci_write_config_word = bios_write_config_word;
+        g_pci_write_config_half = bios_write_config_half;
+        g_pci_write_config_byte = bios_write_config_byte;
+
+        g_pci_get_irq_routing_options = bios_get_irq_routing_options;
+        g_pci_set_irq_hw_int = bios_set_irq_hw_int;
+
+        return 0;
+    }
+
+    return -1;
+}