Add mpu driver and remove interface library
from drivers

Add mpu driver for upstreaming

After removing of interface library,targets and applications
will list explicitly which libraries to link

Change-Id: Icfa449a2981093161f283e45b4d52ca6199371b8
diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt
new file mode 100644
index 0000000..1f97dc5
--- /dev/null
+++ b/drivers/CMakeLists.txt
@@ -0,0 +1,49 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#############################################################################
+# Mailbox driver
+#############################################################################
+add_subdirectory(mailbox)
+
+#############################################################################
+# MHU drivers
+#############################################################################
+# NOTE: These are all built and linked from a CMake perspective. However the
+#       application code can instantiate one or more of the drivers. The
+#       one(s) not used will later be removed by the linker.
+add_subdirectory(mhu_v2)
+add_subdirectory(mhu_juno)
+add_subdirectory(mhu_dummy)
+
+#############################################################################
+# UART drivers
+#############################################################################
+# NOTE: All UART drivers are built, however a platform application should
+#       link the appropriate driver target (see drivers/uart/CMakeLists.txt).
+add_subdirectory(uart)
+
+#############################################################################
+# Timing adapter driver
+#############################################################################
+add_subdirectory(timing_adapter)
+
+#############################################################################
+# MPU driver
+#############################################################################
+add_subdirectory(mpu)
diff --git a/drivers/mailbox/CMakeLists.txt b/drivers/mailbox/CMakeLists.txt
new file mode 100644
index 0000000..bf8889a
--- /dev/null
+++ b/drivers/mailbox/CMakeLists.txt
@@ -0,0 +1,21 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(ethosu_mailbox STATIC)
+target_include_directories(ethosu_mailbox PUBLIC include)
+target_sources(ethosu_mailbox PRIVATE src/mailbox.cpp)
diff --git a/drivers/mailbox/include/mailbox.hpp b/drivers/mailbox/include/mailbox.hpp
new file mode 100644
index 0000000..f6d9edb
--- /dev/null
+++ b/drivers/mailbox/include/mailbox.hpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MAILBOX_HPP
+#define MAILBOX_HPP
+
+#include <cstddef>
+#include <cstdint>
+#include <list>
+
+namespace Mailbox {
+
+/**
+ * The Mailbox parent class
+ *
+ * Intended to be implemented by a driver subclass, see MHU_v2 driver as example.
+ */
+class Mailbox {
+public:
+    /**
+     * Constructor/Destructor
+     */
+    Mailbox();
+    virtual ~Mailbox();
+
+    /**
+     * Intended to trigger an interrupt to an external block
+     * MUST be implemented by subclass.
+     */
+    virtual bool sendMessage() = 0;
+
+    /**
+     * Intended to be called when Cortex M has received an
+     * interrupt/event from mailbox/mhu. If an interrupt needs to be cleared,
+     * this is a good place to do that. MUST call notify().
+     * MUST be implemented by subclass.
+     */
+    virtual void handleMessage() = 0;
+
+    /**
+     * Can be used to verify that hardware versions match expected versions
+     * CAN be implemented by subclass, optional. Default impl returns true.
+     */
+    virtual bool verifyHardware();
+
+    /**
+     * Function signature for callbacks
+     */
+    typedef void (*CallbackFptr)(void *userArg);
+
+    /**
+     * Register a callback to be called when a message is received.
+     */
+    void registerCallback(CallbackFptr callback, void *userArg);
+
+    /**
+     * Remove a specific callback from the callback list.
+     */
+    void deregisterCallback(CallbackFptr callback, void *userArg);
+
+protected:
+    /**
+     * Calls every registered callback when a message has been received.
+     */
+    void notify();
+
+    /**
+     * Helper functions
+     */
+    uint32_t read32(volatile uint32_t *baseAddr, const uint32_t offset);
+    void write32(volatile uint32_t *baseAddr, const uint32_t offset, const uint32_t value);
+
+private:
+    struct Callback {
+        bool operator==(const Callback &b) const;
+        CallbackFptr callback;
+        void *userArg;
+    };
+
+    std::list<Callback> callbacks;
+};
+
+} // namespace Mailbox
+
+#endif
diff --git a/drivers/mailbox/src/mailbox.cpp b/drivers/mailbox/src/mailbox.cpp
new file mode 100644
index 0000000..e5950f0
--- /dev/null
+++ b/drivers/mailbox/src/mailbox.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mailbox.hpp>
+
+#include <cassert>
+#include <cstddef>
+
+namespace Mailbox {
+
+Mailbox::Mailbox() {}
+Mailbox::~Mailbox() {}
+
+bool Mailbox::verifyHardware() {
+    return true;
+}
+
+void Mailbox::registerCallback(CallbackFptr callback, void *userArg) {
+    callbacks.push_back({callback, userArg});
+}
+
+void Mailbox::deregisterCallback(CallbackFptr callback, void *userArg) {
+    callbacks.remove({callback, userArg});
+}
+
+void Mailbox::notify() {
+    for (auto &it : callbacks) {
+        it.callback(it.userArg);
+    }
+}
+
+uint32_t Mailbox::read32(volatile uint32_t *baseAddr, const uint32_t offset) {
+    assert(offset % 4 == 0);
+    volatile uint32_t *addr = baseAddr + (offset / 4);
+
+    return *addr;
+}
+
+void Mailbox::write32(volatile uint32_t *baseAddr, const uint32_t offset, const uint32_t value) {
+    assert(offset % 4 == 0);
+    volatile uint32_t *addr = baseAddr + (offset / 4);
+
+    *addr = value;
+}
+
+bool Mailbox::Callback::operator==(const Callback &b) const {
+    return (callback == b.callback && userArg == b.userArg);
+}
+
+} // namespace Mailbox
diff --git a/drivers/mhu_dummy/CMakeLists.txt b/drivers/mhu_dummy/CMakeLists.txt
new file mode 100644
index 0000000..fca7d5b
--- /dev/null
+++ b/drivers/mhu_dummy/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(ethosu_mhu_dummy STATIC)
+target_include_directories(ethosu_mhu_dummy PUBLIC include)
+
+target_sources(ethosu_mhu_dummy PRIVATE src/mhu_dummy.cpp)
+target_link_libraries(ethosu_mhu_dummy PRIVATE ethosu_mailbox)
diff --git a/drivers/mhu_dummy/include/mhu_dummy.hpp b/drivers/mhu_dummy/include/mhu_dummy.hpp
new file mode 100644
index 0000000..d04fe1c
--- /dev/null
+++ b/drivers/mhu_dummy/include/mhu_dummy.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MHU_DUMMY_HPP
+#define MHU_DUMMY_HPP
+
+#include <mailbox.hpp>
+
+namespace Mailbox {
+
+class MHUDummy : public Mailbox {
+public:
+    MHUDummy();
+    virtual ~MHUDummy();
+    virtual bool sendMessage() final;
+    virtual void handleMessage() final;
+};
+
+} // namespace Mailbox
+
+#endif /* #ifndef MHU_DUMMY_HPP */
diff --git a/drivers/mhu_dummy/src/mhu_dummy.cpp b/drivers/mhu_dummy/src/mhu_dummy.cpp
new file mode 100644
index 0000000..3ae51e7
--- /dev/null
+++ b/drivers/mhu_dummy/src/mhu_dummy.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mhu_dummy.hpp>
+
+namespace Mailbox {
+
+MHUDummy::MHUDummy() {}
+MHUDummy::~MHUDummy() {}
+
+void MHUDummy::handleMessage() {
+    notify();
+}
+bool MHUDummy::sendMessage() {
+    return true;
+}
+
+} // namespace Mailbox
diff --git a/drivers/mhu_juno/CMakeLists.txt b/drivers/mhu_juno/CMakeLists.txt
new file mode 100644
index 0000000..2116ee7
--- /dev/null
+++ b/drivers/mhu_juno/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(ethosu_mhu_juno STATIC)
+target_include_directories(ethosu_mhu_juno PUBLIC include)
+
+target_sources(ethosu_mhu_juno PRIVATE src/mhu_juno.cpp)
+target_link_libraries(ethosu_mhu_juno PRIVATE ethosu_mailbox)
diff --git a/drivers/mhu_juno/include/mhu_juno.hpp b/drivers/mhu_juno/include/mhu_juno.hpp
new file mode 100644
index 0000000..6b36512
--- /dev/null
+++ b/drivers/mhu_juno/include/mhu_juno.hpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MHU_JUNO_HPP
+#define MHU_JUNO_HPP
+
+#include <mailbox.hpp>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace Mailbox {
+
+// Doorbell implementation only
+class MHUJuno : public Mailbox {
+public:
+    MHUJuno(const uint32_t baseAddress);
+    virtual ~MHUJuno();
+    virtual bool sendMessage() final;
+    virtual void handleMessage() final;
+    virtual bool verifyHardware() final;
+
+private:
+    /* Offsets */
+    static constexpr uint32_t CPU0_INTR_STAT = 0x00;
+    static constexpr uint32_t CPU0_INTR_SET  = 0x04;
+    static constexpr uint32_t CPU0_INTR_CLR  = 0x08;
+    static constexpr uint32_t CPU1_INTR_STAT = 0x10;
+    static constexpr uint32_t CPU1_INTR_SET  = 0x14;
+    static constexpr uint32_t CPU1_INTR_CLR  = 0x18;
+    static constexpr uint32_t OFFSET         = 0x10;
+    static constexpr uint32_t PIDR0          = 0xfe0;
+    static constexpr uint32_t PIDR1          = 0xfe4;
+    static constexpr uint32_t PIDR2          = 0xfe8;
+    static constexpr uint32_t PIDR3          = 0xfec;
+    static constexpr uint32_t PIDR4          = 0xfd0;
+    static constexpr uint32_t CIDR0          = 0xff0;
+    static constexpr uint32_t CIDR1          = 0xff4;
+    static constexpr uint32_t CIDR2          = 0xff8;
+    static constexpr uint32_t CIDR3          = 0xffc;
+
+    volatile uint32_t *baseAddr;
+
+    void clearMessage();
+    void write(uint32_t offset, uint32_t val);
+    uint32_t read(uint32_t offset);
+};
+
+} // namespace Mailbox
+
+#endif /* #ifndef MHU_JUNO_HPP */
diff --git a/drivers/mhu_juno/src/mhu_juno.cpp b/drivers/mhu_juno/src/mhu_juno.cpp
new file mode 100644
index 0000000..04b1352
--- /dev/null
+++ b/drivers/mhu_juno/src/mhu_juno.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mhu_juno.hpp>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+namespace Mailbox {
+
+MHUJuno::MHUJuno(const uint32_t baseAddress) {
+    baseAddr = reinterpret_cast<volatile uint32_t *>(baseAddress);
+}
+
+void MHUJuno::handleMessage() {
+    clearMessage();
+    notify();
+}
+
+MHUJuno::~MHUJuno() {}
+
+// Doorbell only
+bool MHUJuno::sendMessage() {
+    write(CPU1_INTR_SET, 1);
+    return true;
+}
+// Doorbell only
+void MHUJuno::clearMessage() {
+    write(CPU0_INTR_CLR, 0xF);
+}
+
+bool MHUJuno::verifyHardware() {
+    uint32_t pidr0 = read(PIDR0);
+    uint32_t pidr1 = read(PIDR1);
+    uint32_t pidr2 = read(PIDR2);
+    uint32_t pidr3 = read(PIDR3);
+    uint32_t pidr4 = read(PIDR4);
+    uint32_t cidr0 = read(CIDR0);
+    uint32_t cidr1 = read(CIDR1);
+    uint32_t cidr2 = read(CIDR2);
+    uint32_t cidr3 = read(CIDR3);
+
+    if (pidr0 != 0x56 || pidr1 != 0xb8 || pidr2 != 0x0b || pidr3 != 0x00 || pidr4 != 0x04 || cidr0 != 0x0d ||
+        cidr1 != 0xf0 || cidr2 != 0x05 || cidr3 != 0xb1) {
+        return false;
+    }
+    return true;
+}
+
+void MHUJuno::write(const uint32_t offset, const uint32_t value) {
+    write32(baseAddr, offset, value);
+}
+
+uint32_t MHUJuno::read(const uint32_t offset) {
+    return read32(baseAddr, offset);
+}
+
+} // namespace Mailbox
diff --git a/drivers/mhu_v2/CMakeLists.txt b/drivers/mhu_v2/CMakeLists.txt
new file mode 100644
index 0000000..2505901
--- /dev/null
+++ b/drivers/mhu_v2/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(ethosu_mhu_v2 STATIC)
+target_include_directories(ethosu_mhu_v2 PUBLIC include)
+
+target_sources(ethosu_mhu_v2 PRIVATE src/mhu_v2.cpp)
+target_link_libraries(ethosu_mhu_v2 PRIVATE ethosu_mailbox ethosu_log)
diff --git a/drivers/mhu_v2/include/mhu_v2.hpp b/drivers/mhu_v2/include/mhu_v2.hpp
new file mode 100644
index 0000000..147bc8a
--- /dev/null
+++ b/drivers/mhu_v2/include/mhu_v2.hpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MHU_V2_HPP
+#define MHU_V2_HPP
+
+#include <mailbox.hpp>
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+namespace Mailbox {
+/*
+ * SENDER OVERVIEW
+ * ------------------------------------------------------------------------
+ * Offset       Access Type Register Name                        Short Name
+ * ------------------------------------------------------------------------
+ * 0x000-0xF7C  -           Sender Channel Window 0-123          -
+ * 0xF80        RO          Message Handling Unit Configuration  MHU_CFG
+ * 0xF84        RW          Response Configuration               RESP_CFG
+ * 0xF88        RW          Access Request                       ACCESS_REQUEST
+ * 0xF8C        RO          Access Ready                         ACCESS_READY
+ * 0xF90        RO          Interrupt Status                     INT_ST
+ * 0xF94        WO          Interrupt Clear                      INT_CLR
+ * 0xF98        RW          Interrupt Enable                     INT_EN
+ * 0xF9C-0xFC4  RO          Reserved                             -
+ * 0xFC8        RO          Implementer Identification Register  IIDR
+ * 0xFCC        RO          Architecture Identification Register AIDR
+ * 0xFD0-0xFFC  -           IMPL DEF Identification Regs         -
+ */
+
+/*
+ * RECEIVER OVERVIEW
+ * ------------------------------------------------------------------------
+ * Offset       Access Type Register Name                        Short Name
+ * ------------------------------------------------------------------------
+ * 0x000-0xF7C  -           Receiver Channel Window 0-123        -
+ * 0xF80        RO          Message Handling Unit Configuration  MHU_CFG
+ * 0xF84-0xFC4  RO          Reserved                             -
+ * 0xFC8        RO          Implementer Identification Register  IIDR
+ * 0xFCC        RO          Architecture Identification Register AIDR
+ * 0xFD0-0xFFC  -           IMPL DEF Identification Regs         -
+ */
+
+/*
+ * Sender Channel Window
+ * ------------------------------------------------------------------------
+ * Offset       Access Type Register Name                        Short Name
+ * ------------------------------------------------------------------------
+ * 0x00         RO          Channel Status                       CH_ST
+ * 0x04         RO          Reserved                             -
+ * 0x08         RO          Reserved                             -
+ * 0x0C         WO          Channel Set                          CH_SET
+ * 0x10         RO          Reserved                             -
+ * 0x14         RO          Reserved                             -
+ * 0x18         RO          Reserved                             -
+ * 0x1C         RO          Reserved                             -
+ */
+
+/*
+ * Receiver Channel Window
+ * ------------------------------------------------------------------------
+ * Offset       Access Type Register Name                        Short Name
+ * ------------------------------------------------------------------------
+ * 0x00         RO          Channel Status                       CH_ST
+ * 0x04         RO          Channel Status Masked                CH_ST_MSK
+ * 0x08         WO          Channel Clear                        CH_CLR
+ * 0x0C         RO          Reserved                             -
+ * 0x10         RO          Channel Mask Status                  CH_MSK_ST
+ * 0x14         WO          Channel Mask Set                     CH_MSK_SET
+ * 0x18         WO          Channel Mask Clear                   CH_MSK_CLR
+ * 0x1C         RO          Reserved                             -
+ */
+
+// Doorbell implementation only
+// NOTE: MHUv2 is unidirectional. Two MHU's are needed for bidirectional
+//       messaging. txBase/rxBase refers to the base address of _two_
+//       separate MHU blocks.
+class MHUv2 : public Mailbox {
+public:
+    MHUv2(const uint32_t txBaseAddress, const uint32_t rxBaseAddress);
+    virtual ~MHUv2();
+    virtual bool sendMessage() final;
+    virtual void handleMessage() final;
+    virtual bool verifyHardware() final;
+
+private:
+    /* Offsets */
+    static constexpr uint32_t MHUv2_CH_ST                   = 0x00;
+    static constexpr uint32_t MHUv2_CH_ST_MSK               = 0x04;
+    static constexpr uint32_t MHUv2_CH_CLR                  = 0x08;
+    static constexpr uint32_t MHUv2_CH_SET                  = 0x0C;
+    static constexpr uint32_t MHUv2_CH_MSK_ST               = 0x10;
+    static constexpr uint32_t MHUv2_CH_MSK_SET              = 0x14;
+    static constexpr uint32_t MHUv2_CH_MSK_CLR              = 0x18;
+    static constexpr uint32_t MHUv2_CH_INT_CLR              = 0x14;
+    static constexpr uint32_t MHUv2_CH_INT_EN               = 0x18;
+    static constexpr uint32_t MHUv2_SND_CHAN_WINDOW_SIZE    = 0x20;
+    static constexpr uint32_t MHUv2_SND_MHU_CFG_OFFS        = 0xF80;
+    static constexpr uint32_t MHUv2_SND_RESP_CFG_OFFS       = 0xF84;
+    static constexpr uint32_t MHUv2_SND_ACCESS_REQUEST_OFFS = 0xF88;
+    static constexpr uint32_t MHUv2_SND_ACCESS_READY_OFFS   = 0xF8C;
+    static constexpr uint32_t MHUv2_SND_INT_ST_OFFS         = 0xF90;
+    static constexpr uint32_t MHUv2_SND_INT_CLR_OFFS        = 0xF94;
+    static constexpr uint32_t MHUv2_SND_INT_EN_OFFS         = 0xF98;
+    static constexpr uint32_t MHUv2_SND_IIDR_OFFS           = 0xFC8;
+    static constexpr uint32_t MHUv2_SND_AIDR_OFFS           = 0xFCC;
+    static constexpr uint32_t MHUv2_RCV_CHAN_WINDOW_SIZE    = 0x20;
+    static constexpr uint32_t MHUv2_RCV_MHU_CFG_OFFS        = 0xF80;
+    static constexpr uint32_t MHUv2_RCV_IIDR_OFFS           = 0xFC8;
+    static constexpr uint32_t MHUv2_RCV_AIDR_OFFS           = 0xFCC;
+    static constexpr uint32_t MHUv2_RCV_INT_EN_OFFS         = 0xF98;
+
+    struct aidr_t {
+        uint32_t ARCH_MINOR_REV : 4;
+        uint32_t ARCH_MAJOR_REV : 4;
+        uint32_t RESERVED : 24;
+    };
+
+    volatile uint32_t *txBaseAddr;
+    volatile uint32_t *rxBaseAddr;
+
+    void clearMessage();
+    void printAIDR(bool tx = true, bool rx = true);
+
+    void txWrite(uint32_t offset, uint32_t value);
+    void rxWrite(uint32_t offset, uint32_t value);
+    uint32_t txRead(uint32_t offset);
+    uint32_t rxRead(uint32_t offset);
+
+    // Sender/tx
+    uint32_t getAccessReady();
+    uint32_t getAccessRequest();
+    uint32_t getInterruptStatus();
+    uint32_t getTxAIDR();
+    uint32_t getTxStatusForChan(uint8_t chan);
+    void enableAccessRequest();
+    void disableAccessRequest();
+    void setCombinedClearInterrupt(bool enable);
+    void setReadyNotReadyInterrupts(bool enable);
+
+    // Receiver/rx
+    uint32_t getRxAIDR();
+    uint32_t getRxStatusForChan(uint8_t chan);
+    void setCombinedRecvInterrupt(bool enable);
+    void enableClearChanInterrupt(uint8_t chan);
+    void disableClearChanInterrupt(uint8_t chan);
+};
+
+} // namespace Mailbox
+
+#endif /* #ifndef MHU_V2_HPP */
diff --git a/drivers/mhu_v2/src/mhu_v2.cpp b/drivers/mhu_v2/src/mhu_v2.cpp
new file mode 100644
index 0000000..1144a0f
--- /dev/null
+++ b/drivers/mhu_v2/src/mhu_v2.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ethosu_log.h"
+
+#include <mhu_v2.hpp>
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+namespace Mailbox {
+
+MHUv2::MHUv2(const uint32_t txBaseAddress, const uint32_t rxBaseAddress) :
+    txBaseAddr(reinterpret_cast<volatile uint32_t *>(txBaseAddress)),
+    rxBaseAddr(reinterpret_cast<volatile uint32_t *>(rxBaseAddress)) {
+
+    setCombinedRecvInterrupt(true);
+    enableAccessRequest(); // Set high throughout
+}
+
+void MHUv2::handleMessage() {
+    clearMessage();
+    notify();
+}
+
+MHUv2::~MHUv2() {
+    setCombinedRecvInterrupt(false);
+    disableAccessRequest();
+}
+
+bool MHUv2::verifyHardware() {
+    // Sanity check MHUv2.1 id's (tx/rx)
+    struct aidr_t *a;
+    uint32_t txAIDR = getTxAIDR();
+    uint32_t rxAIDR = getRxAIDR();
+
+    a = reinterpret_cast<struct aidr_t *>(&txAIDR);
+    if (a->ARCH_MAJOR_REV != 1 || a->ARCH_MINOR_REV != 1) {
+        return false;
+    }
+
+    a = reinterpret_cast<struct aidr_t *>(&rxAIDR);
+    if (a->ARCH_MAJOR_REV != 1 || a->ARCH_MINOR_REV != 1) {
+        return false;
+    }
+
+    return true;
+}
+
+uint32_t MHUv2::getTxStatusForChan(uint8_t chan) {
+    assert(chan >= 0);
+    assert(chan < 124);
+    return txRead((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_ST);
+}
+
+uint32_t MHUv2::getRxStatusForChan(uint8_t chan) {
+    assert(chan >= 0);
+    assert(chan < 124);
+    return rxRead((chan * MHUv2_RCV_CHAN_WINDOW_SIZE) + MHUv2_CH_ST);
+}
+
+uint32_t MHUv2::getInterruptStatus() {
+    return txRead(MHUv2_SND_INT_ST_OFFS);
+}
+
+uint32_t MHUv2::getAccessReady() {
+    return txRead(MHUv2_SND_ACCESS_READY_OFFS);
+}
+
+uint32_t MHUv2::getAccessRequest() {
+    return txRead(MHUv2_SND_ACCESS_REQUEST_OFFS);
+}
+
+uint32_t MHUv2::getTxAIDR() {
+    return txRead(MHUv2_SND_AIDR_OFFS);
+}
+
+uint32_t MHUv2::getRxAIDR() {
+    return rxRead(MHUv2_RCV_AIDR_OFFS);
+}
+
+void MHUv2::enableAccessRequest() {
+    txWrite(MHUv2_SND_ACCESS_REQUEST_OFFS, 1);
+}
+
+void MHUv2::disableAccessRequest() {
+    txWrite(MHUv2_SND_ACCESS_REQUEST_OFFS, 0);
+}
+
+/*
+ * MHUv2.1
+ * sender:   combined clear interrupt
+ */
+void MHUv2::setCombinedClearInterrupt(bool enable) {
+    uint32_t val = txRead(MHUv2_SND_INT_EN_OFFS);
+    if (enable) {
+        val |= (1 << 2);
+    } else {
+        val &= ~(1 << 2);
+    }
+    txWrite(MHUv2_SND_INT_EN_OFFS, val);
+}
+
+/*
+ * MHUv2.1
+ * receiver: combined recv interrupt
+ */
+void MHUv2::setCombinedRecvInterrupt(bool enable) {
+    uint32_t val = rxRead(MHUv2_RCV_INT_EN_OFFS);
+    if (enable) {
+        val |= (1 << 2);
+    } else {
+        val &= ~(1 << 2);
+    }
+    rxWrite(MHUv2_SND_INT_EN_OFFS, val);
+}
+
+// Enable/disable R2NR/NR2R interrupts
+void MHUv2::setReadyNotReadyInterrupts(bool enable) {
+    uint32_t val = txRead(MHUv2_SND_INT_EN_OFFS);
+    if (enable) {
+        val |= (1 << 0 | 1 << 1);
+    } else {
+        val &= ~(1 << 0 | 1 << 1);
+    }
+    txWrite(MHUv2_SND_INT_EN_OFFS, val);
+}
+
+void MHUv2::enableClearChanInterrupt(uint8_t chan) {
+    assert(chan >= 0);
+    assert(chan < 124);
+    txWrite((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_INT_EN, 1);
+}
+
+void MHUv2::disableClearChanInterrupt(uint8_t chan) {
+    assert(chan >= 0);
+    assert(chan < 124);
+    txWrite((chan * MHUv2_SND_CHAN_WINDOW_SIZE) + MHUv2_CH_INT_EN, 0);
+}
+
+/*
+ * Set channel status byte (with only minor error/state check(s))
+ * Doorbell only, chan 0
+ */
+bool MHUv2::sendMessage() {
+    // Check that the other end is ready to receive
+    if (!getAccessReady()) {
+        return false;
+    }
+    txWrite(MHUv2_CH_SET, 1);
+
+    return true;
+}
+
+void MHUv2::clearMessage() {
+    rxWrite(MHUv2_CH_CLR, 0xFFFFFFFF); // Doorbell uses only chan 0, but clear all 32bits to be safe
+}
+
+void MHUv2::txWrite(uint32_t offset, uint32_t value) {
+    write32(txBaseAddr, offset, value);
+}
+
+void MHUv2::rxWrite(uint32_t offset, uint32_t value) {
+    write32(rxBaseAddr, offset, value);
+}
+
+uint32_t MHUv2::txRead(uint32_t offset) {
+    return read32(txBaseAddr, offset);
+}
+
+uint32_t MHUv2::rxRead(uint32_t offset) {
+    return read32(rxBaseAddr, offset);
+}
+
+void MHUv2::printAIDR(bool tx, bool rx) {
+    struct aidr_t *a;
+    uint32_t aidr;
+
+    if (tx) {
+        aidr = getTxAIDR();
+        a    = reinterpret_cast<struct aidr_t *>(&aidr);
+        LOG_INFO("TX MHUv2 reports: Major rev: %d, Minor rev: %d", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV);
+    }
+    if (rx) {
+        aidr = getRxAIDR();
+        a    = reinterpret_cast<struct aidr_t *>(&aidr);
+        LOG_INFO("RX MHUv2 reports: Major rev: %d, Minor rev: %d", a->ARCH_MAJOR_REV, a->ARCH_MINOR_REV);
+    }
+}
+
+} // namespace Mailbox
diff --git a/drivers/mpu/CMakeLists.txt b/drivers/mpu/CMakeLists.txt
new file mode 100644
index 0000000..2b9797e
--- /dev/null
+++ b/drivers/mpu/CMakeLists.txt
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(mpu INTERFACE)
+
+target_sources(mpu INTERFACE
+    src/mpu.cpp)
+
+target_include_directories(mpu INTERFACE
+    include)
diff --git a/drivers/mpu/include/mpu.hpp b/drivers/mpu/include/mpu.hpp
new file mode 100644
index 0000000..dff73b6
--- /dev/null
+++ b/drivers/mpu/include/mpu.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#include <cstdint>
+
+/****************************************************************************
+ * Types and functions
+ ****************************************************************************/
+
+namespace EthosU {
+namespace Mpu {
+
+enum { WTRA_index, WBWARA_index };
+
+/**
+ * Dump the MPU tables.
+ */
+void dump();
+
+void loadAndEnableConfig(ARM_MPU_Region_t const *table, uint32_t cnt);
+
+}; // namespace Mpu
+}; // namespace EthosU
diff --git a/drivers/mpu/src/mpu.cpp b/drivers/mpu/src/mpu.cpp
new file mode 100644
index 0000000..338e3d1
--- /dev/null
+++ b/drivers/mpu/src/mpu.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#include <mpu.hpp>
+
+#include <cachel1_armv7.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+using namespace std;
+
+/****************************************************************************
+ * Functions
+ ****************************************************************************/
+
+namespace EthosU {
+namespace Mpu {
+
+void dump() {
+#ifdef ARM_MPU_ARMV8_H
+    uint32_t mpuRegions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+
+    printf("MPU available with %" PRIu32 " regions.\n", mpuRegions);
+
+    printf("    PRIVDEFENA : %lx\n", (MPU->CTRL & MPU_CTRL_PRIVDEFENA_Msk) >> MPU_CTRL_PRIVDEFENA_Pos);
+    printf("      HFNMIENA : %lx\n", (MPU->CTRL & MPU_CTRL_HFNMIENA_Msk) >> MPU_CTRL_HFNMIENA_Pos);
+    printf("        ENABLE : %lx\n", (MPU->CTRL & MPU_CTRL_ENABLE_Msk) >> MPU_CTRL_ENABLE_Pos);
+
+    for (size_t region = 0; region < mpuRegions; region++) {
+        MPU->RNR = region;
+        printf("-- Region %2d - RBAR:%08" PRIx32 " RLAR:%08" PRIx32 "\n", region, MPU->RBAR, MPU->RLAR);
+    }
+#endif
+}
+
+static void initializeAttributes() {
+#ifdef ARM_MPU_ARMV8_H
+    /* Initialize attributes corresponding to the enums defined in mpu.hpp */
+    const uint8_t WTRA =
+        ARM_MPU_ATTR_MEMORY_(1, 0, 1, 0); // Non-transient, Write-Through, Read-allocate, Not Write-allocate
+    const uint8_t WBWARA = ARM_MPU_ATTR_MEMORY_(1, 1, 1, 1); // Non-transient, Write-Back, Read-allocate, Write-allocate
+
+    ARM_MPU_SetMemAttr(WTRA_index, ARM_MPU_ATTR(WTRA, WTRA));
+    ARM_MPU_SetMemAttr(WBWARA_index, ARM_MPU_ATTR(WBWARA, WBWARA));
+#endif
+}
+
+void loadAndEnableConfig(ARM_MPU_Region_t const *table, uint32_t cnt) {
+#ifdef ARM_MPU_ARMV8_H
+    initializeAttributes();
+
+    ARM_MPU_Load(0, table, cnt);
+
+    // Enable MPU with default priv access to all other regions
+    ARM_MPU_Enable((1 << MPU_CTRL_PRIVDEFENA_Pos) & MPU_CTRL_PRIVDEFENA_Msk);
+#endif
+}
+
+}; // namespace Mpu
+}; // namespace EthosU
diff --git a/drivers/timing_adapter/CMakeLists.txt b/drivers/timing_adapter/CMakeLists.txt
new file mode 100644
index 0000000..f17eaeb
--- /dev/null
+++ b/drivers/timing_adapter/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(timing_adapter STATIC)
+target_include_directories(timing_adapter PUBLIC include)
+
+target_sources(timing_adapter PRIVATE src/timing_adapter.c)
+
diff --git a/drivers/timing_adapter/include/timing_adapter.h b/drivers/timing_adapter/include/timing_adapter.h
new file mode 100644
index 0000000..ef4f9b9
--- /dev/null
+++ b/drivers/timing_adapter/include/timing_adapter.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMING_ADAPTER_H_
+#define TIMING_ADAPTER_H_
+
+#include <stdint.h>
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+/** TIMING ADAPTER
+ *
+ * The timing adapter is an AXI-to-AXI bridge for providing well-defined memory timing
+ * to allow performance evaluation of an AXI master. The bridge works by delaying the
+ * responses from the memory according to run-time configurable parameters that can be
+ * set in the timing adapter. Parameters include read and write response latencies,
+ * no. of outstanding transactions, and a model of interferring traffic.
+ */
+
+struct timing_adapter {
+    uintptr_t base_addr;
+};
+
+/** LIMITATIONS FOR FVP:
+ *
+ *  - TA_MODE is hardcoded to 1 (one) at all times.
+ *  - Only TA_PERFCTRL_AWTRANS and TA_PERFCTRL_ARTRANS support is
+ *    implemented for the performance counter.
+ */
+
+struct timing_adapter_settings {
+    uint32_t maxr;       // 6-bit field. Max no. of pending reads. 0=infinite
+    uint32_t maxw;       // 6-bit field. Max no. of pending writes. 0=infinite
+    uint32_t maxrw;      // 6-bit field. Max no. of pending reads+writes. 0=infinite
+    uint32_t rlatency;   // 12-bit field. Minimum latency (clock cycles) from AVALID to RVALID.
+    uint32_t wlatency;   // 12-bit field. Minimum latency (clock cycles) from WVALID&WLAST to BVALID.
+    uint32_t pulse_on;   // No. of cycles addresses let through (0-65535).
+    uint32_t pulse_off;  // No. of cycles addresses blocked (0-65535).
+    uint32_t bwcap;      // 16-bit field. Max no. of 64-bit words transfered per pulse cycle 0=infinite
+    uint32_t perfctrl;   // 6-bit field selecting an event for event counter 0=default
+    uint32_t perfcnt;    // 32-bit event counter
+    uint32_t mode;       // Bit 0: 1=enable dynamic clocking to avoid underrun
+                         // Bit 1: 1=enable random AR reordering (0=default)
+                         // Bit 2: 1=enable random R reordering (0=default)
+                         // Bit 3: 1=enable random B reordering (0=default)
+                         // Bit 11-4: Frequency scale 0=full speed, 255=(1/256) speed
+    uint32_t maxpending; // (Read-only) Max supported value in MAXR and MAXW registers
+    uint32_t histbin;    // Controlls which histogram bin (0-15) that should be accessed by HISTCNT.
+    uint32_t histcnt;    // 32-bit field. Read/write the selected histogram bin.
+};
+
+enum timing_adapter_perfctrl_settings {
+    TA_PERFCTRL_OFF = 0,     // Disable performance counting
+    TA_PERFCTRL_CYCLES,      // Count all cycles (root clock)
+    TA_PERFCTRL_UNDERRUN_R,  // Unable to meet RLATENCY deadline
+    TA_PERFCTRL_UNDERRUN_B,  // Unable to meet WLATENCY deadline
+    TA_PERFCTRL_OVERFLOW_AR, // Internal read address FIFO full
+    TA_PERFCTRL_OVERFLOW_AW, // Internal write address FIFO full
+    TA_PERFCTRL_OVERFLOW_R,  // Internal read data FIFO full
+    TA_PERFCTRL_OVERFLOW_W,  // Internal write data FIFO full
+    TA_PERFCTRL_OVERFLOW_B,  // Internal write response FIFO full
+    TA_PERFCTRL_RREADY,      // RREADY wait state
+    TA_PERFCTRL_BREADY,      // BREADY wait state
+    TA_PERFCTRL_RTRANS,      // Handshake on R channel
+    TA_PERFCTRL_WTRANS,      // Handshake on W channel
+    TA_PERFCTRL_BTRANS,      // Handshake on B channel
+    TA_PERFCTRL_ARTRANS,     // Handshake on AR channel
+    TA_PERFCTRL_AWTRANS,     // Handshake on AW channel
+    TA_PERFCTRL_ARQTIME,     // Histogram of how much time spent with outstanding read transactions
+    TA_PERFCTRL_AWQTIME,     // Histogram of how much time spent with outstanding write transactions
+    TA_PERFCTRL_MCLK_ON,     // Count cycles when DUT clock is on
+    TA_PERFCTRL_MCLK_OFF,    // Count cycles when DUT clock is off
+    TA_PERFCTRL_ARLEN0 = 32, // Handshake on AR channel with ARLEN=0
+    TA_PERFCTRL_AWLEN0 = 48  // Handshake on AW channel with AWLEN=0
+};
+
+int ta_init(struct timing_adapter *ta, uintptr_t base_addr);
+void ta_uninit(struct timing_adapter *ta);
+
+void ta_set_all(struct timing_adapter *ta, struct timing_adapter_settings *in);
+void ta_set_maxr(struct timing_adapter *ta, uint32_t val);
+void ta_set_maxw(struct timing_adapter *ta, uint32_t val);
+void ta_set_maxrw(struct timing_adapter *ta, uint32_t val);
+void ta_set_rlatency(struct timing_adapter *ta, uint32_t val);
+void ta_set_wlatency(struct timing_adapter *ta, uint32_t val);
+void ta_set_pulse_on(struct timing_adapter *ta, uint32_t val);
+void ta_set_pulse_off(struct timing_adapter *ta, uint32_t val);
+void ta_set_bwcap(struct timing_adapter *ta, uint32_t val);
+void ta_set_perfctrl(struct timing_adapter *ta, uint32_t val);
+void ta_set_perfcnt(struct timing_adapter *ta, uint32_t val);
+void ta_set_mode(struct timing_adapter *ta, uint32_t val);
+void ta_set_histbin(struct timing_adapter *ta, uint32_t val);
+void ta_set_histcnt(struct timing_adapter *ta, uint32_t val);
+
+void ta_get_all(struct timing_adapter *ta, struct timing_adapter_settings *out);
+uint32_t ta_get_maxr(struct timing_adapter *ta);
+uint32_t ta_get_maxw(struct timing_adapter *ta);
+uint32_t ta_get_maxrw(struct timing_adapter *ta);
+uint32_t ta_get_rlatency(struct timing_adapter *ta);
+uint32_t ta_get_wlatency(struct timing_adapter *ta);
+uint32_t ta_get_pulse_on(struct timing_adapter *ta);
+uint32_t ta_get_pulse_off(struct timing_adapter *ta);
+uint32_t ta_get_bwcap(struct timing_adapter *ta);
+uint32_t ta_get_perfctrl(struct timing_adapter *ta);
+uint32_t ta_get_perfcnt(struct timing_adapter *ta);
+uint32_t ta_get_mode(struct timing_adapter *ta);
+uint32_t ta_get_maxpending(struct timing_adapter *ta);
+uint32_t ta_get_histbin(struct timing_adapter *ta);
+uint32_t ta_get_histcnt(struct timing_adapter *ta);
+uint32_t ta_get_version(struct timing_adapter *ta);
+
+#if defined __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/timing_adapter/src/timing_adapter.c b/drivers/timing_adapter/src/timing_adapter.c
new file mode 100644
index 0000000..65e4178
--- /dev/null
+++ b/drivers/timing_adapter/src/timing_adapter.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <timing_adapter.h>
+
+// Register offsets
+#define TA_MAXR       0x00
+#define TA_MAXW       0x04
+#define TA_MAXRW      0x08
+#define TA_RLATENCY   0x0C
+#define TA_WLATENCY   0x10
+#define TA_PULSE_ON   0x14
+#define TA_PULSE_OFF  0x18
+#define TA_BWCAP      0x1C
+#define TA_PERFCTRL   0x20
+#define TA_PERFCNT    0x24
+#define TA_MODE       0x28
+#define TA_MAXPENDING 0x2C
+#define TA_HISTBIN    0x30
+#define TA_HISTCNT    0x34
+#define TA_VERSION    0x38
+
+// Register masks
+#define TA_MAXR_MASK       0x0000003F
+#define TA_MAXW_MASK       0x0000003F
+#define TA_MAXRW_MASK      0x0000003F
+#define TA_RLATENCY_MASK   0x00000FFF
+#define TA_WLATENCY_MASK   0x00000FFF
+#define TA_PULSE_ON_MASK   0x0000FFFF
+#define TA_PULSE_OFF_MASK  0x0000FFFF
+#define TA_BWCAP_MASK      0x0000FFFF
+#define TA_PERFCTRL_MASK   0x0000003F
+#define TA_PERFCNT_MASK    0xFFFFFFFF
+#define TA_MODE_MASK       0x00000FFF
+#define TA_MAXPENDING_MASK 0xFFFFFFFF
+#define TA_HISTBIN_MASK    0x0000000F
+#define TA_HISTCNT_MASK    0xFFFFFFFF
+
+#define TA_VERSION_SUPPORTED 0x1117
+
+int ta_init(struct timing_adapter *ta, uintptr_t base_addr) {
+    ta->base_addr = base_addr;
+
+    if (ta_get_version(ta) != TA_VERSION_SUPPORTED) {
+        return -1;
+    }
+    return 0;
+}
+
+void ta_uninit(struct timing_adapter *ta) {
+    ta->base_addr = 0;
+}
+
+// -- Set API --------------------------------------
+void ta_set_all(struct timing_adapter *ta, struct timing_adapter_settings *in) {
+    ta_set_maxr(ta, in->maxr);
+    ta_set_maxw(ta, in->maxw);
+    ta_set_maxrw(ta, in->maxrw);
+    ta_set_rlatency(ta, in->rlatency);
+    ta_set_wlatency(ta, in->wlatency);
+    ta_set_pulse_on(ta, in->pulse_on);
+    ta_set_pulse_off(ta, in->pulse_off);
+    ta_set_bwcap(ta, in->bwcap);
+    ta_set_perfctrl(ta, in->perfctrl);
+    ta_set_perfcnt(ta, in->perfcnt);
+    ta_set_mode(ta, in->mode);
+    ta_set_histbin(ta, in->histbin);
+    ta_set_histcnt(ta, in->histcnt);
+}
+
+void ta_set_maxr(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_MAXR) = val & TA_MAXR_MASK;
+};
+
+void ta_set_maxw(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_MAXW) = val & TA_MAXW_MASK;
+};
+
+void ta_set_maxrw(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_MAXRW) = val & TA_MAXRW_MASK;
+};
+
+void ta_set_rlatency(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_RLATENCY) = val & TA_RLATENCY_MASK;
+};
+
+void ta_set_wlatency(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_WLATENCY) = val & TA_WLATENCY_MASK;
+};
+
+void ta_set_pulse_on(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_PULSE_ON) = val & TA_PULSE_ON_MASK;
+};
+
+void ta_set_pulse_off(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_PULSE_OFF) = val & TA_PULSE_OFF_MASK;
+};
+
+void ta_set_bwcap(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_BWCAP) = val & TA_BWCAP_MASK;
+};
+
+void ta_set_perfctrl(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_PERFCTRL) = val & TA_PERFCTRL_MASK;
+};
+
+void ta_set_perfcnt(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_PERFCNT) = val & TA_PERFCNT_MASK;
+};
+
+void ta_set_mode(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_MODE) = val & TA_MODE_MASK;
+};
+
+void ta_set_histbin(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_HISTBIN) = val & TA_HISTBIN_MASK;
+};
+
+void ta_set_histcnt(struct timing_adapter *ta, uint32_t val) {
+    *(volatile uint32_t *)(ta->base_addr + TA_HISTCNT) = val & TA_HISTCNT_MASK;
+};
+
+// -- Get API --------------------------------------
+void ta_get_all(struct timing_adapter *ta, struct timing_adapter_settings *out) {
+    out->maxr       = ta_get_maxr(ta);
+    out->maxw       = ta_get_maxw(ta);
+    out->maxrw      = ta_get_maxrw(ta);
+    out->rlatency   = ta_get_rlatency(ta);
+    out->wlatency   = ta_get_wlatency(ta);
+    out->pulse_on   = ta_get_pulse_on(ta);
+    out->pulse_off  = ta_get_pulse_off(ta);
+    out->bwcap      = ta_get_bwcap(ta);
+    out->perfctrl   = ta_get_perfctrl(ta);
+    out->perfcnt    = ta_get_perfcnt(ta);
+    out->mode       = ta_get_mode(ta);
+    out->maxpending = ta_get_maxpending(ta);
+    out->histbin    = ta_get_histbin(ta);
+    out->histcnt    = ta_get_histcnt(ta);
+}
+
+uint32_t ta_get_maxr(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_MAXR) & TA_MAXR_MASK;
+};
+
+uint32_t ta_get_maxw(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_MAXW) & TA_MAXW_MASK;
+};
+
+uint32_t ta_get_maxrw(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_MAXRW) & TA_MAXRW_MASK;
+};
+
+uint32_t ta_get_rlatency(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_RLATENCY) & TA_RLATENCY_MASK;
+};
+
+uint32_t ta_get_wlatency(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_WLATENCY) & TA_WLATENCY_MASK;
+};
+
+uint32_t ta_get_pulse_on(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_PULSE_ON) & TA_PULSE_ON_MASK;
+};
+
+uint32_t ta_get_pulse_off(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_PULSE_OFF) & TA_PULSE_OFF_MASK;
+};
+
+uint32_t ta_get_bwcap(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_BWCAP) & TA_BWCAP_MASK;
+};
+
+uint32_t ta_get_perfctrl(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_PERFCTRL) & TA_PERFCTRL_MASK;
+};
+
+uint32_t ta_get_perfcnt(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_PERFCNT) & TA_PERFCNT_MASK;
+};
+
+uint32_t ta_get_mode(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_MODE) & TA_MODE_MASK;
+};
+
+uint32_t ta_get_maxpending(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_MAXPENDING) & TA_MAXPENDING_MASK;
+};
+
+uint32_t ta_get_histbin(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_HISTBIN) & TA_HISTBIN_MASK;
+};
+
+uint32_t ta_get_histcnt(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_HISTCNT) & TA_HISTCNT_MASK;
+};
+
+uint32_t ta_get_version(struct timing_adapter *ta) {
+    return *(volatile uint32_t *)(ta->base_addr + TA_VERSION);
+};
diff --git a/drivers/uart/CMakeLists.txt b/drivers/uart/CMakeLists.txt
new file mode 100644
index 0000000..e21de24
--- /dev/null
+++ b/drivers/uart/CMakeLists.txt
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+add_library(ethosu_uart_common INTERFACE)
+
+target_include_directories(ethosu_uart_common INTERFACE
+                           include
+                           ${CMAKE_CURRENT_BINARY_DIR})
+
+# UART configuration (Can be overriden from user project, default value is for  target "Corestone-300")
+set(UART0_BASE        "0x49303000" CACHE STRING "UART base address")
+set(UART0_BAUDRATE    "115200"     CACHE STRING "UART baudrate")
+set(SYSTEM_CORE_CLOCK "25000000"   CACHE STRING "System core clock (Hz)")
+
+# Generate UART configuration file
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/uart_config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/uart_config.h")
+
+# Drivers
+add_library(ethosu_uart_cmsdk_apb STATIC src/uart_cmsdk_apb.c)
+target_link_libraries(ethosu_uart_cmsdk_apb PUBLIC ethosu_uart_common)
+
+add_library(ethosu_uart_pl011 STATIC src/uart_pl011.c)
+target_link_libraries(ethosu_uart_pl011 PUBLIC ethosu_uart_common)
+
+add_library(ethosu_uart_dummy STATIC src/uart_dummy.c)
+target_link_libraries(ethosu_uart_dummy PUBLIC ethosu_uart_common)
diff --git a/drivers/uart/include/uart_stdout.h b/drivers/uart/include/uart_stdout.h
new file mode 100644
index 0000000..a489b3f
--- /dev/null
+++ b/drivers/uart/include/uart_stdout.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UART_STDOUT_H_
+#define _UART_STDOUT_H_
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void UartStdOutInit(void);
+unsigned char UartPutc(unsigned char my_ch);
+unsigned char UartGetc(void);
+unsigned int GetLine(char *lp, unsigned int len);
+
+#if __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/uart/src/uart_cmsdk_apb.c b/drivers/uart/src/uart_cmsdk_apb.c
new file mode 100644
index 0000000..2c644bb
--- /dev/null
+++ b/drivers/uart/src/uart_cmsdk_apb.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Basic CMSDK APB UART driver */
+
+#include "uart_config.h"
+#include "uart_stdout.h"
+#include <stdint.h>
+#include <stdio.h>
+
+#define CNTLQ     0x11
+#define CNTLS     0x13
+#define DEL       0x7F
+#define BACKSPACE 0x08
+#define CR        0x0D
+#define LF        0x0A
+#define ESC       0x1B
+
+#define __IO volatile
+#define __I  volatile const
+#define __O  volatile
+
+typedef struct {
+    __IO uint32_t DATA;  /* Offset: 0x000 (R/W) Data Register    */
+    __IO uint32_t STATE; /* Offset: 0x004 (R/W) Status Register  */
+    __IO uint32_t CTRL;  /* Offset: 0x008 (R/W) Control Register */
+    union {
+        __I uint32_t INTSTATUS; /* Offset: 0x00C (R/ ) Interrupt Status Register */
+        __O uint32_t INTCLEAR;  /* Offset: 0x00C ( /W) Interrupt Clear Register  */
+    };
+    __IO uint32_t BAUDDIV; /* Offset: 0x010 (R/W) Baudrate Divider Register */
+} CMSDK_UART_TypeDef;
+
+#define CMSDK_UART0_BASE     UART0_BASE
+#define CMSDK_UART0          ((CMSDK_UART_TypeDef *)CMSDK_UART0_BASE)
+#define CMSDK_UART0_BAUDRATE UART0_BAUDRATE
+
+void UartStdOutInit(void) {
+    CMSDK_UART0->BAUDDIV = SYSTEM_CORE_CLOCK / CMSDK_UART0_BAUDRATE;
+
+    CMSDK_UART0->CTRL = ((1ul << 0) | /* TX enable */
+                         (1ul << 1)); /* RX enable */
+}
+
+// Output a character
+unsigned char UartPutc(unsigned char my_ch) {
+    while ((CMSDK_UART0->STATE & 1))
+        ; // Wait if Transmit Holding register is full
+
+    if (my_ch == '\n') {
+        CMSDK_UART0->DATA = '\r';
+        while ((CMSDK_UART0->STATE & 1))
+            ; // Wait if Transmit Holding register is full
+    }
+
+    CMSDK_UART0->DATA = my_ch; // write to transmit holding register
+
+    return (my_ch);
+}
+
+// Get a character
+unsigned char UartGetc(void) {
+    unsigned char my_ch;
+    // unsigned int  cnt;
+
+    while ((CMSDK_UART0->STATE & 2) == 0) // Wait if Receive Holding register is empty
+        ;
+
+    my_ch = CMSDK_UART0->DATA;
+
+    // Convert CR to LF
+    if (my_ch == '\r')
+        my_ch = '\n';
+
+    return (my_ch);
+}
+
+// Get line from terminal
+unsigned int GetLine(char *lp, unsigned int len) {
+    unsigned int cnt = 0;
+    char c;
+
+    do {
+        c = UartGetc();
+        switch (c) {
+        case CNTLQ: /* ignore Control S/Q             */
+        case CNTLS:
+            break;
+        case BACKSPACE:
+        case DEL:
+            if (cnt == 0) {
+                break;
+            }
+            cnt--;          /* decrement count                */
+            lp--;           /* and line pointer               */
+            UartPutc(0x08); /* echo backspace                 */
+            UartPutc(' ');
+            UartPutc(0x08);
+            fflush(stdout);
+            break;
+        case ESC:
+        case 0:
+            *lp = 0; /* ESC - stop editing line        */
+            return 0;
+        case CR: /* CR - done, stop editing line   */
+            *lp = c;
+            lp++;  /* increment line pointer         */
+            cnt++; /* and count                      */
+            c = LF;
+            /* fall through */
+        default:
+            UartPutc(*lp = c); /* echo and store character       */
+            fflush(stdout);
+            lp++;  /* increment line pointer         */
+            cnt++; /* and count                      */
+            break;
+        }
+    } while (cnt < len - 2 && c != LF); /* check limit and CR             */
+    *lp = 0;                            /* mark end of string             */
+    return 1;
+}
diff --git a/drivers/uart/src/uart_dummy.c b/drivers/uart/src/uart_dummy.c
new file mode 100644
index 0000000..66da44f
--- /dev/null
+++ b/drivers/uart/src/uart_dummy.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "uart_stdout.h"
+
+void UartStdOutInit(void) {}
+
+unsigned char UartPutc(unsigned char c) {
+    (void)c;
+    return 0;
+}
+
+unsigned char UartGetc(void) {
+    return 0;
+}
+
+unsigned int GetLine(char *lp, unsigned int len) {
+    (void)lp;
+    (void)len;
+    return 0;
+}
diff --git a/drivers/uart/src/uart_pl011.c b/drivers/uart/src/uart_pl011.c
new file mode 100644
index 0000000..d65269a
--- /dev/null
+++ b/drivers/uart/src/uart_pl011.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Basic PL011 UART driver */
+
+#include "uart_config.h"
+#include "uart_stdout.h"
+#include <stdint.h>
+#include <stdio.h>
+
+#define CNTLQ     0x11
+#define CNTLS     0x13
+#define DEL       0x7F
+#define BACKSPACE 0x08
+#define CR        0x0D
+#define LF        0x0A
+#define ESC       0x1B
+
+/*****************************************************************************/
+/*  UART Control Register Locations                                          */
+/*****************************************************************************/
+#define UART0_DR   *((volatile uint32_t *)UART0_BASE)
+#define UART0_RSR  *((volatile uint32_t *)(UART0_BASE + 0x04))
+#define UART0_ECR  *((volatile uint32_t *)(UART0_BASE + 0x04))
+#define UART0_LCRH *((volatile uint32_t *)(UART0_BASE + 0x2C))
+#define UART0_LCRM *((volatile uint32_t *)(UART0_BASE + 0x28))
+#define UART0_LCRL *((volatile uint32_t *)(UART0_BASE + 0x24))
+#define UART0_CR   *((volatile uint32_t *)(UART0_BASE + 0x30))
+#define UART0_FR   *((volatile uint32_t *)(UART0_BASE + 0x18))
+#define UART0_IIR  *((volatile uint32_t *)(UART0_BASE + 0x1C))
+#define UART0_ICR  *((volatile uint32_t *)(UART0_BASE + 0x44))
+
+/*****************************************************************************/
+/* Received Status Register - RSR                                            */
+/*****************************************************************************/
+#define RSR_OVERRUN_ERROR 0x08
+#define RSR_BREAK_ERROR   0x04
+#define RSR_PARITY_ERROR  0x02
+#define RSR_FRAMING_ERROR 0x01
+
+/*****************************************************************************/
+/* Line Control High Byte Register - LCRH                                    */
+/*****************************************************************************/
+#define LCRH_WORD_LENGTH_8 0x60
+#define LCRH_WORD_LENGTH_7 0x40
+#define LCRH_WORD_LENGTH_6 0x20
+#define LCRH_WORD_LENGTH_5 0x00
+#define LCRH_FIFO_ENABLED  0x10
+#define LCRH_2_STOP_BITS   0x08
+#define LCRH_EVEN_PARITY   0x04
+#define LCRH_PARITY_ENABLE 0x02
+#define LCRH_SEND_BREAK    0x01
+
+/*****************************************************************************/
+/* Line Control Medium Byte Register - LCRM                                  */
+/* This register specifies the high byte of the Baud rate divisor            */
+/*****************************************************************************/
+#define LCRM_BAUD_460800 0x00
+#define LCRM_BAUD_230400 0x00
+#define LCRM_BAUD_115200 0x00
+#define LCRM_BAUD_76800  0x00
+#define LCRM_BAUD_57600  0x00
+#define LCRM_BAUD_38400  0x00
+#define LCRM_BAUD_19200  0x00
+#define LCRM_BAUD_14400  0x00
+#define LCRM_BAUD_9600   0x00
+#define LCRM_BAUD_2400   0x01
+#define LCRM_BAUD_1200   0x02
+
+/*****************************************************************************/
+/* Line Control Low Byte Register - LCRL                                     */
+/* This register specifies the low byte of the Baud rate divisor             */
+/*****************************************************************************/
+#define LCRL_BAUD_460800 0x01
+#define LCRL_BAUD_230400 0x03
+#define LCRL_BAUD_115200 0x07
+#define LCRL_BAUD_76800  0x0B
+#define LCRL_BAUD_57600  0x0F
+#define LCRL_BAUD_38400  0xC
+#define LCRL_BAUD_19200  0x2F
+#define LCRL_BAUD_14400  0x3F
+#define LCRL_BAUD_9600   0x5F
+#define LCRL_BAUD_2400   0x7F
+#define LCRL_BAUD_1200   0xFF
+
+/*****************************************************************************/
+/* Control Register - CR                                                     */
+/*****************************************************************************/
+#define CR_LOOP_BACK_EN   0x80
+#define CR_TIMEOUT_INT_EN 0x40
+#define CR_TX_INT_ENABLE  0x100
+#define CR_RX_INT_ENABLE  0x200
+#define CR_MODSTAT_INT_EN 0x08
+#define CR_UART_ENABLE    0x01
+
+/*****************************************************************************/
+/* Flag Register - FR                                                        */
+/*****************************************************************************/
+#define FR_TX_FIFO_EMPTY  0x80
+#define FR_RX_FIFO_FULL   0x40
+#define FR_TX_FIFO_FULL   0x20
+#define FR_RX_FIFO_EMPTY  0x10
+#define FR_BUSY           0x08
+#define FR_CARRIER_DETECT 0x04
+#define FR_SET_READY      0x02
+#define FR_CLEAR_TO_SEND  0x01
+
+/*****************************************************************************/
+/* Interrupt Identification Register - IIR                                   */
+/*****************************************************************************/
+#define IIR_RX_TIME_OUT 0x08
+#define IIR_TX          0x04
+#define IIR_RX          0x02
+#define IIR_MODEM       0x01
+
+void UartStdOutInit(void) {
+    // Disable the serial port while setting the baud rate and word length
+    UART0_CR = 0;
+
+    // Clear the receive status register
+    UART0_ECR = 0;
+
+    // Set the correct baud rate and word length
+    UART0_LCRL = LCRL_BAUD_115200;
+    UART0_LCRM = LCRM_BAUD_115200;
+    UART0_LCRH = LCRH_WORD_LENGTH_8;
+
+    // Explicitly disable FIFO's for char mode
+    UART0_LCRH &= ~LCRH_FIFO_ENABLED;
+
+    // Enable UART0 (and RX/TX) without interrupts
+    UART0_CR = CR_UART_ENABLE | CR_TX_INT_ENABLE | CR_RX_INT_ENABLE;
+}
+
+unsigned char UartPutc(unsigned char ch) {
+    if (ch == '\n') {
+        (void)UartPutc('\r');
+    }
+    while (UART0_FR & FR_TX_FIFO_FULL)
+        ;
+    UART0_DR = ch;
+
+    return ch;
+}
+
+unsigned char UartGetc(void) {
+    unsigned char c;
+    while (UART0_FR & FR_RX_FIFO_EMPTY)
+        ;
+    c = UART0_DR;
+    if (c == '\r') {
+        c = '\n';
+    }
+
+    return c;
+}
+
+// Get line from terminal
+unsigned int GetLine(char *lp, unsigned int len) {
+    unsigned int cnt = 0;
+    char c;
+
+    do {
+        c = UartGetc();
+        switch (c) {
+        case CNTLQ: /* ignore Control S/Q             */
+        case CNTLS:
+            break;
+        case BACKSPACE:
+        case DEL:
+            if (cnt == 0) {
+                break;
+            }
+            cnt--;          /* decrement count                */
+            lp--;           /* and line pointer               */
+            UartPutc(0x08); /* echo backspace                 */
+            UartPutc(' ');
+            UartPutc(0x08);
+            fflush(stdout);
+            break;
+        case ESC:
+        case 0:
+            *lp = 0; /* ESC - stop editing line        */
+            return 0;
+        case CR: /* CR - done, stop editing line   */
+            *lp = c;
+            lp++;  /* increment line pointer         */
+            cnt++; /* and count                      */
+            c = LF;
+            UartPutc(*lp = c); /* echo and store character       */
+            fflush(stdout);
+            lp++;  /* increment line pointer         */
+            cnt++; /* and count                      */
+            break;
+        default:
+            UartPutc(*lp = c); /* echo and store character       */
+            fflush(stdout);
+            lp++;  /* increment line pointer         */
+            cnt++; /* and count                      */
+            break;
+        }
+    } while (cnt < len - 2 && c != LF); /* check limit and CR             */
+    *lp = 0;                            /* mark end of string             */
+    return 1;
+}
diff --git a/drivers/uart/uart_config.h.in b/drivers/uart/uart_config.h.in
new file mode 100644
index 0000000..c016c3f
--- /dev/null
+++ b/drivers/uart/uart_config.h.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define UART0_BASE          (@UART0_BASE@)
+#define UART0_BAUDRATE      (@UART0_BAUDRATE@)
+#define SYSTEM_CORE_CLOCK   (@SYSTEM_CORE_CLOCK@)