[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/lib/mempool/include/lib/mempool.h b/src/bsp/lk/lib/mempool/include/lib/mempool.h
new file mode 100644
index 0000000..2da3f36
--- /dev/null
+++ b/src/bsp/lk/lib/mempool/include/lib/mempool.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ *
+ * 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.
+ */
+#pragma once
+
+#include <compiler.h>
+#include <stddef.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS
+
+/* mempool type */
+enum {
+    MEMPOOL_CACHE = 0,
+    MEMPOOL_UNCACHE,
+
+    MAX_MEMPOOL_TYPE,
+    MEMPOOL_ANY /* a pseudo type to indicate any mempool */
+};
+
+/* init mempool of type
+ *
+ * We will always return cache line aligned memory address to caller,
+ * so the start address of each mempool should be aligned to a cache line.
+ */
+int mempool_init(void *mem, size_t size, uint32_t type);
+
+/* alloc mem of type from mempool
+ *
+ * returned memory with following characteristics,
+ * - start address aligned to a cache line
+ * - size round up to multiple of CACHE_LINE
+ */
+void *mempool_alloc(size_t size, uint32_t type);
+
+/* free mem back to mempool */
+void mempool_free(void *mem);
+
+/* clear mempool, used for test code */
+void mempool_clear(void);
+
+__END_CDECLS
diff --git a/src/bsp/lk/lib/mempool/mempool.c b/src/bsp/lk/lib/mempool/mempool.c
new file mode 100644
index 0000000..2ea2208
--- /dev/null
+++ b/src/bsp/lk/lib/mempool/mempool.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ *
+ * 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 <assert.h>
+#include <err.h>
+#include <kernel/mutex.h>
+#include <lib/console.h>
+#include <lib/mempool.h>
+#include <list.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trace.h>
+
+#define LOCAL_TRACE 0
+
+struct mem_chunk {
+    struct list_node node;
+    void *start;
+    size_t len;
+    bool free;
+};
+
+struct mempool {
+    struct list_node chunk_list;
+    void *start;
+    size_t len;
+};
+
+static struct mempool pool[MAX_MEMPOOL_TYPE] = {
+    { LIST_INITIAL_VALUE(pool[0].chunk_list), NULL, 0 },
+    { LIST_INITIAL_VALUE(pool[1].chunk_list), NULL, 0 }
+};
+
+static mutex_t memlock = MUTEX_INITIAL_VALUE(memlock);
+
+int mempool_init(void *mem, size_t size, uint32_t type)
+{
+    int i;
+    int ret;
+    struct mem_chunk *chunk;
+
+    LTRACEF("pool init %p, size %zx, type %d\n", mem, size, type);
+
+    /* check input arg, mem address should be aligned to a cache line */
+    if (!mem || !IS_ALIGNED(mem, CACHE_LINE) ||
+            !size || (type >= MAX_MEMPOOL_TYPE))
+        return ERR_INVALID_ARGS;
+
+    ret = NO_ERROR;
+    mutex_acquire(&memlock);
+    /* check if the mem address already inited */
+    for (i = 0; i < MAX_MEMPOOL_TYPE; i++) {
+        list_for_every_entry(&pool[i].chunk_list, chunk,
+                             struct mem_chunk, node) {
+            if (chunk->start <= mem && ((chunk->start + chunk->len) > mem)) {
+                ret = ERR_ALREADY_EXISTS;
+                goto exit;
+            }
+        }
+    }
+
+    chunk = (struct mem_chunk *)malloc(sizeof(struct mem_chunk));
+    if (!chunk) {
+        ret = ERR_NO_MEMORY;
+        goto exit;
+    }
+
+    chunk->start = mem;
+    chunk->len = size;
+    chunk->free = true;
+    list_add_tail(&pool[type].chunk_list, &chunk->node);
+
+exit:
+    mutex_release(&memlock);
+    return ret;
+}
+
+void *mempool_alloc(size_t size, uint32_t type)
+{
+    bool found;
+    uint32_t i, s_type, e_type;
+    size_t alloc_size;
+    struct mem_chunk *chunk, *new_chunk;
+
+    LTRACEF("pool alloc size %zx, type %d\n", size, type);
+
+    if (!size ||
+            ((type >= MAX_MEMPOOL_TYPE) && (type != MEMPOOL_ANY)))
+        return NULL;
+
+    alloc_size = ROUNDUP(size, CACHE_LINE);
+    found = false;
+
+    s_type = e_type = type;
+    if (type == MEMPOOL_ANY) {
+        s_type = 0;
+        e_type = MAX_MEMPOOL_TYPE - 1;
+    }
+
+    mutex_acquire(&memlock);
+    for (i = s_type; i <= e_type; i++) {
+        list_for_every_entry(&pool[i].chunk_list, chunk,
+                             struct mem_chunk, node) {
+            if (chunk->len < alloc_size || !chunk->free)
+                continue;
+
+            found = true;
+            break;
+        }
+
+        if (found)
+            break;
+    }
+
+    new_chunk = NULL;
+    if (found) {
+        /* if the chunk len happend to equal to alloc size, just return it */
+        if (chunk->len == alloc_size) {
+            chunk->free = false;
+            new_chunk = chunk;
+        } else {
+            new_chunk = (struct mem_chunk *)malloc(sizeof(struct mem_chunk));
+            if (new_chunk) {
+                new_chunk->start = chunk->start;
+                new_chunk->len = alloc_size;
+                new_chunk->free = false;
+                chunk->start = chunk->start + alloc_size;
+                chunk->len -= alloc_size;
+                list_add_before(&chunk->node, &new_chunk->node);
+            }
+        }
+    }
+
+    mutex_release(&memlock);
+    return new_chunk ? new_chunk->start : NULL;
+}
+
+void mempool_free(void *ptr)
+{
+    int i;
+    bool found;
+    struct mem_chunk *chunk, *prev, *next;
+
+    LTRACEF("pool free %p\n", ptr);
+
+    if (NULL == ptr)
+        return;
+
+    /* walk through list to find matched chunk */
+    found = false;
+    mutex_acquire(&memlock);
+    for (i = 0; i < MAX_MEMPOOL_TYPE; i++) {
+        list_for_every_entry(&pool[i].chunk_list, chunk,
+                             struct mem_chunk, node) {
+            if (!chunk->free && (chunk->start == ptr)) {
+                found = true;
+                break;
+            }
+        }
+
+        if (found) {
+            /* merge with adjecent chunk if possible */
+            prev = list_prev_type(&pool[i].chunk_list, &chunk->node,
+                                  struct mem_chunk, node);
+            if (prev && prev->free && ((prev->start + prev->len) == ptr)) {
+                chunk->len += prev->len;
+                chunk->start = prev->start;
+                list_delete(&prev->node);
+                free(prev);
+                prev = NULL;
+            }
+
+            next = list_next_type(&pool[i].chunk_list, &chunk->node,
+                                  struct mem_chunk, node);
+            if (next && next->free &&
+                    ((chunk->start + chunk->len) == next->start)) {
+                chunk->len += next->len;
+                list_delete(&next->node);
+                free(next);
+                next = NULL;
+            }
+
+            chunk->free = true;
+
+            break;
+        }
+    }
+
+    mutex_release(&memlock);
+}
+
+void mempool_clear(void)
+{
+    int i;
+    struct mem_chunk *chunk;
+    struct mem_chunk *temp;
+
+    /* delete every node in the list */
+    mutex_acquire(&memlock);
+    for (i = 0; i < MAX_MEMPOOL_TYPE; i++) {
+        list_for_every_entry_safe(&pool[i].chunk_list, chunk, temp,
+                                  struct mem_chunk, node) {
+            list_delete(&chunk->node);
+            free(chunk);
+            chunk = NULL;
+        }
+        pool[i].start = NULL;
+        pool[i].len = 0;
+    }
+
+    mutex_release(&memlock);
+}
+
+#if LK_DEBUGLEVEL > 1
+
+#include <lib/console.h>
+
+static int cmd_mempool(int argc, const cmd_args *argv);
+static void show_usage(const char *cmd);
+
+STATIC_COMMAND_START
+STATIC_COMMAND("mempool", "mempool debug commands", &cmd_mempool)
+STATIC_COMMAND_END(mempool);
+
+static void show_usage(const char *cmd)
+{
+    printf("usage:\n");
+    printf("\t%s init <address> <size> <type>\n", cmd);
+    printf("\t%s info\n", cmd);
+    printf("\t%s alloc <size> <type>\n", cmd);
+    printf("\t%s free <address>\n", cmd);
+}
+
+static void mempool_dump(void)
+{
+    int i;
+    struct mem_chunk *chunk;
+
+    for (i = 0; i < MAX_MEMPOOL_TYPE; i++) {
+        printf("dump mempool type %d\n", i);
+        list_for_every_entry(&pool[i].chunk_list, chunk,
+                             struct mem_chunk, node) {
+            printf("start %p, len %zx, free %d, type %d\n",
+                   chunk->start, chunk->len, chunk->free, i);
+        }
+    }
+}
+
+static int cmd_mempool(int argc, const cmd_args *argv)
+{
+    int ret;
+    void *p;
+
+    if (argc < 2) {
+notenoughargs:
+        printf("not enough arguments\n");
+usage:
+        show_usage(argv[0].str);
+        return -1;
+    }
+
+    if (strcmp(argv[1].str, "init") == 0) {
+        if (argc < 5)
+            goto notenoughargs;
+
+        ret = mempool_init((void *)argv[2].u, argv[3].u, argv[4].i);
+        if (ret != NO_ERROR)
+            printf("mempool_init failed, ret %d\n", ret);
+    } else if (strcmp(argv[1].str, "info") == 0) {
+        mempool_dump();
+    } else if (strcmp(argv[1].str, "alloc") == 0) {
+        if (argc < 4)
+            goto notenoughargs;
+
+        p = mempool_alloc(argv[2].u, argv[3].i);
+        if (!p) {
+            printf("mempool alloc failed, size %lu, type %ld\n",
+                   argv[2].u, argv[3].i);
+            mempool_dump();
+        }
+    } else if (strcmp(argv[1].str, "free") == 0) {
+        if (argc < 3)
+            goto notenoughargs;
+
+        mempool_free((void *)(uintptr_t)argv[2].u);
+    } else {
+        printf("unrecognized command\n");
+        goto usage;
+    }
+
+    return 0;
+}
+#endif
diff --git a/src/bsp/lk/lib/mempool/rules.mk b/src/bsp/lk/lib/mempool/rules.mk
new file mode 100644
index 0000000..6ddd3fc
--- /dev/null
+++ b/src/bsp/lk/lib/mempool/rules.mk
@@ -0,0 +1,8 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS += \
+	$(LOCAL_DIR)/mempool.c
+
+include make/module.mk
diff --git a/src/bsp/lk/lib/mempool/test/mempool_test.c b/src/bsp/lk/lib/mempool/test/mempool_test.c
new file mode 100644
index 0000000..d3e73a5
--- /dev/null
+++ b/src/bsp/lk/lib/mempool/test/mempool_test.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2017 MediaTek Inc.
+ *
+ * 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 <err.h>
+#include <lib/mempool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unittest.h>
+
+struct mempool_range {
+    void *start;
+    size_t size;
+    uint32_t type;
+};
+
+struct mempool_range test_mempool_range[] = {
+    { (void *)0x40000000, 0x20000, MEMPOOL_CACHE },
+    { (void *)0x40020000, 0x20000, MEMPOOL_UNCACHE },
+    { (void *)0x60000000, 0x20000, MEMPOOL_UNCACHE },
+    { (void *)0x60020000, 0x20000, MEMPOOL_CACHE }
+};
+
+#define NUM_OF_TEST_MEM_RANGE   (sizeof(test_mempool_range)/sizeof(struct mempool_range))
+
+static int test_init_mempool(uint32_t type)
+{
+    uint32_t i;
+    uint32_t s_type, e_type;
+    int ret;
+    struct mempool_range *m;
+
+    mempool_clear();
+
+    ret = 0;
+    for (i = 0; i < NUM_OF_TEST_MEM_RANGE; i++) {
+        m = &test_mempool_range[i];
+        if ((type != MEMPOOL_ANY) && (m->type != type))
+            continue;
+
+        ret = mempool_init(m->start, m->size, m->type);
+        if (ret != NO_ERROR)
+            return ret;
+    }
+
+    return NO_ERROR;
+}
+
+static bool test_mempool_init(void)
+{
+    BEGIN_TEST;
+
+    int ret;
+
+    mempool_clear();
+
+    /* input arguments check */
+    ret = mempool_init(NULL, 0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_INVALID_ARGS, ret, "mempool_init should fail with mem:NULL");
+    ret = mempool_init((void *)0x40000000, 0, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_INVALID_ARGS, ret, "mempool_init should fail with size:0");
+    ret = mempool_init((void *)0x40000000, 0x20000, MAX_MEMPOOL_TYPE);
+    EXPECT_EQ(ERR_INVALID_ARGS, ret,
+              "mempool_init should fail with invalid type");
+    ret = mempool_init((void *)0x40000003, 0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_INVALID_ARGS, ret,
+              "mempool_init should fail with non cache line aligned address");
+
+    EXPECT_EQ(NO_ERROR, test_init_mempool(MEMPOOL_ANY), "fail to init mempool");
+
+    /* memory pool region overlap check */
+    ret = mempool_init((void *)0x40000000, 0x1000, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in pool");
+    ret = mempool_init((void *)0x40001000, 0x1000, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in pool");
+    ret = mempool_init((void *)0x40000000, 0x1000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in other pool");
+    ret = mempool_init((void *)0x60000000, 0x1000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in pool");
+    ret = mempool_init((void *)0x60008000, 0x20000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in pool");
+    ret = mempool_init((void *)0x60001000, 0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(ERR_ALREADY_EXISTS, ret,
+              "mempool_init should fail when memory exists in other pool");
+
+    /* add new memory to pools */
+    ret = mempool_init((void *)0x40040000, 0x30000, MEMPOOL_CACHE);
+    EXPECT_EQ(NO_ERROR, ret,
+              "fail to init memory of MEMPOOL_CACHE with new memory range");
+    ret = mempool_init((void *)0x40080000, 0x40000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(NO_ERROR, ret,
+              "fail to init memory of MEMPOOL_UNCACHE with new memory range");
+
+    END_TEST;
+}
+
+static bool test_mempool_alloc_free(void)
+{
+    BEGIN_TEST;
+
+    int i;
+    uintptr_t mem;
+
+    EXPECT_EQ(NO_ERROR, test_init_mempool(MEMPOOL_ANY), "fail to init mempool");
+
+    /* input argument check */
+    mem = (uintptr_t)mempool_alloc(0, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem, "mempool_alloc should fail when size = 0");
+    mem = (uintptr_t)mempool_alloc(0x1000, MAX_MEMPOOL_TYPE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail with invalid mempool type");
+
+    /* alloc fail test */
+    mem = (uintptr_t)mempool_alloc(0x40000, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when not enough memory");
+    mem = (uintptr_t)mempool_alloc(0x30000, MEMPOOL_UNCACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when not enough memory");
+
+    /* free test */
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40000000UL, mem, "fail to alloc from cache pool");
+    mempool_free((void *)mem);
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40000000UL, mem,
+              "fail to alloc size:0x20000 after free from cache pool");
+
+    /* alloc from 2nd mempool */
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x60020000UL, mem, "fail to alloc from 2nd cache pool");
+    mempool_free((void *)0x40000000UL);
+    mempool_free((void *)0x60020000UL);
+
+    /* round up size to multiple cache line alloc test */
+    mempool_alloc(0x3, MEMPOOL_CACHE);
+    mempool_alloc(0x8, MEMPOOL_CACHE);
+    mempool_alloc(0x11, MEMPOOL_CACHE);
+    mempool_alloc(0x21, MEMPOOL_CACHE);
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+    i = ROUNDUP(0x3, CACHE_LINE) +
+        ROUNDUP(0x8, CACHE_LINE) +
+        ROUNDUP(0x11, CACHE_LINE) +
+        ROUNDUP(0x21, CACHE_LINE);
+    EXPECT_EQ(0x40000000UL + i, mem,
+              "fail to round up alloc size from cache pool");
+
+    test_init_mempool(MEMPOOL_ANY);
+
+    mem = (uintptr_t)mempool_alloc(0xffff, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40000000UL, mem, "fail to alloc size: 0xffff from cache pool");
+    mem = (uintptr_t)mempool_alloc(0x10000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40010000UL, mem,
+              "fail to alloc size: 0x10000 after round up size alloc");
+    mem = (uintptr_t)mempool_alloc(0x1ffff, MEMPOOL_CACHE);
+    EXPECT_EQ(0x60020000UL, mem, "fail to alloc from 2nd cache pool");
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no enoguh memory");
+
+    /* alloc test from uncache pool */
+    mem = (uintptr_t)mempool_alloc(0x10000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x40020000UL, mem, "fail to alloc from uncache pool");
+    mem = (uintptr_t)mempool_alloc(0x1ffff, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x60000000UL, mem, "fail to alloc from uncache pool");
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x40030000UL, mem, "fail to alloc from uncache pool");
+
+    /* free all previously allocated mem */
+    mempool_free((void *)0x40000000UL);
+    mempool_free((void *)0x40010000UL);
+    mempool_free((void *)0x60020000UL);
+    mempool_free((void *)0x40020000UL);
+    mempool_free((void *)0x40030000UL);
+    mempool_free((void *)0x60000000UL);
+
+    /* interleaved alloc and free test */
+    for (i = 0; i < 0x20000; i += 0x1000) {
+        mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+        EXPECT_EQ(0x40000000UL + i, mem,
+                  "fail to continuously alloc from 1st cache pool");
+    }
+
+    for (i = 0; i < 0x20000; i += 0x1000) {
+        mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+        EXPECT_EQ(0x60020000UL + i, mem,
+                  "fail to continuously alloc from 1st cache pool");
+    }
+
+    for (i = 0; i < 0x20000; i += 0x1000) {
+        mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_UNCACHE);
+        EXPECT_EQ(0x40020000UL + i, mem,
+                  "fail to continuously alloc frmo 1st uncache pool");
+    }
+
+    for (i = 0; i < 0x20000; i += 0x1000) {
+        mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_UNCACHE);
+        EXPECT_EQ(0x60000000UL + i, mem,
+                  "fail to continuously alloc frmo 1st uncache pool");
+    }
+
+    mempool_free((void *)0x40000000);
+    mempool_free((void *)0x40002000);
+    mempool_free((void *)0x4001f000);
+    mempool_free((void *)0x40020000);
+    mempool_free((void *)0x40022000);
+    mempool_free((void *)0x4003f000);
+    mempool_free((void *)0x4003e000);
+
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no enough memory");
+    mempool_free((void *)0x40001000);
+    mem = (uintptr_t)mempool_alloc(0x3000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40000000, mem,
+              "fail to alloc size:0x3000 from 1st cache pool after free");
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no enough memory");
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x4001f000, mem,
+              "fail to alloc size:0x1000 at the end of 1st cache pool");
+
+    mem = (uintptr_t)mempool_alloc(0x4000, MEMPOOL_UNCACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no enough memory");
+    mempool_free((void *)0x4003d000);
+    mempool_free((void *)0x4003c000);
+    mem = (uintptr_t)mempool_alloc(0x4000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x4003c000, mem,
+              "fail to alloc size:0x4000 at the end of 1st uncache pool");
+    mempool_free((void *)0x40021000);
+    mem = (uintptr_t)mempool_alloc(0x4000, MEMPOOL_UNCACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no enough memory");
+    mempool_free((void *)0x40023000);
+    mem = (uintptr_t)mempool_alloc(0x4000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x40020000, mem,
+              "fail to alloc size:0x4000 at the begin of 1st uncache pool");
+
+    END_TEST;
+}
+
+static bool test_mempool_alloc_any(void)
+{
+    BEGIN_TEST;
+
+    uintptr_t mem;
+
+    /* init mempool with both cached and uncached mempool */
+    EXPECT_EQ(NO_ERROR, test_init_mempool(MEMPOOL_ANY), "fail to init mempool");
+
+    mem = (uintptr_t)mempool_alloc(0x4000, MEMPOOL_ANY);
+    EXPECT_EQ(0x40000000, mem,
+              "fail to alloc from cache mem for MEMPOOL_ANY");
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_ANY);
+    EXPECT_EQ(0x60020000, mem,
+              "fail to alloc from uncached mem for MEMPOOL_ANY");
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_ANY);
+    EXPECT_EQ(0x40004000, mem,
+              "fail to alloc from cached mem for MEMPOOL_ANY");
+    mem = (uintptr_t)mempool_alloc(0x1000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40005000, mem,
+              "fail to alloc from cached mem for MEMPOOL_CACHE");
+    mem = (uintptr_t)mempool_alloc(0x1f000, MEMPOOL_ANY);
+    EXPECT_EQ(0x40020000, mem,
+              "fail to alloc from uncached mem for MEMPOOL_ANY");
+
+    /* init only cached mempool */
+    EXPECT_EQ(NO_ERROR, test_init_mempool(MEMPOOL_CACHE),
+              "fail to init mempool");
+
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_ANY);
+    EXPECT_EQ(0x40000000, mem,
+              "fail to alloc from cached mem for MEMPOOL_ANY");
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_UNCACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no uncached mempool");
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_CACHE);
+    EXPECT_EQ(0x40002000, mem,
+              "fail to alloc from cached mem for MEMPOOL_CACHE");
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_ANY);
+    EXPECT_EQ(0x60020000, mem,
+              "fail to alloc from cached mem for MEMPOOL_CACHE");
+
+    /* init only uncached mempool */
+    EXPECT_EQ(NO_ERROR, test_init_mempool(MEMPOOL_UNCACHE),
+              "fail to init mempool");
+
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_ANY);
+    EXPECT_EQ(0x40020000, mem,
+              "fail to alloc from uncached mem for MEMPOOL_ANY");
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_CACHE);
+    EXPECT_EQ((uintptr_t)NULL, mem,
+              "mempool_alloc should fail when no cached mempool");
+    mem = (uintptr_t)mempool_alloc(0x2000, MEMPOOL_UNCACHE);
+    EXPECT_EQ(0x40022000, mem,
+              "fail to alloc from uncached mem for MEMPOOL_UNCACHE");
+    mem = (uintptr_t)mempool_alloc(0x20000, MEMPOOL_ANY);
+    EXPECT_EQ(0x60000000, mem,
+              "fail to alloc from uncached mem for MEMPOOL_ANY");
+
+    END_TEST;
+}
+
+BEGIN_TEST_CASE(mempool_tests);
+RUN_TEST(test_mempool_init);
+RUN_TEST(test_mempool_alloc_free);
+RUN_TEST(test_mempool_alloc_any);
+END_TEST_CASE(mempool_tests);
diff --git a/src/bsp/lk/lib/mempool/test/rules.mk b/src/bsp/lk/lib/mempool/test/rules.mk
new file mode 100644
index 0000000..b77897b
--- /dev/null
+++ b/src/bsp/lk/lib/mempool/test/rules.mk
@@ -0,0 +1,11 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_DEPS := \
+	lib/mempool
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/mempool_test.c
+
+include make/module.mk