summaryrefslogtreecommitdiff
path: root/core/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'core/drivers')
-rw-r--r--core/drivers/cdns_uart.c100
-rw-r--r--core/drivers/dra7_rng.c204
-rw-r--r--core/drivers/frame_buffer.c59
-rw-r--r--core/drivers/gic.c457
-rw-r--r--core/drivers/hi16xx_rng.c113
-rw-r--r--core/drivers/hi16xx_uart.c131
-rw-r--r--core/drivers/imx_uart.c112
-rw-r--r--core/drivers/ns16550.c57
-rw-r--r--core/drivers/pl011.c147
-rw-r--r--core/drivers/pl022_spi.c530
-rw-r--r--core/drivers/pl050.c102
-rw-r--r--core/drivers/pl061_gpio.c243
-rw-r--r--core/drivers/pl111.c126
-rw-r--r--core/drivers/ps2mouse.c160
-rw-r--r--core/drivers/scif.c65
-rw-r--r--core/drivers/serial8250_uart.c93
-rw-r--r--core/drivers/sprd_uart.c78
-rw-r--r--core/drivers/sub.mk19
-rw-r--r--core/drivers/sunxi_uart.c97
-rw-r--r--core/drivers/tzc400.c417
20 files changed, 3310 insertions, 0 deletions
diff --git a/core/drivers/cdns_uart.c b/core/drivers/cdns_uart.c
new file mode 100644
index 0000000..3b4e4b9
--- /dev/null
+++ b/core/drivers/cdns_uart.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Xilinx Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <compiler.h>
+#include <drivers/cdns_uart.h>
+#include <io.h>
+#include <util.h>
+
+#define CDNS_UART_CONTROL 0
+#define CDNS_UART_MODE 4
+#define CDNS_UART_IEN 8
+#define CDNS_UART_IRQ_STATUS 0x14
+#define CDNS_UART_CHANNEL_STATUS 0x2c
+#define CDNS_UART_FIFO 0x30
+
+#define CDNS_UART_CONTROL_RXRES BIT(0)
+#define CDNS_UART_CONTROL_TXRES BIT(1)
+#define CDNS_UART_CONTROL_RXEN BIT(2)
+#define CDNS_UART_CONTROL_TXEN BIT(4)
+
+#define CDNS_UART_MODE_8BIT (0 << 1)
+#define CDNS_UART_MODE_PARITY_NONE (0x4 << 3)
+#define CDNS_UART_MODE_1STP (0 << 6)
+
+#define CDNS_UART_CHANNEL_STATUS_TFUL BIT(4)
+#define CDNS_UART_CHANNEL_STATUS_TEMPTY BIT(3)
+#define CDNS_UART_CHANNEL_STATUS_REMPTY BIT(1)
+
+#define CDNS_UART_IRQ_RXTRIG BIT(0)
+#define CDNS_UART_IRQ_RXTOUT BIT(8)
+
+void cdns_uart_flush(vaddr_t base)
+{
+ while (!(read32(base + CDNS_UART_CHANNEL_STATUS) &
+ CDNS_UART_CHANNEL_STATUS_TEMPTY))
+ ;
+}
+
+/*
+ * we rely on the bootloader having set up the HW correctly, we just enable
+ * transmitter/receiver here, just in case.
+ */
+void cdns_uart_init(vaddr_t base, uint32_t uart_clk, uint32_t baud_rate)
+{
+ if (!base || !uart_clk || !baud_rate)
+ return;
+
+ /* Enable UART and RX/TX */
+ write32(CDNS_UART_CONTROL_RXEN | CDNS_UART_CONTROL_TXEN,
+ base + CDNS_UART_CONTROL);
+
+ cdns_uart_flush(base);
+}
+
+void cdns_uart_putc(int ch, vaddr_t base)
+{
+ /* Wait until there is space in the FIFO */
+ while (read32(base + CDNS_UART_CHANNEL_STATUS) &
+ CDNS_UART_CHANNEL_STATUS_TFUL)
+ ;
+
+ /* Send the character */
+ write32(ch, base + CDNS_UART_FIFO);
+}
+
+bool cdns_uart_have_rx_data(vaddr_t base)
+{
+ return !(read32(base + CDNS_UART_CHANNEL_STATUS) &
+ CDNS_UART_CHANNEL_STATUS_REMPTY);
+}
+
+int cdns_uart_getchar(vaddr_t base)
+{
+ while (!cdns_uart_have_rx_data(base))
+ ;
+ return read32(base + CDNS_UART_FIFO) & 0xff;
+}
diff --git a/core/drivers/dra7_rng.c b/core/drivers/dra7_rng.c
new file mode 100644
index 0000000..f9238f8
--- /dev/null
+++ b/core/drivers/dra7_rng.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <initcall.h>
+#include <io.h>
+#include <keep.h>
+#include <kernel/interrupt.h>
+#include <kernel/misc.h>
+#include <kernel/spinlock.h>
+#include <mm/core_memprot.h>
+#include <mm/core_mmu.h>
+#include <platform_config.h>
+#include <rng_support.h>
+
+#define RNG_OUTPUT_L 0x0000
+#define RNG_OUTPUT_H 0x0004
+#define RNG_STATUS 0x0008
+# define RNG_READY BIT(0)
+# define SHUTDOWN_OFLO BIT(1)
+#define RNG_INTMASK 0x000C
+#define RNG_INTACK 0x0010
+#define RNG_CONTROL 0x0014
+# define ENABLE_TRNG BIT(10)
+#define RNG_CONFIG 0x0018
+#define RNG_ALARMCNT 0x001C
+#define RNG_FROENABLE 0x0020
+#define RNG_FRODETUNE 0x0024
+#define RNG_ALARMMASK 0x0028
+#define RNG_ALARMSTOP 0x002C
+#define RNG_LFSR_L 0x0030
+#define RNG_LFSR_M 0x0034
+#define RNG_LFSR_H 0x0038
+#define RNG_COUNT 0x003C
+#define RNG_OPTIONS 0x0078
+#define RNG_EIP_REV 0x007C
+#define RNG_MMR_STATUS_EN 0x1FD8
+#define RNG_REV 0x1FE0
+#define RNG_SYS_CONFIG_REG 0x1FE4
+# define RNG_AUTOIDLE BIT(0)
+#define RNG_MMR_STATUS_SET 0x1FEC
+#define RNG_SOFT_RESET_REG 0x1FF0
+# define RNG_SOFT_RESET BIT(0)
+#define RNG_IRQ_EOI_REG 0x1FF4
+#define RNG_IRQSTATUS 0x1FF8
+
+#define RNG_CONTROL_STARTUP_CYCLES_SHIFT 16
+#define RNG_CONTROL_STARTUP_CYCLES_MASK GENMASK_32(31, 16)
+
+#define RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT 16
+#define RNG_CONFIG_MAX_REFIL_CYCLES_MASK GENMASK_32(31, 16)
+#define RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT 0
+#define RNG_CONFIG_MIN_REFIL_CYCLES_MASK GENMASK_32(7, 0)
+
+#define RNG_ALARMCNT_ALARM_TH_SHIFT 0
+#define RNG_ALARMCNT_ALARM_TH_MASK GENMASK_32(7, 0)
+#define RNG_ALARMCNT_SHUTDOWN_TH_SHIFT 16
+#define RNG_ALARMCNT_SHUTDOWN_TH_MASK GENMASK_32(20, 16)
+
+#define RNG_CONTROL_STARTUP_CYCLES 0xff
+#define RNG_CONFIG_MIN_REFIL_CYCLES 0x21
+#define RNG_CONFIG_MAX_REFIL_CYCLES 0x22
+#define RNG_ALARM_THRESHOLD 0xff
+#define RNG_SHUTDOWN_THRESHOLD 0x4
+
+#define RNG_FRO_MASK GENMASK_32(23, 0)
+
+#define RNG_REG_SIZE 0x2000
+
+register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
+
+static unsigned int rng_lock = SPINLOCK_UNLOCK;
+
+uint8_t hw_get_random_byte(void)
+{
+ static int pos;
+ static union {
+ uint32_t val[2];
+ uint8_t byte[8];
+ } random;
+ vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
+ uint8_t ret;
+
+ uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_ALL);
+ cpu_spin_lock(&rng_lock);
+
+ if (!pos) {
+ /* Is the result ready (available)? */
+ while (!(read32(rng + RNG_STATUS) & RNG_READY)) {
+ /* Is the shutdown threshold reached? */
+ if (read32(rng + RNG_STATUS) & SHUTDOWN_OFLO) {
+ uint32_t alarm = read32(rng + RNG_ALARMSTOP);
+ uint32_t tuning = read32(rng + RNG_FRODETUNE);
+ /* Clear the alarm events */
+ write32(0x0, rng + RNG_ALARMMASK);
+ write32(0x0, rng + RNG_ALARMSTOP);
+ /* De-tune offending FROs */
+ write32(tuning ^ alarm, rng + RNG_FRODETUNE);
+ /* Re-enable the shut down FROs */
+ write32(RNG_FRO_MASK, rng + RNG_FROENABLE);
+ /* Clear the shutdown overflow event */
+ write32(SHUTDOWN_OFLO, rng + RNG_INTACK);
+
+ DMSG("Fixed FRO shutdown\n");
+ }
+ }
+ /* Read random value */
+ random.val[0] = read32(rng + RNG_OUTPUT_L);
+ random.val[1] = read32(rng + RNG_OUTPUT_H);
+ /* Acknowledge read complete */
+ write32(RNG_READY, rng + RNG_INTACK);
+ }
+
+ ret = random.byte[pos];
+
+ pos = (pos + 1) % 8;
+
+ cpu_spin_unlock(&rng_lock);
+ thread_set_exceptions(exceptions);
+
+ return ret;
+}
+
+static TEE_Result dra7_rng_init(void)
+{
+ vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
+ uint32_t val;
+
+ /* Execute a software reset */
+ write32(RNG_SOFT_RESET, rng + RNG_SOFT_RESET_REG);
+
+ /* Wait for the software reset completion by polling */
+ while (read32(rng + RNG_SOFT_RESET_REG) & RNG_SOFT_RESET)
+ ;
+
+ /* Switch to low-power operating mode */
+ write32(RNG_AUTOIDLE, rng + RNG_SYS_CONFIG_REG);
+
+ /*
+ * Select the number of clock input cycles to the
+ * FROs between two samples
+ */
+ val = 0;
+
+ /* Ensure initial latency */
+ val |= RNG_CONFIG_MIN_REFIL_CYCLES <<
+ RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT;
+ val |= RNG_CONFIG_MAX_REFIL_CYCLES <<
+ RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT;
+ write32(val, rng + RNG_CONFIG);
+
+ /* Configure the desired FROs */
+ write32(0x0, rng + RNG_FRODETUNE);
+
+ /* Enable all FROs */
+ write32(0xffffff, rng + RNG_FROENABLE);
+
+ /*
+ * Select the maximum number of samples after
+ * which if a repeating pattern is still detected, an
+ * alarm event is generated
+ */
+ val = RNG_ALARM_THRESHOLD << RNG_ALARMCNT_ALARM_TH_SHIFT;
+
+ /*
+ * Set the shutdown threshold to the number of FROs
+ * allowed to be shut downed
+ */
+ val |= RNG_SHUTDOWN_THRESHOLD << RNG_ALARMCNT_SHUTDOWN_TH_SHIFT;
+ write32(val, rng + RNG_ALARMCNT);
+
+ /* Enable the RNG module */
+ val = RNG_CONTROL_STARTUP_CYCLES << RNG_CONTROL_STARTUP_CYCLES_SHIFT;
+ val |= ENABLE_TRNG;
+ write32(val, rng + RNG_CONTROL);
+
+ IMSG("DRA7x TRNG initialized");
+
+ return TEE_SUCCESS;
+}
+driver_init(dra7_rng_init);
diff --git a/core/drivers/frame_buffer.c b/core/drivers/frame_buffer.c
new file mode 100644
index 0000000..8ef9a4e
--- /dev/null
+++ b/core/drivers/frame_buffer.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <compiler.h>
+#include <drivers/frame_buffer.h>
+
+size_t frame_buffer_get_image_size(struct frame_buffer *fb __unused,
+ size_t width, size_t height)
+{
+ return width * height * sizeof(uint32_t);
+}
+
+void frame_buffer_clear(struct frame_buffer *fb, uint32_t color)
+{
+ size_t n;
+ uint32_t *base = fb->base;
+
+ for (n = 0; n < fb->width * fb->height; n++)
+ base[n] = color;
+}
+
+void frame_buffer_set_image(struct frame_buffer *fb, size_t xpos, size_t ypos,
+ size_t width, size_t height, const void *image)
+{
+ size_t x;
+ size_t y;
+ uint32_t *base = fb->base;
+ const uint32_t *img = image;
+
+ for (y = 0; y < height && (y + ypos) < fb->height; y++)
+ for (x = 0; x < width && (x + xpos) < fb->width; x++)
+ base[x + xpos + (y + ypos) * fb->width] =
+ img[x + y * width];
+}
+
diff --git a/core/drivers/gic.c b/core/drivers/gic.c
new file mode 100644
index 0000000..93979a0
--- /dev/null
+++ b/core/drivers/gic.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <drivers/gic.h>
+#include <kernel/interrupt.h>
+#include <kernel/panic.h>
+#include <util.h>
+#include <io.h>
+#include <trace.h>
+
+/* Offsets from gic.gicc_base */
+#define GICC_CTLR (0x000)
+#define GICC_PMR (0x004)
+#define GICC_IAR (0x00C)
+#define GICC_EOIR (0x010)
+
+#define GICC_CTLR_ENABLEGRP0 (1 << 0)
+#define GICC_CTLR_ENABLEGRP1 (1 << 1)
+#define GICC_CTLR_FIQEN (1 << 3)
+
+/* Offsets from gic.gicd_base */
+#define GICD_CTLR (0x000)
+#define GICD_TYPER (0x004)
+#define GICD_IGROUPR(n) (0x080 + (n) * 4)
+#define GICD_ISENABLER(n) (0x100 + (n) * 4)
+#define GICD_ICENABLER(n) (0x180 + (n) * 4)
+#define GICD_ISPENDR(n) (0x200 + (n) * 4)
+#define GICD_ICPENDR(n) (0x280 + (n) * 4)
+#define GICD_IPRIORITYR(n) (0x400 + (n) * 4)
+#define GICD_ITARGETSR(n) (0x800 + (n) * 4)
+#define GICD_SGIR (0xF00)
+
+#define GICD_CTLR_ENABLEGRP0 (1 << 0)
+#define GICD_CTLR_ENABLEGRP1 (1 << 1)
+
+/* Number of Private Peripheral Interrupt */
+#define NUM_PPI 32
+
+/* Number of Software Generated Interrupt */
+#define NUM_SGI 16
+
+/* Number of Non-secure Software Generated Interrupt */
+#define NUM_NS_SGI 8
+
+/* Number of interrupts in one register */
+#define NUM_INTS_PER_REG 32
+
+/* Number of targets in one register */
+#define NUM_TARGETS_PER_REG 4
+
+/* Accessors to access ITARGETSRn */
+#define ITARGETSR_FIELD_BITS 8
+#define ITARGETSR_FIELD_MASK 0xff
+
+/* Maximum number of interrups a GIC can support */
+#define GIC_MAX_INTS 1020
+
+#define GIC_SPURIOUS_ID 1023
+
+#define GICC_IAR_IT_ID_MASK 0x3ff
+#define GICC_IAR_CPU_ID_MASK 0x7
+#define GICC_IAR_CPU_ID_SHIFT 10
+
+static void gic_op_add(struct itr_chip *chip, size_t it, uint32_t flags);
+static void gic_op_enable(struct itr_chip *chip, size_t it);
+static void gic_op_disable(struct itr_chip *chip, size_t it);
+static void gic_op_raise_pi(struct itr_chip *chip, size_t it);
+static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
+ uint8_t cpu_mask);
+static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
+ uint8_t cpu_mask);
+
+static const struct itr_ops gic_ops = {
+ .add = gic_op_add,
+ .enable = gic_op_enable,
+ .disable = gic_op_disable,
+ .raise_pi = gic_op_raise_pi,
+ .raise_sgi = gic_op_raise_sgi,
+ .set_affinity = gic_op_set_affinity,
+};
+
+static size_t probe_max_it(vaddr_t gicc_base, vaddr_t gicd_base)
+{
+ int i;
+ uint32_t old_ctlr;
+ size_t ret = 0;
+ const size_t max_regs = ((GIC_MAX_INTS + NUM_INTS_PER_REG - 1) /
+ NUM_INTS_PER_REG) - 1;
+
+ /*
+ * Probe which interrupt number is the largest.
+ */
+ old_ctlr = read32(gicc_base + GICC_CTLR);
+ write32(0, gicc_base + GICC_CTLR);
+ for (i = max_regs; i >= 0; i--) {
+ uint32_t old_reg;
+ uint32_t reg;
+ int b;
+
+ old_reg = read32(gicd_base + GICD_ISENABLER(i));
+ write32(0xffffffff, gicd_base + GICD_ISENABLER(i));
+ reg = read32(gicd_base + GICD_ISENABLER(i));
+ write32(old_reg, gicd_base + GICD_ICENABLER(i));
+ for (b = NUM_INTS_PER_REG - 1; b >= 0; b--) {
+ if (BIT32(b) & reg) {
+ ret = i * NUM_INTS_PER_REG + b;
+ goto out;
+ }
+ }
+ }
+out:
+ write32(old_ctlr, gicc_base + GICC_CTLR);
+ return ret;
+}
+
+void gic_cpu_init(struct gic_data *gd)
+{
+ assert(gd->gicd_base && gd->gicc_base);
+
+ /* per-CPU interrupts config:
+ * ID0-ID7(SGI) for Non-secure interrupts
+ * ID8-ID15(SGI) for Secure interrupts.
+ * All PPI config as Non-secure interrupts.
+ */
+ write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(0));
+
+ /* Set the priority mask to permit Non-secure interrupts, and to
+ * allow the Non-secure world to adjust the priority mask itself
+ */
+ write32(0x80, gd->gicc_base + GICC_PMR);
+
+ /* Enable GIC */
+ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
+ gd->gicc_base + GICC_CTLR);
+}
+
+void gic_init(struct gic_data *gd, vaddr_t gicc_base, vaddr_t gicd_base)
+{
+ size_t n;
+
+ gic_init_base_addr(gd, gicc_base, gicd_base);
+
+ for (n = 0; n <= gd->max_it / NUM_INTS_PER_REG; n++) {
+ /* Disable interrupts */
+ write32(0xffffffff, gd->gicd_base + GICD_ICENABLER(n));
+
+ /* Make interrupts non-pending */
+ write32(0xffffffff, gd->gicd_base + GICD_ICPENDR(n));
+
+ /* Mark interrupts non-secure */
+ if (n == 0) {
+ /* per-CPU inerrupts config:
+ * ID0-ID7(SGI) for Non-secure interrupts
+ * ID8-ID15(SGI) for Secure interrupts.
+ * All PPI config as Non-secure interrupts.
+ */
+ write32(0xffff00ff, gd->gicd_base + GICD_IGROUPR(n));
+ } else {
+ write32(0xffffffff, gd->gicd_base + GICD_IGROUPR(n));
+ }
+ }
+
+ /* Set the priority mask to permit Non-secure interrupts, and to
+ * allow the Non-secure world to adjust the priority mask itself
+ */
+ write32(0x80, gd->gicc_base + GICC_PMR);
+
+ /* Enable GIC */
+ write32(GICC_CTLR_ENABLEGRP0 | GICC_CTLR_ENABLEGRP1 | GICC_CTLR_FIQEN,
+ gd->gicc_base + GICC_CTLR);
+ write32(GICD_CTLR_ENABLEGRP0 | GICD_CTLR_ENABLEGRP1,
+ gd->gicd_base + GICD_CTLR);
+}
+
+void gic_init_base_addr(struct gic_data *gd, vaddr_t gicc_base,
+ vaddr_t gicd_base)
+{
+ gd->gicc_base = gicc_base;
+ gd->gicd_base = gicd_base;
+ gd->max_it = probe_max_it(gicc_base, gicd_base);
+ gd->chip.ops = &gic_ops;
+}
+
+static void gic_it_add(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
+
+ /* Disable the interrupt */
+ write32(mask, gd->gicd_base + GICD_ICENABLER(idx));
+ /* Make it non-pending */
+ write32(mask, gd->gicd_base + GICD_ICPENDR(idx));
+ /* Assign it to group0 */
+ write32(read32(gd->gicd_base + GICD_IGROUPR(idx)) & ~mask,
+ gd->gicd_base + GICD_IGROUPR(idx));
+}
+
+static void gic_it_set_cpu_mask(struct gic_data *gd, size_t it,
+ uint8_t cpu_mask)
+{
+ size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
+ uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
+ uint32_t target, target_shift;
+
+ /* Assigned to group0 */
+ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
+
+ /* Route it to selected CPUs */
+ target = read32(gd->gicd_base +
+ GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
+ target_shift = (it % NUM_TARGETS_PER_REG) * ITARGETSR_FIELD_BITS;
+ target &= ~(ITARGETSR_FIELD_MASK << target_shift);
+ target |= cpu_mask << target_shift;
+ DMSG("cpu_mask: writing 0x%x to 0x%" PRIxVA,
+ target, gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
+ write32(target,
+ gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG));
+ DMSG("cpu_mask: 0x%x\n",
+ read32(gd->gicd_base + GICD_ITARGETSR(it / NUM_TARGETS_PER_REG)));
+}
+
+static void gic_it_set_prio(struct gic_data *gd, size_t it, uint8_t prio)
+{
+ size_t idx __maybe_unused = it / NUM_INTS_PER_REG;
+ uint32_t mask __maybe_unused = 1 << (it % NUM_INTS_PER_REG);
+
+ /* Assigned to group0 */
+ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
+
+ /* Set prio it to selected CPUs */
+ DMSG("prio: writing 0x%x to 0x%" PRIxVA,
+ prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
+ write8(prio, gd->gicd_base + GICD_IPRIORITYR(0) + it);
+}
+
+static void gic_it_enable(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
+
+ /* Assigned to group0 */
+ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
+ if (it >= NUM_SGI) {
+ /*
+ * Not enabled yet, except Software Generated Interrupt
+ * which is implementation defined
+ */
+ assert(!(read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask));
+ }
+
+ /* Enable the interrupt */
+ write32(mask, gd->gicd_base + GICD_ISENABLER(idx));
+}
+
+static void gic_it_disable(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
+
+ /* Assigned to group0 */
+ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
+
+ /* Disable the interrupt */
+ write32(mask, gd->gicd_base + GICD_ICENABLER(idx));
+}
+
+static void gic_it_set_pending(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = BIT32(it % NUM_INTS_PER_REG);
+
+ /* Should be Peripheral Interrupt */
+ assert(it >= NUM_SGI);
+ /* Assigned to group0 */
+ assert(!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask));
+
+ /* Raise the interrupt */
+ write32(mask, gd->gicd_base + GICD_ISPENDR(idx));
+}
+
+static void gic_it_raise_sgi(struct gic_data *gd, size_t it,
+ uint8_t cpu_mask, uint8_t group)
+{
+ uint32_t mask_id = it & 0xf;
+ uint32_t mask_group = group & 0x1;
+ uint32_t mask_cpu = cpu_mask & 0xff;
+ uint32_t mask = (mask_id | SHIFT_U32(mask_group, 15) |
+ SHIFT_U32(mask_cpu, 16));
+
+ /* Should be Software Generated Interrupt */
+ assert(it < NUM_SGI);
+
+ /* Raise the interrupt */
+ write32(mask, gd->gicd_base + GICD_SGIR);
+}
+
+static uint32_t gic_read_iar(struct gic_data *gd)
+{
+ return read32(gd->gicc_base + GICC_IAR);
+}
+
+static void gic_write_eoir(struct gic_data *gd, uint32_t eoir)
+{
+ write32(eoir, gd->gicc_base + GICC_EOIR);
+}
+
+static bool gic_it_is_enabled(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
+ return !!(read32(gd->gicd_base + GICD_ISENABLER(idx)) & mask);
+}
+
+static bool __maybe_unused gic_it_get_group(struct gic_data *gd, size_t it)
+{
+ size_t idx = it / NUM_INTS_PER_REG;
+ uint32_t mask = 1 << (it % NUM_INTS_PER_REG);
+ return !!(read32(gd->gicd_base + GICD_IGROUPR(idx)) & mask);
+}
+
+static uint32_t __maybe_unused gic_it_get_target(struct gic_data *gd, size_t it)
+{
+ size_t reg_idx = it / NUM_TARGETS_PER_REG;
+ uint32_t target_shift = (it % NUM_TARGETS_PER_REG) *
+ ITARGETSR_FIELD_BITS;
+ uint32_t target_mask = ITARGETSR_FIELD_MASK << target_shift;
+ uint32_t target =
+ read32(gd->gicd_base + GICD_ITARGETSR(reg_idx)) & target_mask;
+
+ target = target >> target_shift;
+ return target;
+}
+
+void gic_dump_state(struct gic_data *gd)
+{
+ int i;
+
+ DMSG("GICC_CTLR: 0x%x", read32(gd->gicc_base + GICC_CTLR));
+ DMSG("GICD_CTLR: 0x%x", read32(gd->gicd_base + GICD_CTLR));
+
+ for (i = 0; i < (int)gd->max_it; i++) {
+ if (gic_it_is_enabled(gd, i)) {
+ DMSG("irq%d: enabled, group:%d, target:%x", i,
+ gic_it_get_group(gd, i), gic_it_get_target(gd, i));
+ }
+ }
+}
+
+void gic_it_handle(struct gic_data *gd)
+{
+ uint32_t iar;
+ uint32_t id;
+
+ iar = gic_read_iar(gd);
+ id = iar & GICC_IAR_IT_ID_MASK;
+
+ if (id == GIC_SPURIOUS_ID)
+ DMSG("ignoring spurious interrupt");
+ else
+ itr_handle(id);
+
+ gic_write_eoir(gd, iar);
+}
+
+static void gic_op_add(struct itr_chip *chip, size_t it,
+ uint32_t flags __unused)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ gic_it_add(gd, it);
+ /* Set the CPU mask to deliver interrupts to any online core */
+ gic_it_set_cpu_mask(gd, it, 0xff);
+ gic_it_set_prio(gd, it, 0x1);
+}
+
+static void gic_op_enable(struct itr_chip *chip, size_t it)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ gic_it_enable(gd, it);
+}
+
+static void gic_op_disable(struct itr_chip *chip, size_t it)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ gic_it_disable(gd, it);
+}
+
+static void gic_op_raise_pi(struct itr_chip *chip, size_t it)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ gic_it_set_pending(gd, it);
+}
+
+static void gic_op_raise_sgi(struct itr_chip *chip, size_t it,
+ uint8_t cpu_mask)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ if (it < NUM_NS_SGI)
+ gic_it_raise_sgi(gd, it, cpu_mask, 1);
+ else
+ gic_it_raise_sgi(gd, it, cpu_mask, 0);
+}
+static void gic_op_set_affinity(struct itr_chip *chip, size_t it,
+ uint8_t cpu_mask)
+{
+ struct gic_data *gd = container_of(chip, struct gic_data, chip);
+
+ if (it >= gd->max_it)
+ panic();
+
+ gic_it_set_cpu_mask(gd, it, cpu_mask);
+}
diff --git a/core/drivers/hi16xx_rng.c b/core/drivers/hi16xx_rng.c
new file mode 100644
index 0000000..a837477
--- /dev/null
+++ b/core/drivers/hi16xx_rng.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Driver for the internal Random Number Generator of HiSilicon P660/Hi16xx */
+
+#include <initcall.h>
+#include <io.h>
+#include <kernel/mutex.h>
+#include <kernel/tee_time.h>
+#include <mm/core_memprot.h>
+#include <mm/core_mmu.h>
+#include <platform_config.h>
+#include <rng_support.h>
+#include <trace.h>
+#include <types_ext.h>
+#include <util.h>
+
+/* ALG sub-controller registers */
+
+#define ALG_SC_RNG_RESET_DREQ 0xAB4 /* RNG reset cancel */
+# define ALG_SC_SRST_DREQ_RNG BIT(0)
+
+/* RNG registers */
+
+#define RNG_SEED 0x0 /* Initial seed */
+#define RNG_CTRL 0x4 /* Control register */
+# define RNG_SEED_SEL BIT(2) /* Re-seed source: 1: ring osc., 0: LFSR */
+# define RNG_RING_EN BIT(1) /* Enable ring oscillator */
+# define RNG_EN BIT(0) /* Enable RNG */
+#define RNG_NUM 0x10 /* Random number output */
+#define RNG_PHY_SEED 0x14 /* Ring oscillator output */
+
+register_phys_mem(MEM_AREA_IO_SEC, ALG_SC_BASE, ALG_SC_REG_SIZE);
+register_phys_mem(MEM_AREA_IO_SEC, RNG_BASE, RNG_REG_SIZE);
+
+static struct mutex rng_mutex = MUTEX_INITIALIZER;
+
+static TEE_Result hi16xx_rng_init(void)
+{
+ vaddr_t alg = (vaddr_t)phys_to_virt(ALG_SC_BASE, MEM_AREA_IO_SEC);
+ vaddr_t rng = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC);
+ TEE_Time time;
+
+ /* ALG sub-controller must allow RNG out of reset */
+ write32(ALG_SC_SRST_DREQ_RNG, alg + ALG_SC_RNG_RESET_DREQ);
+
+ /* Set initial seed */
+ tee_time_get_sys_time(&time);
+ write32(time.seconds * 1000 + time.millis, rng + RNG_SEED);
+
+ /*
+ * Enable RNG and configure it to re-seed automatically from the
+ * internal ring oscillator
+ */
+ write32(RNG_EN | RNG_RING_EN | RNG_SEED_SEL, rng + RNG_CTRL);
+
+ IMSG("Hi16xx RNG initialized");
+ return TEE_SUCCESS;
+}
+
+uint8_t hw_get_random_byte(void)
+{
+ static vaddr_t r;
+ static int pos;
+ static union {
+ uint32_t val;
+ uint8_t byte[4];
+ } random;
+ uint8_t ret;
+
+ mutex_lock(&rng_mutex);
+
+ if (!r)
+ r = (vaddr_t)phys_to_virt(RNG_BASE, MEM_AREA_IO_SEC) + RNG_NUM;
+
+ if (!pos)
+ random.val = read32(r);
+
+ ret = random.byte[pos++];
+
+ if (pos == 4)
+ pos = 0;
+
+ mutex_unlock(&rng_mutex);
+
+ return ret;
+}
+
+driver_init(hi16xx_rng_init);
diff --git a/core/drivers/hi16xx_uart.c b/core/drivers/hi16xx_uart.c
new file mode 100644
index 0000000..76e769d
--- /dev/null
+++ b/core/drivers/hi16xx_uart.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <drivers/hi16xx_uart.h>
+#include <io.h>
+
+/* Register offsets */
+
+#define UART_RBR 0x00 /* RX data buffer register */
+#define UART_THR 0x00 /* TX data buffer register */
+#define UART_DLL 0x00 /* Lower-bit frequency divider register */
+
+#define UART_IEL 0x04 /* Interrupt enable register */
+#define UART_DLH 0x04 /* Upper-bit frequency divider register */
+
+#define UART_FCR 0x08 /* FIFO control register */
+
+#define UART_LCR 0x0C /* Line control register */
+
+#define UART_LSR 0x14 /* Line status register */
+
+#define UART_USR 0x7C /* Status register */
+
+/*
+ * Line control register
+ */
+
+/* Data length selection */
+#define UART_LCR_DLS5 0x0 /* 5 bits */
+#define UART_LCR_DLS6 0x1 /* 6 bits */
+#define UART_LCR_DLS7 0x2 /* 7 bits */
+#define UART_LCR_DLS8 0x3 /* 8 bits */
+
+/* Enable access to UART_DLL and UART_DLH */
+#define UART_LCR_DLAB 0x80
+
+/*
+ * FIFO control register
+ */
+
+#define UART_FCR_FIFO_EN 0x1 /* Enable FIFO (depth: 32 bytes) */
+#define UART_FCR_RX_FIFO_RST 0x2 /* Clear receive FIFO (auto reset) */
+#define UART_FCR_TX_FIFO_RST 0x4 /* Clear send FIFO (auto reset) */
+
+
+/*
+ * Status register
+ */
+
+#define UART_USR_BUSY_BIT 0 /* 0: idle/non-activated, 1: busy */
+#define UART_USR_TFNF_BIT 1 /* Transmit FIFO not full bit */
+#define UART_USR_TFE_BIT 2 /* Transmit FIFO empty bit */
+#define UART_USR_RFNE_BIT 3 /* Receive FIFO not empty bit */
+#define UART_USR_RFF_BIT 4 /* Receive FIFO full bit */
+
+void hi16xx_uart_flush(vaddr_t base)
+{
+ while (!(read32(base + UART_USR) & UART_USR_TFE_BIT))
+ ;
+}
+
+void hi16xx_uart_init(vaddr_t base, uint32_t uart_clk, uint32_t baud_rate)
+{
+ uint16_t freq_div = uart_clk / (16 * baud_rate);
+
+ /* Enable (and clear) FIFOs */
+ write32(UART_FCR_FIFO_EN, base + UART_FCR);
+
+ /* Enable access to _DLL and _DLH */
+ write32(UART_LCR_DLAB, base + UART_LCR);
+
+ /* Calculate and set UART_DLL */
+ write32(freq_div & 0xFF, base + UART_DLL);
+
+ /* Calculate and set UART_DLH */
+ write32((freq_div >> 8) & 0xFF, base + UART_DLH);
+
+ /* Clear _DLL/_DLH access bit, set data size (8 bits), parity etc. */
+ write32(UART_LCR_DLS8, base + UART_LCR);
+
+ /* Disable interrupt mode */
+ write32(0, base + UART_IEL);
+
+ hi16xx_uart_flush(base);
+}
+
+void hi16xx_uart_putc(int ch, vaddr_t base)
+{
+ /* Wait until TX FIFO is empty */
+ while (!(read32(base + UART_USR) & UART_USR_TFE_BIT))
+ ;
+
+ /* Put character into TX FIFO */
+ write32(ch & 0xFF, base + UART_THR);
+}
+
+bool hi16xx_uart_have_rx_data(vaddr_t base)
+{
+ return (read32(base + UART_USR) & UART_USR_RFNE_BIT);
+}
+
+int hi16xx_uart_getchar(vaddr_t base)
+{
+ while (!hi16xx_uart_have_rx_data(base))
+ ;
+ return read32(base + UART_RBR) & 0xFF;
+}
+
diff --git a/core/drivers/imx_uart.c b/core/drivers/imx_uart.c
new file mode 100644
index 0000000..b66d905
--- /dev/null
+++ b/core/drivers/imx_uart.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <platform_config.h>
+
+#include <drivers/imx_uart.h>
+#include <console.h>
+#include <io.h>
+#include <compiler.h>
+
+/* Register definitions */
+#define URXD 0x0 /* Receiver Register */
+#define UTXD 0x40 /* Transmitter Register */
+#define UCR1 0x80 /* Control Register 1 */
+#define UCR2 0x84 /* Control Register 2 */
+#define UCR3 0x88 /* Control Register 3 */
+#define UCR4 0x8c /* Control Register 4 */
+#define UFCR 0x90 /* FIFO Control Register */
+#define USR1 0x94 /* Status Register 1 */
+#define USR2 0x98 /* Status Register 2 */
+#define UESC 0x9c /* Escape Character Register */
+#define UTIM 0xa0 /* Escape Timer Register */
+#define UBIR 0xa4 /* BRM Incremental Register */
+#define UBMR 0xa8 /* BRM Modulator Register */
+#define UBRC 0xac /* Baud Rate Count Register */
+#define UTS 0xb4 /* UART Test Register (mx31) */
+
+/* UART Control Register Bit Fields.*/
+#define URXD_CHARRDY (1<<15)
+#define URXD_ERR (1<<14)
+#define URXD_OVRRUN (1<<13)
+#define URXD_FRMERR (1<<12)
+#define URXD_BRK (1<<11)
+#define URXD_PRERR (1<<10)
+#define URXD_RX_DATA (0xFF)
+#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
+#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
+#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
+#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
+#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
+#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
+#define UCR1_IREN (1<<7) /* Infrared interface enable */
+#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
+#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
+#define UCR1_SNDBRK (1<<4) /* Send break */
+#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
+#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
+#define UCR1_DOZE (1<<1) /* Doze */
+#define UCR1_UARTEN (1<<0) /* UART enabled */
+
+#define UTS_FRCPERR (1<<13) /* Force parity error */
+#define UTS_LOOP (1<<12) /* Loop tx and rx */
+#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
+#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
+#define UTS_TXFULL (1<<4) /* TxFIFO full */
+#define UTS_RXFULL (1<<3) /* RxFIFO full */
+#define UTS_SOFTRST (1<<0) /* Software reset */
+
+void imx_uart_init(vaddr_t __unused vbase)
+{
+ /*
+ * Do nothing, debug uart(uart0) share with normal world,
+ * everything for uart0 intialization is done in bootloader.
+ */
+}
+
+void imx_uart_flush_tx_fifo(vaddr_t base)
+{
+ while (!(read32(base + UTS) & UTS_TXEMPTY))
+ ;
+}
+
+int imx_uart_getchar(vaddr_t base)
+{
+ while (read32(base + UTS) & UTS_RXEMPTY)
+ ;
+
+ return (read32(base + URXD) & URXD_RX_DATA);
+}
+
+void imx_uart_putc(const char c, vaddr_t base)
+{
+ write32(c, base + UTXD);
+
+ /* wait until sent */
+ while (!(read32(base + UTS) & UTS_TXEMPTY))
+ ;
+}
diff --git a/core/drivers/ns16550.c b/core/drivers/ns16550.c
new file mode 100644
index 0000000..710b351
--- /dev/null
+++ b/core/drivers/ns16550.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <drivers/ns16550.h>
+#include <io.h>
+
+/* uart register defines */
+#define UART_RBR 0x0
+#define UART_THR 0x0
+#define UART_IER 0x1
+#define UART_FCR 0x2
+#define UART_LCR 0x3
+#define UART_MCR 0x4
+#define UART_LSR 0x5
+#define UART_MSR 0x6
+#define UART_SPR 0x7
+
+/* uart status register bits */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+
+void ns16550_flush(vaddr_t base)
+{
+ while ((read8(base + UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+}
+
+void ns16550_putc(int ch, vaddr_t base)
+{
+ ns16550_flush(base);
+
+ /* write out charset to Transmit-hold-register */
+ write8(ch, base + UART_THR);
+}
diff --git a/core/drivers/pl011.c b/core/drivers/pl011.c
new file mode 100644
index 0000000..8c03090
--- /dev/null
+++ b/core/drivers/pl011.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <drivers/pl011.h>
+#include <io.h>
+
+#define UART_DR 0x00 /* data register */
+#define UART_RSR_ECR 0x04 /* receive status or error clear */
+#define UART_DMAWM 0x08 /* DMA watermark configure */
+#define UART_TIMEOUT 0x0C /* Timeout period */
+/* reserved space */
+#define UART_FR 0x18 /* flag register */
+#define UART_ILPR 0x20 /* IrDA low-poer */
+#define UART_IBRD 0x24 /* integer baud register */
+#define UART_FBRD 0x28 /* fractional baud register */
+#define UART_LCR_H 0x2C /* line control register */
+#define UART_CR 0x30 /* control register */
+#define UART_IFLS 0x34 /* interrupt FIFO level select */
+#define UART_IMSC 0x38 /* interrupt mask set/clear */
+#define UART_RIS 0x3C /* raw interrupt register */
+#define UART_MIS 0x40 /* masked interrupt register */
+#define UART_ICR 0x44 /* interrupt clear register */
+#define UART_DMACR 0x48 /* DMA control register */
+
+/* flag register bits */
+#define UART_FR_RTXDIS (1 << 13)
+#define UART_FR_TERI (1 << 12)
+#define UART_FR_DDCD (1 << 11)
+#define UART_FR_DDSR (1 << 10)
+#define UART_FR_DCTS (1 << 9)
+#define UART_FR_RI (1 << 8)
+#define UART_FR_TXFE (1 << 7)
+#define UART_FR_RXFF (1 << 6)
+#define UART_FR_TXFF (1 << 5)
+#define UART_FR_RXFE (1 << 4)
+#define UART_FR_BUSY (1 << 3)
+#define UART_FR_DCD (1 << 2)
+#define UART_FR_DSR (1 << 1)
+#define UART_FR_CTS (1 << 0)
+
+/* transmit/receive line register bits */
+#define UART_LCRH_SPS (1 << 7)
+#define UART_LCRH_WLEN_8 (3 << 5)
+#define UART_LCRH_WLEN_7 (2 << 5)
+#define UART_LCRH_WLEN_6 (1 << 5)
+#define UART_LCRH_WLEN_5 (0 << 5)
+#define UART_LCRH_FEN (1 << 4)
+#define UART_LCRH_STP2 (1 << 3)
+#define UART_LCRH_EPS (1 << 2)
+#define UART_LCRH_PEN (1 << 1)
+#define UART_LCRH_BRK (1 << 0)
+
+/* control register bits */
+#define UART_CR_CTSEN (1 << 15)
+#define UART_CR_RTSEN (1 << 14)
+#define UART_CR_OUT2 (1 << 13)
+#define UART_CR_OUT1 (1 << 12)
+#define UART_CR_RTS (1 << 11)
+#define UART_CR_DTR (1 << 10)
+#define UART_CR_RXE (1 << 9)
+#define UART_CR_TXE (1 << 8)
+#define UART_CR_LPE (1 << 7)
+#define UART_CR_OVSFACT (1 << 3)
+#define UART_CR_UARTEN (1 << 0)
+
+#define UART_IMSC_RTIM (1 << 6)
+#define UART_IMSC_RXIM (1 << 4)
+
+void pl011_flush(vaddr_t base)
+{
+ while (!(read32(base + UART_FR) & UART_FR_TXFE))
+ ;
+}
+
+void pl011_init(vaddr_t base, uint32_t uart_clk, uint32_t baud_rate)
+{
+ /* Clear all errors */
+ write32(0, base + UART_RSR_ECR);
+ /* Disable everything */
+ write32(0, base + UART_CR);
+
+ if (baud_rate) {
+ uint32_t divisor = (uart_clk * 4) / baud_rate;
+
+ write32(divisor >> 6, base + UART_IBRD);
+ write32(divisor & 0x3f, base + UART_FBRD);
+ }
+
+ /* Configure TX to 8 bits, 1 stop bit, no parity, fifo disabled. */
+ write32(UART_LCRH_WLEN_8, base + UART_LCR_H);
+
+ /* Enable interrupts for receive and receive timeout */
+ write32(UART_IMSC_RXIM | UART_IMSC_RTIM, base + UART_IMSC);
+
+ /* Enable UART and RX/TX */
+ write32(UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE, base + UART_CR);
+
+ pl011_flush(base);
+}
+
+void pl011_putc(int ch, vaddr_t base)
+{
+ /*
+ * Wait until there is space in the FIFO
+ */
+ while (read32(base + UART_FR) & UART_FR_TXFF)
+ ;
+
+ /* Send the character */
+ write32(ch, base + UART_DR);
+}
+
+bool pl011_have_rx_data(vaddr_t base)
+{
+ return !(read32(base + UART_FR) & UART_FR_RXFE);
+}
+
+int pl011_getchar(vaddr_t base)
+{
+ while (!pl011_have_rx_data(base))
+ ;
+ return read32(base + UART_DR) & 0xff;
+}
+
diff --git a/core/drivers/pl022_spi.c b/core/drivers/pl022_spi.c
new file mode 100644
index 0000000..e5e3512
--- /dev/null
+++ b/core/drivers/pl022_spi.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <drivers/pl022_spi.h>
+#include <initcall.h>
+#include <io.h>
+#include <kernel/panic.h>
+#include <kernel/tee_time.h>
+#include <platform_config.h>
+#include <trace.h>
+#include <util.h>
+
+/* SPI register offsets */
+#define SSPCR0 0x000
+#define SSPCR1 0x004
+#define SSPDR 0x008
+#define SSPSR 0x00C
+#define SSPCPSR 0x010
+#define SSPIMSC 0x014
+#define SSPRIS 0x018
+#define SSPMIS 0x01C
+#define SSPICR 0x020
+#define SSPDMACR 0x024
+
+#ifdef PLATFORM_hikey
+/* HiKey extensions */
+#define SSPTXFIFOCR 0x028
+#define SSPRXFIFOCR 0x02C
+#define SSPB2BTRANS 0x030
+#endif
+
+/* test registers */
+#define SSPTCR 0x080
+#define SSPITIP 0x084
+#define SSPITOP 0x088
+#define SSPTDR 0x08C
+
+#define SSPPeriphID0 0xFE0
+#define SSPPeriphID1 0xFE4
+#define SSPPeriphID2 0xFE8
+#define SSPPeriphID3 0xFEC
+
+#define SSPPCellID0 0xFF0
+#define SSPPCellID1 0xFF4
+#define SSPPCellID2 0xFF8
+#define SSPPCellID3 0xFFC
+
+/* SPI register masks */
+#define SSPCR0_SCR SHIFT_U32(0xFF, 8)
+#define SSPCR0_SPH SHIFT_U32(1, 7)
+#define SSPCR0_SPH1 SHIFT_U32(1, 7)
+#define SSPCR0_SPH0 SHIFT_U32(0, 7)
+#define SSPCR0_SPO SHIFT_U32(1, 6)
+#define SSPCR0_SPO1 SHIFT_U32(1, 6)
+#define SSPCR0_SPO0 SHIFT_U32(0, 6)
+#define SSPCR0_FRF SHIFT_U32(3, 4)
+#define SSPCR0_FRF_SPI SHIFT_U32(0, 4)
+#define SSPCR0_DSS SHIFT_U32(0xFF, 0)
+#define SSPCR0_DSS_16BIT SHIFT_U32(0xF, 0)
+#define SSPCR0_DSS_8BIT SHIFT_U32(7, 0)
+
+#define SSPCR1_SOD SHIFT_U32(1, 3)
+#define SSPCR1_SOD_ENABLE SHIFT_U32(1, 3)
+#define SSPCR1_SOD_DISABLE SHIFT_U32(0, 3)
+#define SSPCR1_MS SHIFT_U32(1, 2)
+#define SSPCR1_MS_SLAVE SHIFT_U32(1, 2)
+#define SSPCR1_MS_MASTER SHIFT_U32(0, 2)
+#define SSPCR1_SSE SHIFT_U32(1, 1)
+#define SSPCR1_SSE_ENABLE SHIFT_U32(1, 1)
+#define SSPCR1_SSE_DISABLE SHIFT_U32(0, 1)
+#define SSPCR1_LBM SHIFT_U32(1, 0)
+#define SSPCR1_LBM_YES SHIFT_U32(1, 0)
+#define SSPCR1_LBM_NO SHIFT_U32(0, 0)
+
+#define SSPDR_DATA SHIFT_U32(0xFFFF, 0)
+
+#define SSPSR_BSY SHIFT_U32(1, 4)
+#define SSPSR_RNF SHIFT_U32(1, 3)
+#define SSPSR_RNE SHIFT_U32(1, 2)
+#define SSPSR_TNF SHIFT_U32(1, 1)
+#define SSPSR_TFE SHIFT_U32(1, 0)
+
+#define SSPCPSR_CPSDVR SHIFT_U32(0xFF, 0)
+
+#define SSPIMSC_TXIM SHIFT_U32(1, 3)
+#define SSPIMSC_RXIM SHIFT_U32(1, 2)
+#define SSPIMSC_RTIM SHIFT_U32(1, 1)
+#define SSPIMSC_RORIM SHIFT_U32(1, 0)
+
+#define SSPRIS_TXRIS SHIFT_U32(1, 3)
+#define SSPRIS_RXRIS SHIFT_U32(1, 2)
+#define SSPRIS_RTRIS SHIFT_U32(1, 1)
+#define SSPRIS_RORRIS SHIFT_U32(1, 0)
+
+#define SSPMIS_TXMIS SHIFT_U32(1, 3)
+#define SSPMIS_RXMIS SHIFT_U32(1, 2)
+#define SSPMIS_RTMIS SHIFT_U32(1, 1)
+#define SSPMIS_RORMIS SHIFT_U32(1, 0)
+
+#define SSPICR_RTIC SHIFT_U32(1, 1)
+#define SSPICR_RORIC SHIFT_U32(1, 0)
+
+#define SSPDMACR_TXDMAE SHIFT_U32(1, 1)
+#define SSPDMACR_RXDMAE SHIFT_U32(1, 0)
+
+#define SSPPeriphID0_PartNumber0 SHIFT_U32(0xFF, 0) /* 0x22 */
+#define SSPPeriphID1_Designer0 SHIFT_U32(0xF, 4) /* 0x1 */
+#define SSPPeriphID1_PartNumber1 SHIFT_U32(0xF, 0) /* 0x0 */
+#define SSPPeriphID2_Revision SHIFT_U32(0xF, 4)
+#define SSPPeriphID2_Designer1 SHIFT_U32(0xF, 0) /* 0x4 */
+#define SSPPeriphID3_Configuration SHIFT_U32(0xFF, 0) /* 0x00 */
+
+#define SSPPCellID_0 SHIFT_U32(0xFF, 0) /* 0x0D */
+#define SSPPCellID_1 SHIFT_U32(0xFF, 0) /* 0xF0 */
+#define SSPPPCellID_2 SHIFT_U32(0xFF, 0) /* 0x05 */
+#define SSPPPCellID_3 SHIFT_U32(0xFF, 0) /* 0xB1 */
+
+#define MASK_32 0xFFFFFFFF
+#define MASK_28 0xFFFFFFF
+#define MASK_24 0xFFFFFF
+#define MASK_20 0xFFFFF
+#define MASK_16 0xFFFF
+#define MASK_12 0xFFF
+#define MASK_8 0xFF
+#define MASK_4 0xF
+/* SPI register masks */
+
+#define SSP_CPSDVR_MAX 254
+#define SSP_CPSDVR_MIN 2
+#define SSP_SCR_MAX 255
+#define SSP_SCR_MIN 0
+#define SSP_DATASIZE_MAX 16
+
+static enum spi_result pl022_txrx8(struct spi_chip *chip, uint8_t *wdat,
+ uint8_t *rdat, size_t num_pkts)
+{
+ size_t i = 0;
+ size_t j = 0;
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+
+ if (pd->data_size_bits != 8) {
+ EMSG("data_size_bits should be 8, not %u",
+ pd->data_size_bits);
+ return SPI_ERR_CFG;
+ }
+
+ if (wdat)
+ while (i < num_pkts) {
+ if (read8(pd->base + SSPSR) & SSPSR_TNF) {
+ /* tx 1 packet */
+ write8(wdat[i++], pd->base + SSPDR);
+ }
+
+ if (rdat)
+ if (read8(pd->base + SSPSR) & SSPSR_RNE) {
+ /* rx 1 packet */
+ rdat[j++] = read8(pd->base + SSPDR);
+ }
+ }
+
+ /* Capture remaining rdat not read above */
+ if (rdat) {
+ while ((j < num_pkts) &&
+ (read8(pd->base + SSPSR) & SSPSR_BSY))
+ if (read8(pd->base + SSPSR) & SSPSR_RNE) {
+ /* rx 1 packet */
+ rdat[j++] = read8(pd->base + SSPDR);
+ }
+
+ if (j < num_pkts) {
+ EMSG("Packets requested %zu, received %zu",
+ num_pkts, j);
+ return SPI_ERR_PKTCNT;
+ }
+ }
+
+ return SPI_OK;
+}
+
+static enum spi_result pl022_txrx16(struct spi_chip *chip, uint16_t *wdat,
+ uint16_t *rdat, size_t num_pkts)
+{
+ size_t i = 0;
+ size_t j = 0;
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+ if (pd->data_size_bits != 16) {
+ EMSG("data_size_bits should be 16, not %u",
+ pd->data_size_bits);
+ return SPI_ERR_CFG;
+ }
+
+ if (wdat)
+ while (i < num_pkts) {
+ if (read8(pd->base + SSPSR) & SSPSR_TNF) {
+ /* tx 1 packet */
+ write16(wdat[i++], pd->base + SSPDR);
+ }
+
+ if (rdat)
+ if (read8(pd->base + SSPSR) & SSPSR_RNE) {
+ /* rx 1 packet */
+ rdat[j++] = read16(pd->base + SSPDR);
+ }
+ }
+
+ /* Capture remaining rdat not read above */
+ if (rdat) {
+ while ((j < num_pkts) &&
+ (read8(pd->base + SSPSR) & SSPSR_BSY))
+ if (read8(pd->base + SSPSR) & SSPSR_RNE) {
+ /* rx 1 packet */
+ rdat[j++] = read16(pd->base + SSPDR);
+ }
+
+ if (j < num_pkts) {
+ EMSG("Packets requested %zu, received %zu",
+ num_pkts, j);
+ return SPI_ERR_PKTCNT;
+ }
+ }
+
+ return SPI_OK;
+}
+
+static void pl022_print_peri_id(struct pl022_data *pd __maybe_unused)
+{
+ DMSG("Expected: 0x 22 10 ?4 00");
+ DMSG("Read: 0x %02x %02x %02x %02x",
+ read32(pd->base + SSPPeriphID0),
+ read32(pd->base + SSPPeriphID1),
+ read32(pd->base + SSPPeriphID2),
+ read32(pd->base + SSPPeriphID3));
+}
+
+static void pl022_print_cell_id(struct pl022_data *pd __maybe_unused)
+{
+ DMSG("Expected: 0x 0d f0 05 b1");
+ DMSG("Read: 0x %02x %02x %02x %02x",
+ read32(pd->base + SSPPCellID0),
+ read32(pd->base + SSPPCellID1),
+ read32(pd->base + SSPPCellID2),
+ read32(pd->base + SSPPCellID3));
+}
+
+static void pl022_sanity_check(struct pl022_data *pd)
+{
+ assert(pd);
+ assert(pd->chip.ops);
+ assert(pd->cs_control <= PL022_CS_CTRL_MANUAL);
+ switch (pd->cs_control) {
+ case PL022_CS_CTRL_AUTO_GPIO:
+ assert(pd->cs_data.gpio_data.chip);
+ assert(pd->cs_data.gpio_data.chip->ops);
+ break;
+ case PL022_CS_CTRL_CB:
+ assert(pd->cs_data.cs_cb);
+ break;
+ default:
+ break;
+ }
+ assert(pd->clk_hz);
+ assert(pd->speed_hz && pd->speed_hz <= pd->clk_hz/2);
+ assert(pd->mode <= SPI_MODE3);
+ assert(pd->data_size_bits == 8 || pd->data_size_bits == 16);
+
+ #ifdef PLATFORM_hikey
+ DMSG("SSPB2BTRANS: Expected: 0x2. Read: 0x%x",
+ read32(pd->base + SSPB2BTRANS));
+ #endif
+ pl022_print_peri_id(pd);
+ pl022_print_cell_id(pd);
+}
+
+static inline uint32_t pl022_calc_freq(struct pl022_data *pd,
+ uint8_t cpsdvr, uint8_t scr)
+{
+ return pd->clk_hz / (cpsdvr * (1 + scr));
+}
+
+static void pl022_control_cs(struct spi_chip *chip, enum gpio_level value)
+{
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+ switch (pd->cs_control) {
+ case PL022_CS_CTRL_AUTO_GPIO:
+ if (read8(pd->base + SSPSR) & SSPSR_BSY)
+ DMSG("pl022 busy - do NOT set CS!");
+ while (read8(pd->base + SSPSR) & SSPSR_BSY)
+ ;
+ DMSG("pl022 done - set CS!");
+
+ pd->cs_data.gpio_data.chip->ops->set_value(
+ pd->cs_data.gpio_data.pin_num, value);
+ break;
+ case PL022_CS_CTRL_CB:
+ pd->cs_data.cs_cb(value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void pl022_calc_clk_divisors(struct pl022_data *pd,
+ uint8_t *cpsdvr, uint8_t *scr)
+{
+ unsigned int freq1 = 0;
+ unsigned int freq2 = 0;
+ uint8_t tmp_cpsdvr1;
+ uint8_t tmp_scr1;
+ uint8_t tmp_cpsdvr2 = 0;
+ uint8_t tmp_scr2 = 0;
+
+ for (tmp_scr1 = SSP_SCR_MIN; tmp_scr1 < SSP_SCR_MAX; tmp_scr1++) {
+ for (tmp_cpsdvr1 = SSP_CPSDVR_MIN; tmp_cpsdvr1 < SSP_CPSDVR_MAX;
+ tmp_cpsdvr1++) {
+ freq1 = pl022_calc_freq(pd, tmp_cpsdvr1, tmp_scr1);
+ if (freq1 == pd->speed_hz)
+ goto done;
+ else if (freq1 < pd->speed_hz)
+ goto stage2;
+ }
+ }
+
+stage2:
+ for (tmp_cpsdvr2 = SSP_CPSDVR_MIN; tmp_cpsdvr2 < SSP_CPSDVR_MAX;
+ tmp_cpsdvr2++) {
+ for (tmp_scr2 = SSP_SCR_MIN; tmp_scr2 < SSP_SCR_MAX;
+ tmp_scr2++) {
+ freq2 = pl022_calc_freq(pd, tmp_cpsdvr2, tmp_scr2);
+ if (freq2 <= pd->speed_hz)
+ goto done;
+ }
+ }
+
+done:
+ if (freq1 >= freq2) {
+ *cpsdvr = tmp_cpsdvr1;
+ *scr = tmp_scr1;
+ DMSG("speed: requested: %u, closest1: %u",
+ pd->speed_hz, freq1);
+ } else {
+ *cpsdvr = tmp_cpsdvr2;
+ *scr = tmp_scr2;
+ DMSG("speed: requested: %u, closest2: %u",
+ pd->speed_hz, freq2);
+ }
+ DMSG("CPSDVR: %u (0x%x), SCR: %u (0x%x)",
+ *cpsdvr, *cpsdvr, *scr, *scr);
+}
+
+static void pl022_flush_fifo(struct pl022_data *pd)
+{
+ uint32_t __maybe_unused rdat;
+
+ do {
+ while (read32(pd->base + SSPSR) & SSPSR_RNE) {
+ rdat = read32(pd->base + SSPDR);
+ DMSG("rdat: 0x%x", rdat);
+ }
+ } while (read32(pd->base + SSPSR) & SSPSR_BSY);
+}
+
+static void pl022_configure(struct spi_chip *chip)
+{
+ uint16_t mode;
+ uint16_t data_size;
+ uint8_t cpsdvr;
+ uint8_t scr;
+ uint8_t lbm;
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+ pl022_sanity_check(pd);
+
+ switch (pd->cs_control) {
+ case PL022_CS_CTRL_AUTO_GPIO:
+ DMSG("Use auto GPIO CS control");
+ DMSG("Mask/disable interrupt for CS GPIO");
+ pd->cs_data.gpio_data.chip->ops->set_interrupt(
+ pd->cs_data.gpio_data.pin_num,
+ GPIO_INTERRUPT_DISABLE);
+ DMSG("Set CS GPIO dir to out");
+ pd->cs_data.gpio_data.chip->ops->set_direction(
+ pd->cs_data.gpio_data.pin_num,
+ GPIO_DIR_OUT);
+ break;
+ case PL022_CS_CTRL_CB:
+ DMSG("Use registered CS callback");
+ break;
+ case PL022_CS_CTRL_MANUAL:
+ DMSG("Use manual CS control");
+ break;
+ default:
+ EMSG("Invalid CS control type: %d", pd->cs_control);
+ panic();
+ }
+
+ DMSG("Pull CS high");
+ pl022_control_cs(chip, GPIO_LEVEL_HIGH);
+
+ pl022_calc_clk_divisors(pd, &cpsdvr, &scr);
+
+ /* configure ssp based on platform settings */
+ switch (pd->mode) {
+ case SPI_MODE0:
+ DMSG("SPI mode 0");
+ mode = SSPCR0_SPO0 | SSPCR0_SPH0;
+ break;
+ case SPI_MODE1:
+ DMSG("SPI mode 1");
+ mode = SSPCR0_SPO0 | SSPCR0_SPH1;
+ break;
+ case SPI_MODE2:
+ DMSG("SPI mode 2");
+ mode = SSPCR0_SPO1 | SSPCR0_SPH0;
+ break;
+ case SPI_MODE3:
+ DMSG("SPI mode 3");
+ mode = SSPCR0_SPO1 | SSPCR0_SPH1;
+ break;
+ default:
+ EMSG("Invalid SPI mode: %u", pd->mode);
+ panic();
+ }
+
+ switch (pd->data_size_bits) {
+ case 8:
+ DMSG("Data size: 8");
+ data_size = SSPCR0_DSS_8BIT;
+ break;
+ case 16:
+ DMSG("Data size: 16");
+ data_size = SSPCR0_DSS_16BIT;
+ break;
+ default:
+ EMSG("Unsupported data size: %u bits", pd->data_size_bits);
+ panic();
+ }
+
+ if (pd->loopback) {
+ DMSG("Starting in loopback mode!");
+ lbm = SSPCR1_LBM_YES;
+ } else {
+ DMSG("Starting in regular (non-loopback) mode!");
+ lbm = SSPCR1_LBM_NO;
+ }
+
+ DMSG("Set Serial Clock Rate (SCR), SPI mode (phase and clock)");
+ DMSG("Set frame format (SPI) and data size (8- or 16-bit)");
+ io_mask16(pd->base + SSPCR0, SHIFT_U32(scr, 8) | mode | SSPCR0_FRF_SPI |
+ data_size, MASK_16);
+
+ DMSG("Set master mode, disable SSP, set loopback mode");
+ io_mask8(pd->base + SSPCR1, SSPCR1_SOD_DISABLE | SSPCR1_MS_MASTER |
+ SSPCR1_SSE_DISABLE | lbm, MASK_4);
+
+ DMSG("Set clock prescale");
+ io_mask8(pd->base + SSPCPSR, cpsdvr, SSPCPSR_CPSDVR);
+
+ DMSG("Disable interrupts");
+ io_mask8(pd->base + SSPIMSC, 0, MASK_4);
+
+ DMSG("Clear interrupts");
+ io_mask8(pd->base + SSPICR, SSPICR_RORIC | SSPICR_RTIC,
+ SSPICR_RORIC | SSPICR_RTIC);
+
+ DMSG("Empty FIFO before starting");
+ pl022_flush_fifo(pd);
+}
+
+static void pl022_start(struct spi_chip *chip)
+{
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+ DMSG("Enable SSP");
+ io_mask8(pd->base + SSPCR1, SSPCR1_SSE_ENABLE, SSPCR1_SSE);
+
+ pl022_control_cs(chip, GPIO_LEVEL_LOW);
+}
+
+static void pl022_end(struct spi_chip *chip)
+{
+ struct pl022_data *pd = container_of(chip, struct pl022_data, chip);
+
+ pl022_control_cs(chip, GPIO_LEVEL_HIGH);
+
+ DMSG("Disable SSP");
+ io_mask8(pd->base + SSPCR1, SSPCR1_SSE_DISABLE, SSPCR1_SSE);
+}
+
+static const struct spi_ops pl022_ops = {
+ .configure = pl022_configure,
+ .start = pl022_start,
+ .txrx8 = pl022_txrx8,
+ .txrx16 = pl022_txrx16,
+ .end = pl022_end,
+};
+
+void pl022_init(struct pl022_data *pd)
+{
+ assert(pd);
+ pd->chip.ops = &pl022_ops;
+}
diff --git a/core/drivers/pl050.c b/core/drivers/pl050.c
new file mode 100644
index 0000000..fa5feab
--- /dev/null
+++ b/core/drivers/pl050.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <compiler.h>
+#include <drivers/pl050.h>
+#include <util.h>
+#include <io.h>
+
+#define KMI_ICR 0x00
+#define KMI_STAT 0x04
+#define KMI_DATA 0x08
+#define KMI_CLKDIV 0x0c
+#define KMI_IR 0x10
+
+#define KMI_ICR_TYPE (1 << 5)
+#define KMI_ICR_RXINTERN (1 << 4)
+#define KMI_ICR_TXINTERN (1 << 3)
+#define KMI_ICR_EN (1 << 2)
+#define KMI_ICR_FKMID (1 << 1)
+#define KMI_ICR_FKMIC (1 << 0)
+
+#define KMI_STAT_TXEMPTY (1 << 6)
+#define KMI_STAT_TXBUSY (1 << 5)
+#define KMI_STAT_RXFULL (1 << 4)
+#define KMI_STAT_RXBUSY (1 << 3)
+#define KMI_STAT_RXPARITY (1 << 2)
+#define KMI_STAT_KMIC (1 << 1)
+#define KMI_STAT_KMID (1 << 0)
+
+#define KMI_IR_TXINTR (1 << 1)
+#define KMI_IR_RXINTR (1 << 0)
+
+static bool pl050_have_rx_data(struct serial_chip *chip)
+{
+ struct pl050_data *pd = container_of(chip, struct pl050_data, chip);
+
+ return !!(read8(pd->base + KMI_STAT) & KMI_STAT_RXFULL);
+}
+
+static int pl050_getchar(struct serial_chip *chip)
+{
+ struct pl050_data *pd = container_of(chip, struct pl050_data, chip);
+
+ while (!pl050_have_rx_data(chip))
+ ;
+ return read8(pd->base + KMI_DATA);
+}
+
+static void pl050_flush(struct serial_chip *chip)
+{
+ struct pl050_data *pd = container_of(chip, struct pl050_data, chip);
+
+ while (!(read8(pd->base + KMI_STAT) & KMI_STAT_TXEMPTY))
+ ;
+}
+
+static void pl050_putc(struct serial_chip *chip, int ch)
+{
+ struct pl050_data *pd = container_of(chip, struct pl050_data, chip);
+
+ pl050_flush(chip);
+ write8(ch, pd->base + KMI_DATA);
+}
+
+static const struct serial_ops pl050_ops = {
+ .putc = pl050_putc,
+ .flush = pl050_flush,
+ .have_rx_data = pl050_have_rx_data,
+ .getchar = pl050_getchar,
+};
+
+void pl050_init(struct pl050_data *pd, vaddr_t base, uint32_t clk)
+{
+ pd->base = base;
+ pd->chip.ops = &pl050_ops;
+
+ write8(KMI_ICR_RXINTERN | KMI_ICR_EN, pd->base + KMI_ICR);
+ write8(clk, base + KMI_CLKDIV);
+}
diff --git a/core/drivers/pl061_gpio.c b/core/drivers/pl061_gpio.c
new file mode 100644
index 0000000..d670c44
--- /dev/null
+++ b/core/drivers/pl061_gpio.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <drivers/pl061_gpio.h>
+#include <io.h>
+#include <trace.h>
+#include <util.h>
+
+#ifndef PLAT_PL061_MAX_GPIOS
+# define PLAT_PL061_MAX_GPIOS 32
+#endif /* PLAT_PL061_MAX_GPIOS */
+
+#define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \
+ (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
+
+#define GPIOS_PER_PL061 8
+
+/* gpio register offsets */
+#define GPIODIR 0x400
+#define GPIOIS 0x404
+#define GPIOIBE 0x408
+#define GPIOIEV 0x40C
+#define GPIOIE 0x410
+#define GPIORIS 0x414
+#define GPIOMIS 0x418
+#define GPIOIC 0x41C
+#define GPIOAFSEL 0x420
+
+/* gpio register masks */
+#define GPIOIE_ENABLED SHIFT_U32(1, 0)
+#define GPIOIE_MASKED SHIFT_U32(0, 0)
+#define GPIOAFSEL_HW SHIFT_U32(1, 0)
+#define GPIOAFSEL_SW SHIFT_U32(0, 0)
+#define GPIODIR_OUT SHIFT_U32(1, 0)
+#define GPIODIR_IN SHIFT_U32(0, 0)
+
+static vaddr_t pl061_reg_base[MAX_GPIO_DEVICES];
+
+static enum gpio_dir pl061_get_direction(unsigned int gpio_pin)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ data = read8(base_addr + GPIODIR);
+ if (data & BIT(offset))
+ return GPIO_DIR_OUT;
+ return GPIO_DIR_IN;
+}
+
+static void pl061_set_direction(unsigned int gpio_pin, enum gpio_dir direction)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ if (direction == GPIO_DIR_OUT) {
+ data = read8(base_addr + GPIODIR) | BIT(offset);
+ write8(data, base_addr + GPIODIR);
+ } else {
+ data = read8(base_addr + GPIODIR) & ~BIT(offset);
+ write8(data, base_addr + GPIODIR);
+ }
+}
+
+/*
+ * The offset of GPIODATA register is 0.
+ * The values read from GPIODATA are determined for each bit, by the mask bit
+ * derived from the address used to access the data register, PADDR[9:2].
+ * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
+ * to be read, and bits that are 0 in the address mask cause the corresponding
+ * bits in GPIODATA to be read as 0, regardless of their value.
+ */
+static enum gpio_level pl061_get_value(unsigned int gpio_pin)
+{
+ vaddr_t base_addr;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ if (read8(base_addr + BIT(offset + 2)))
+ return GPIO_LEVEL_HIGH;
+ return GPIO_LEVEL_LOW;
+}
+
+/*
+ * In order to write GPIODATA, the corresponding bits in the mask, resulting
+ * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
+ * remain unchanged by the write.
+ */
+static void pl061_set_value(unsigned int gpio_pin, enum gpio_level value)
+{
+ vaddr_t base_addr;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ if (value == GPIO_LEVEL_HIGH)
+ write8(BIT(offset), base_addr + BIT(offset + 2));
+ else
+ write8(0, base_addr + BIT(offset + 2));
+}
+
+static enum gpio_interrupt pl061_get_interrupt(unsigned int gpio_pin)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ data = read8(base_addr + GPIOIE);
+ if (data & BIT(offset))
+ return GPIO_INTERRUPT_ENABLE;
+ return GPIO_INTERRUPT_DISABLE;
+}
+
+static void pl061_set_interrupt(unsigned int gpio_pin,
+ enum gpio_interrupt ena_dis)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ if (ena_dis == GPIO_INTERRUPT_ENABLE) {
+ data = read8(base_addr + GPIOIE) | BIT(offset);
+ write8(data, base_addr + GPIOIE);
+ } else {
+ data = read8(base_addr + GPIOIE) & ~BIT(offset);
+ write8(data, base_addr + GPIOIE);
+ }
+}
+
+/*
+ * Register the PL061 GPIO controller with a base address and the offset
+ * of start pin in this GPIO controller.
+ * This function is called after pl061_init().
+ */
+void pl061_register(vaddr_t base_addr, unsigned int gpio_dev)
+{
+ assert(gpio_dev < MAX_GPIO_DEVICES);
+
+ pl061_reg_base[gpio_dev] = base_addr;
+}
+
+static const struct gpio_ops pl061_ops = {
+ .get_direction = pl061_get_direction,
+ .set_direction = pl061_set_direction,
+ .get_value = pl061_get_value,
+ .set_value = pl061_set_value,
+ .get_interrupt = pl061_get_interrupt,
+ .set_interrupt = pl061_set_interrupt,
+};
+
+/*
+ * Initialize PL061 GPIO controller
+ */
+void pl061_init(struct pl061_data *pd)
+{
+ COMPILE_TIME_ASSERT(PLAT_PL061_MAX_GPIOS > 0);
+
+ assert(pd);
+ pd->chip.ops = &pl061_ops;
+}
+
+enum pl061_mode_control pl061_get_mode_control(unsigned int gpio_pin)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ data = read8(base_addr + GPIOAFSEL);
+ if (data & BIT(offset))
+ return PL061_MC_HW;
+ return PL061_MC_SW;
+}
+
+void pl061_set_mode_control(unsigned int gpio_pin,
+ enum pl061_mode_control hw_sw)
+{
+ vaddr_t base_addr;
+ uint8_t data;
+ unsigned int offset;
+
+ assert(gpio_pin < PLAT_PL061_MAX_GPIOS);
+
+ base_addr = pl061_reg_base[gpio_pin / GPIOS_PER_PL061];
+ offset = gpio_pin % GPIOS_PER_PL061;
+ if (hw_sw == PL061_MC_HW) {
+ data = read8(base_addr + GPIOAFSEL) | BIT(offset);
+ write8(data, base_addr + GPIOAFSEL);
+ } else {
+ data = read8(base_addr + GPIOAFSEL) & ~BIT(offset);
+ write8(data, base_addr + GPIOAFSEL);
+ }
+}
diff --git a/core/drivers/pl111.c b/core/drivers/pl111.c
new file mode 100644
index 0000000..de27624
--- /dev/null
+++ b/core/drivers/pl111.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <compiler.h>
+#include <drivers/pl111.h>
+#include <io.h>
+#include <string.h>
+#include <types_ext.h>
+#include <util.h>
+
+#define CLCD_TIM0 0x000
+#define CLCD_TIM1 0x004
+#define CLCD_TIM2 0x008
+#define CLCD_TIM3 0x00c
+#define CLCD_UBASE 0x010
+#define CLCD_LBASE 0x014
+#define CLCD_CNTL 0x018
+#define CLCD_IMSC 0x01c
+#define CLCD_CRSRIMAGE0 0x800
+#define CLCD_CRSRCTRL 0xc00
+#define CLCD_CRSRCFG 0xc04
+#define CLCD_CRSRPLT0 0xc08
+#define CLCD_CRSRXY 0xc10
+
+#define CLCD_TIM0_HBP_SHIFT 24
+#define CLCD_TIM0_HBP_MASK 0x7f
+#define CLCD_TIM0_HFP_SHIFT 16
+#define CLCD_TIM0_HFP_MASK 0x7f
+#define CLCD_TIM0_HSW_SHIFT 8
+#define CLCD_TIM0_HSW_MASK 0x7f
+#define CLCD_TIM0_PPL_SHIFT 2
+#define CLCD_TIM0_PPL_MASK 0x1f
+
+#define CLCD_TIM1_VBP_SHIFT 24
+#define CLCD_TIM1_VBP_MASK 0x7f
+#define CLCD_TIM1_VFP_SHIFT 16
+#define CLCD_TIM1_VFP_MASK 0x7f
+#define CLCD_TIM1_VSW_SHIFT 10
+#define CLCD_TIM1_VSW_MASK 0x1f
+#define CLCD_TIM1_LPP_SHIFT 0
+#define CLCD_TIM1_LPP_MASK 0x1ff
+
+#define CLCD_TIM2_CPL_SHIFT 16
+#define CLCD_TIM2_CPL_MASK 0x1ff
+#define CLCD_TIM2_BCD (1 << 26)
+
+#define CLCD_CNTL_EN (1 << 0)
+#define CLCD_CNTL_BPP_SHIFT 1
+#define CLCD_CNTL_BPP_MASK 0x7
+#define CLCD_CNTL_BPP_24BPP 5
+#define CLCD_CNTL_TFT (1 << 5)
+#define CLCD_CNTL_PWR (1 << 11)
+
+#define CLCD_CRSRXY_X_SHIFT 0
+#define CLCD_CRSRXY_X_MASK 0x1ff
+#define CLCD_CRSRXY_Y_SHIFT 16
+#define CLCD_CRSRXY_Y_MASK 0x1ff
+
+
+void pl111_init(vaddr_t base, paddr_t frame_base,
+ const struct pl111_videomode *m)
+{
+ uint32_t v;
+
+ v = SHIFT_U32((m->hactive / 16) - 1, CLCD_TIM0_PPL_SHIFT) |
+ SHIFT_U32(m->hback_porch - 1, CLCD_TIM0_HBP_SHIFT) |
+ SHIFT_U32(m->hfront_porch - 1, CLCD_TIM0_HFP_SHIFT) |
+ SHIFT_U32(m->hsync_len - 1, CLCD_TIM0_HSW_SHIFT);
+ write32(v, base + CLCD_TIM0);
+
+ v = SHIFT_U32(m->vactive - 1, CLCD_TIM1_LPP_SHIFT) |
+ SHIFT_U32(m->vsync_len, CLCD_TIM1_VSW_SHIFT) |
+ SHIFT_U32(m->vfront_porch, CLCD_TIM1_VFP_SHIFT) |
+ SHIFT_U32(m->vback_porch, CLCD_TIM1_VBP_SHIFT);
+ write32(v, base + CLCD_TIM1);
+
+ v = SHIFT_U32(m->hactive - 1, CLCD_TIM2_CPL_SHIFT) | CLCD_TIM2_BCD;
+ write32(v, base + CLCD_TIM2);
+
+ write32(0, base + CLCD_TIM3);
+ write32(frame_base, base + CLCD_UBASE);
+ write32(0, base + CLCD_LBASE);
+ write32(0, base + CLCD_IMSC);
+
+ write32(0, base + CLCD_CRSRCFG);
+
+ v = CLCD_CNTL_EN | SHIFT_U32(CLCD_CNTL_BPP_24BPP, CLCD_CNTL_BPP_SHIFT) |
+ CLCD_CNTL_TFT | CLCD_CNTL_PWR;
+ write32(v, base + CLCD_CNTL);
+}
+
+void pl111_cursor(vaddr_t base, bool on)
+{
+ write32(on ? 1 : 0, base + CLCD_CRSRCTRL);
+}
+
+void pl111_set_cursor_xy(vaddr_t base, size_t x, size_t y)
+{
+ write32(SHIFT_U32(x, CLCD_CRSRXY_X_SHIFT) |
+ SHIFT_U32(y, CLCD_CRSRXY_Y_SHIFT),
+ base + CLCD_CRSRXY);
+}
diff --git a/core/drivers/ps2mouse.c b/core/drivers/ps2mouse.c
new file mode 100644
index 0000000..893b247
--- /dev/null
+++ b/core/drivers/ps2mouse.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <types_ext.h>
+#include <drivers/ps2mouse.h>
+#include <drivers/serial.h>
+#include <string.h>
+#include <keep.h>
+#include <trace.h>
+
+#define PS2_CMD_RESET 0xff
+#define PS2_CMD_ACK 0xfa
+#define PS2_CMD_ENABLE_DATA_REPORTING 0xf4
+#define PS2_BAT_OK 0xaa
+#define PS2_MOUSE_ID 0x00
+
+#define PS2_BYTE0_Y_OVERFLOW (1 << 7)
+#define PS2_BYTE0_X_OVERFLOW (1 << 6)
+#define PS2_BYTE0_Y_SIGN (1 << 5)
+#define PS2_BYTE0_X_SIGN (1 << 4)
+#define PS2_BYTE0_ALWAYS_ONE (1 << 3)
+#define PS2_BYTE0_MIDDLE_DOWN (1 << 2)
+#define PS2_BYTE0_RIGHT_DOWN (1 << 1)
+#define PS2_BYTE0_LEFT_DOWN (1 << 0)
+
+static void call_callback(struct ps2mouse_data *d, uint8_t byte1,
+ uint8_t byte2, uint8_t byte3)
+{
+ uint8_t button;
+ int16_t xdelta;
+ int16_t ydelta;
+
+ button = byte1 & (PS2_BYTE0_MIDDLE_DOWN | PS2_BYTE0_RIGHT_DOWN |
+ PS2_BYTE0_LEFT_DOWN);
+
+ if (byte1 & PS2_BYTE0_X_OVERFLOW) {
+ xdelta = byte1 & PS2_BYTE0_X_SIGN ? -255 : 255;
+ } else {
+ xdelta = byte2;
+ if (byte1 & PS2_BYTE0_X_SIGN)
+ xdelta |= 0xff00; /* sign extend */
+ }
+
+ if (byte1 & PS2_BYTE0_Y_OVERFLOW) {
+ ydelta = byte1 & PS2_BYTE0_Y_SIGN ? -255 : 255;
+ } else {
+ ydelta = byte3;
+ if (byte1 & PS2_BYTE0_Y_SIGN)
+ ydelta |= 0xff00; /* sign extend */
+ }
+
+ d->callback(d->callback_data, button, xdelta, -ydelta);
+}
+
+static void psm_consume(struct ps2mouse_data *d, uint8_t b)
+{
+ switch (d->state) {
+ case PS2MS_RESET:
+ if (b != PS2_CMD_ACK)
+ goto reset;
+ d->state = PS2MS_INIT;
+ return;
+ case PS2MS_INIT:
+ if (b != PS2_BAT_OK)
+ goto reset;
+ d->state = PS2MS_INIT2;
+ return;
+ case PS2MS_INIT2:
+ if (b != PS2_MOUSE_ID) {
+ EMSG("Unexpected byte 0x%x in state %d", b, d->state);
+ d->state = PS2MS_INACTIVE;
+ return;
+ }
+ d->state = PS2MS_INIT3;
+ d->serial->ops->putc(d->serial, PS2_CMD_ENABLE_DATA_REPORTING);
+ return;
+ case PS2MS_INIT3:
+ d->state = PS2MS_ACTIVE1;
+ return;
+ case PS2MS_ACTIVE1:
+ if (!(b & PS2_BYTE0_ALWAYS_ONE))
+ goto reset;
+ d->bytes[0] = b;
+ d->state = PS2MS_ACTIVE2;
+ return;
+ case PS2MS_ACTIVE2:
+ d->bytes[1] = b;
+ d->state = PS2MS_ACTIVE3;
+ return;
+ case PS2MS_ACTIVE3:
+ d->state = PS2MS_ACTIVE1;
+ call_callback(d, d->bytes[0], d->bytes[1], b);
+ return;
+ default:
+ EMSG("Unexpected byte 0x%x in state %d", b, d->state);
+ return;
+ }
+
+reset:
+ EMSG("Unexpected byte 0x%x in state %d, resetting", b, d->state);
+ d->state = PS2MS_RESET;
+ d->serial->ops->putc(d->serial, PS2_CMD_RESET);
+}
+
+static enum itr_return ps2mouse_itr_cb(struct itr_handler *h)
+{
+ struct ps2mouse_data *d = h->data;
+
+ if (!d->serial->ops->have_rx_data(d->serial))
+ return ITRR_NONE;
+
+ while (true) {
+ psm_consume(d, d->serial->ops->getchar(d->serial));
+ if (!d->serial->ops->have_rx_data(d->serial))
+ return ITRR_HANDLED;
+ }
+}
+KEEP_PAGER(ps2mouse_itr_cb);
+
+void ps2mouse_init(struct ps2mouse_data *d, struct serial_chip *serial,
+ size_t serial_it, ps2mouse_callback cb, void *cb_data)
+{
+ memset(d, 0, sizeof(*d));
+ d->serial = serial;
+ d->state = PS2MS_RESET;
+ d->itr_handler.it = serial_it;
+ d->itr_handler.flags = ITRF_TRIGGER_LEVEL;
+ d->itr_handler.handler = ps2mouse_itr_cb;
+ d->itr_handler.data = d;
+ d->callback = cb;
+ d->callback_data = cb_data;
+
+ itr_add(&d->itr_handler);
+ itr_enable(serial_it);
+ d->serial->ops->putc(d->serial, PS2_CMD_RESET);
+}
diff --git a/core/drivers/scif.c b/core/drivers/scif.c
new file mode 100644
index 0000000..02fd49d
--- /dev/null
+++ b/core/drivers/scif.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016, GlobalLogic
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <compiler.h>
+#include <io.h>
+#include <util.h>
+#include <drivers/scif.h>
+
+#define SCIF_SCFSR (0x10)
+#define SCIF_SCFTDR (0x0C)
+#define SCIF_SCFCR (0x18)
+#define SCIF_SCFDR (0x1C)
+
+#define SCFSR_TDFE BIT(5)
+#define SCFSR_TEND BIT(6)
+
+#define SCFDR_T_SHIFT 8
+
+#define SCIF_TX_FIFO_SIZE 16
+
+void scif_uart_flush(vaddr_t base)
+{
+ while (!(read16(base + SCIF_SCFSR) & SCFSR_TEND))
+ ;
+}
+
+void scif_uart_init(vaddr_t base)
+{
+ /* Bootloader should initialize device for us */
+ scif_uart_flush(base);
+}
+
+void scif_uart_putc(int ch, vaddr_t base)
+{
+ /* Wait until there is space in the FIFO */
+ while ((read16(base + SCIF_SCFDR) >> SCFDR_T_SHIFT) >=
+ SCIF_TX_FIFO_SIZE)
+ ;
+ write8(ch, base + SCIF_SCFTDR);
+ write16(read16(base + SCIF_SCFSR) & ~(SCFSR_TEND | SCFSR_TDFE),
+ base + SCIF_SCFSR);
+}
diff --git a/core/drivers/serial8250_uart.c b/core/drivers/serial8250_uart.c
new file mode 100644
index 0000000..1dd21de
--- /dev/null
+++ b/core/drivers/serial8250_uart.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <platform_config.h>
+
+#include <drivers/serial8250_uart.h>
+#include <console.h>
+#include <io.h>
+#include <compiler.h>
+
+/* uart register defines */
+#define UART_RHR 0x0
+#define UART_THR 0x0
+#define UART_IER 0x4
+#define UART_ISR 0x8
+#define UART_FCR 0x8
+#define UART_LCR 0xc
+#define UART_MCR 0x10
+#define UART_LSR 0x14
+#define UART_MSR 0x18
+#define UART_SPR 0x1c
+
+/* uart status register bits */
+#define LSR_TEMT 0x40 /* Transmitter empty */
+#define LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define LSR_EMPTY (LSR_TEMT | LSR_THRE)
+#define LSR_DR 0x01 /* DATA Ready */
+
+void serial8250_uart_init(vaddr_t __unused base,
+ uint32_t __unused uart_clk, uint32_t __unused baud_rate)
+{
+ /*
+ * do nothing, debug uart(uart0) share with normal world,
+ * everything for uart0 is ready now.
+ */
+}
+
+void serial8250_uart_flush_tx_fifo(vaddr_t base)
+{
+ while (1) {
+ uint8_t state = read8(base + UART_LSR);
+
+ /* waiting transmit fifo empty */
+ if ((state & LSR_EMPTY) == LSR_EMPTY)
+ break;
+ }
+}
+
+bool serial8250_uart_have_rx_data(vaddr_t base)
+{
+ return (read32(base + UART_LSR) & LSR_DR);
+}
+
+void serial8250_uart_putc(int ch, vaddr_t base)
+{
+ serial8250_uart_flush_tx_fifo(base);
+
+ /* write out charset to transmit fifo */
+ write8(ch, base + UART_THR);
+}
+
+int serial8250_uart_getchar(vaddr_t base)
+{
+ while (!serial8250_uart_have_rx_data(base)) {
+ /* transmit fifo is empty, waiting again. */
+ ;
+ }
+ return read8(base + UART_RHR);
+}
+
diff --git a/core/drivers/sprd_uart.c b/core/drivers/sprd_uart.c
new file mode 100644
index 0000000..fdaa1b6
--- /dev/null
+++ b/core/drivers/sprd_uart.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, Spreadtrum Communications Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <io.h>
+#include <drivers/sprd_uart.h>
+
+/* Register definitions */
+#define UART_TXD 0x0000
+#define UART_RXD 0x0004
+#define UART_STS1 0x000C /* data number in TX and RX fifo */
+
+/* Register Bit Fields*/
+#define STS1_RXF_CNT_MASK 0x00ff /* Rx FIFO data counter mask */
+#define STS1_TXF_CNT_MASK 0xff00 /* Tx FIFO data counter mask */
+
+static uint32_t sprd_uart_read(vaddr_t base, uint32_t reg)
+{
+ return read32(base + reg);
+}
+
+static void sprd_uart_write(vaddr_t base, uint32_t reg, uint32_t value)
+{
+ write32(value, base + reg);
+}
+
+static void sprd_uart_wait_xmit_done(vaddr_t base)
+{
+ while (sprd_uart_read(base, UART_STS1) & STS1_TXF_CNT_MASK)
+ ;
+}
+
+static void sprd_uart_wait_rx_data(vaddr_t base)
+{
+ while (!(sprd_uart_read(base, UART_STS1) & STS1_RXF_CNT_MASK))
+ ;
+}
+
+void sprd_uart_flush(vaddr_t base)
+{
+ sprd_uart_wait_xmit_done(base);
+}
+
+void sprd_uart_putc(vaddr_t base, unsigned char ch)
+{
+ sprd_uart_wait_xmit_done(base);
+
+ sprd_uart_write(base, UART_TXD, (uint32_t)ch);
+}
+
+unsigned char sprd_uart_getc(vaddr_t base)
+{
+ sprd_uart_wait_rx_data(base);
+
+ return sprd_uart_read(base, UART_RXD) & 0xff;
+}
diff --git a/core/drivers/sub.mk b/core/drivers/sub.mk
new file mode 100644
index 0000000..609b378
--- /dev/null
+++ b/core/drivers/sub.mk
@@ -0,0 +1,19 @@
+srcs-$(CFG_CDNS_UART) += cdns_uart.c
+srcs-$(CFG_PL011) += pl011.c
+srcs-$(CFG_PL050) += pl050.c
+srcs-$(CFG_TZC400) += tzc400.c
+srcs-$(CFG_PS2MOUSE) += ps2mouse.c
+srcs-$(CFG_PL111) += pl111.c
+srcs-$(CFG_FRAME_BUFFER) += frame_buffer.c
+srcs-$(CFG_GIC) += gic.c
+srcs-$(CFG_PL061) += pl061_gpio.c
+srcs-$(CFG_PL022) += pl022_spi.c
+srcs-$(CFG_SUNXI_UART) += sunxi_uart.c
+srcs-$(CFG_8250_UART) += serial8250_uart.c
+srcs-$(CFG_16550_UART) += ns16550.c
+srcs-$(CFG_IMX_UART) += imx_uart.c
+srcs-$(CFG_SPRD_UART) += sprd_uart.c
+srcs-$(CFG_HI16XX_UART) += hi16xx_uart.c
+srcs-$(CFG_HI16XX_RNG) += hi16xx_rng.c
+srcs-$(CFG_SCIF) += scif.c
+srcs-$(CFG_DRA7_RNG) += dra7_rng.c
diff --git a/core/drivers/sunxi_uart.c b/core/drivers/sunxi_uart.c
new file mode 100644
index 0000000..433c423
--- /dev/null
+++ b/core/drivers/sunxi_uart.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, Allwinner Technology Co., Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <platform_config.h>
+
+#include <drivers/sunxi_uart.h>
+#include <io.h>
+#include <compiler.h>
+
+/* uart register defines */
+#define UART_REG_RBR (0x00)
+#define UART_REG_THR (0x00)
+#define UART_REG_DLL (0x00)
+#define UART_REG_DLH (0x04)
+#define UART_REG_IER (0x04)
+#define UART_REG_IIR (0x08)
+#define UART_REG_FCR (0x08)
+#define UART_REG_LCR (0x0c)
+#define UART_REG_MCR (0x10)
+#define UART_REG_LSR (0x14)
+#define UART_REG_MSR (0x18)
+#define UART_REG_SCH (0x1c)
+#define UART_REG_USR (0x7c)
+#define UART_REG_TFL (0x80)
+#define UART_REG_RFL (0x84)
+#define UART_REG_HALT (0xa4)
+
+/* uart status register bits */
+#define UART_REG_USR_BUSY (0x1 << 0x0)
+#define UART_REG_USR_TFNF (0x1 << 0x1)
+#define UART_REG_USR_TFE (0x1 << 0x2)
+#define UART_REG_USR_RFNE (0x1 << 0x3)
+#define UART_REG_USR_RFF (0x1 << 0x4)
+
+void sunxi_uart_init(vaddr_t __unused base)
+{
+ /* do nothing, debug uart(uart0) share with normal world,
+ * everything for uart0 is ready now.
+ */
+}
+
+void sunxi_uart_flush(vaddr_t base)
+{
+ while (read32(base + UART_REG_TFL)) {
+ /* waiting transmit fifo empty */
+ ;
+ }
+}
+
+bool sunxi_uart_have_rx_data(vaddr_t base)
+{
+ return read32(base + UART_REG_RFL);
+}
+
+void sunxi_uart_putc(int ch, vaddr_t base)
+{
+ while (!(read32(base + UART_REG_USR) & UART_REG_USR_TFNF)) {
+ /* transmit fifo is full, waiting again. */
+ ;
+ }
+
+ /* write out charset to transmit fifo */
+ write8(ch, base + UART_REG_THR);
+}
+
+int sunxi_uart_getchar(vaddr_t base)
+{
+ while (!sunxi_uart_have_rx_data(base)) {
+ /* transmit fifo is empty, waiting again. */
+ ;
+ }
+ return read32(base + UART_REG_RBR) & 0xff;
+}
+
diff --git a/core/drivers/tzc400.c b/core/drivers/tzc400.c
new file mode 100644
index 0000000..9fee0b4
--- /dev/null
+++ b/core/drivers/tzc400.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ /*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <drivers/tzc400.h>
+#include <io.h>
+#include <kernel/panic.h>
+#include <stddef.h>
+#include <trace.h>
+#include <util.h>
+
+/*
+ * Implementation defined values used to validate inputs later.
+ * Filters : max of 4 ; 0 to 3
+ * Regions : max of 9 ; 0 to 8
+ * Address width : Values between 32 to 64
+ */
+struct tzc_instance {
+ vaddr_t base;
+ uint8_t addr_width;
+ uint8_t num_filters;
+ uint8_t num_regions;
+};
+
+static struct tzc_instance tzc;
+
+
+static uint32_t tzc_read_build_config(vaddr_t base)
+{
+ return read32(base + BUILD_CONFIG_OFF);
+}
+
+static uint32_t tzc_read_gate_keeper(vaddr_t base)
+{
+ return read32(base + GATE_KEEPER_OFF);
+}
+
+static void tzc_write_gate_keeper(vaddr_t base, uint32_t val)
+{
+ write32(val, base + GATE_KEEPER_OFF);
+}
+
+static void tzc_write_action(vaddr_t base, enum tzc_action action)
+{
+ write32(action, base + ACTION_OFF);
+}
+
+static void tzc_write_region_base_low(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_BASE_LOW_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static void tzc_write_region_base_high(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_BASE_HIGH_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static void tzc_write_region_top_low(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_TOP_LOW_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static void tzc_write_region_top_high(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_TOP_HIGH_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static void tzc_write_region_attributes(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_ATTRIBUTES_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static void tzc_write_region_id_access(vaddr_t base, uint32_t region,
+ uint32_t val)
+{
+ write32(val, base + REGION_ID_ACCESS_OFF +
+ REGION_NUM_OFF(region));
+}
+
+static uint32_t tzc_read_component_id(vaddr_t base)
+{
+ uint32_t id;
+
+ id = read8(base + CID0_OFF);
+ id |= SHIFT_U32(read8(base + CID1_OFF), 8);
+ id |= SHIFT_U32(read8(base + CID2_OFF), 16);
+ id |= SHIFT_U32(read8(base + CID3_OFF), 24);
+
+ return id;
+}
+
+static uint32_t tzc_get_gate_keeper(vaddr_t base, uint8_t filter)
+{
+ uint32_t tmp;
+
+ tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
+ GATE_KEEPER_OS_MASK;
+
+ return (tmp >> filter) & GATE_KEEPER_FILTER_MASK;
+}
+
+/* This function is not MP safe. */
+static void tzc_set_gate_keeper(vaddr_t base, uint8_t filter, uint32_t val)
+{
+ uint32_t tmp;
+
+ /* Upper half is current state. Lower half is requested state. */
+ tmp = (tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
+ GATE_KEEPER_OS_MASK;
+
+ if (val)
+ tmp |= (1 << filter);
+ else
+ tmp &= ~(1 << filter);
+
+ tzc_write_gate_keeper(base, (tmp & GATE_KEEPER_OR_MASK) <<
+ GATE_KEEPER_OR_SHIFT);
+
+ /* Wait here until we see the change reflected in the TZC status. */
+ while (((tzc_read_gate_keeper(base) >> GATE_KEEPER_OS_SHIFT) &
+ GATE_KEEPER_OS_MASK) != tmp)
+ ;
+}
+
+
+void tzc_init(vaddr_t base)
+{
+ uint32_t tzc_id, tzc_build;
+
+ assert(base);
+ tzc.base = base;
+
+ /*
+ * We expect to see a tzc400. Check component ID. The TZC-400 TRM shows
+ * component ID is expected to be "0xB105F00D".
+ */
+ tzc_id = tzc_read_component_id(tzc.base);
+ if (tzc_id != TZC400_COMPONENT_ID) {
+ EMSG("TZC : Wrong device ID (0x%x).\n", tzc_id);
+ panic();
+ }
+
+ /* Save values we will use later. */
+ tzc_build = tzc_read_build_config(tzc.base);
+ tzc.num_filters = ((tzc_build >> BUILD_CONFIG_NF_SHIFT) &
+ BUILD_CONFIG_NF_MASK) + 1;
+ tzc.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) &
+ BUILD_CONFIG_AW_MASK) + 1;
+ tzc.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) &
+ BUILD_CONFIG_NR_MASK) + 1;
+}
+
+static uint32_t addr_low(vaddr_t addr)
+{
+ return (uint32_t)addr;
+}
+
+static uint32_t addr_high(vaddr_t addr __unused)
+{
+#if (UINTPTR_MAX == UINT64_MAX)
+ return (addr >> 32);
+#else
+ return 0;
+#endif
+}
+
+
+/*
+ * `tzc_configure_region` is used to program regions into the TrustZone
+ * controller. A region can be associated with more than one filter. The
+ * associated filters are passed in as a bitmap (bit0 = filter0).
+ * NOTE:
+ * The region 0 covers the whole address space and is enabled on all filters,
+ * this cannot be changed. It is, however, possible to change some region 0
+ * permissions.
+ */
+void tzc_configure_region(uint32_t filters,
+ uint8_t region,
+ vaddr_t region_base,
+ vaddr_t region_top,
+ enum tzc_region_attributes sec_attr,
+ uint32_t ns_device_access)
+{
+ assert(tzc.base);
+
+ /* Do range checks on filters and regions. */
+ assert(((filters >> tzc.num_filters) == 0) &&
+ (region < tzc.num_regions));
+
+ /*
+ * Do address range check based on TZC configuration. A 64bit address is
+ * the max and expected case.
+ */
+#if (UINTPTR_MAX == UINT64_MAX)
+ assert(((region_top <= (UINT64_MAX >> (64 - tzc.addr_width))) &&
+ (region_base < region_top)));
+#endif
+ /* region_base and (region_top + 1) must be 4KB aligned */
+ assert(((region_base | (region_top + 1)) & (4096 - 1)) == 0);
+
+ assert(sec_attr <= TZC_REGION_S_RDWR);
+
+ /*
+ * Inputs look ok, start programming registers.
+ * All the address registers are 32 bits wide and have a LOW and HIGH
+ * component used to construct a up to a 64bit address.
+ */
+ tzc_write_region_base_low(tzc.base, region,
+ addr_low(region_base));
+ tzc_write_region_base_high(tzc.base, region,
+ addr_high(region_base));
+
+ tzc_write_region_top_low(tzc.base, region,
+ addr_low(region_top));
+ tzc_write_region_top_high(tzc.base, region,
+ addr_high(region_top));
+
+ /* Assign the region to a filter and set secure attributes */
+ tzc_write_region_attributes(tzc.base, region,
+ (sec_attr << REG_ATTR_SEC_SHIFT) | filters);
+
+ /*
+ * Specify which non-secure devices have permission to access this
+ * region.
+ */
+ tzc_write_region_id_access(tzc.base, region, ns_device_access);
+}
+
+
+void tzc_set_action(enum tzc_action action)
+{
+ assert(tzc.base);
+
+ /*
+ * - Currently no handler is provided to trap an error via interrupt
+ * or exception.
+ * - The interrupt action has not been tested.
+ */
+ tzc_write_action(tzc.base, action);
+}
+
+
+void tzc_enable_filters(void)
+{
+ uint32_t state;
+ uint32_t filter;
+
+ assert(tzc.base);
+
+ for (filter = 0; filter < tzc.num_filters; filter++) {
+ state = tzc_get_gate_keeper(tzc.base, filter);
+ if (state) {
+ /*
+ * The TZC filter is already configured. Changing the
+ * programmer's view in an active system can cause
+ * unpredictable behavior therefore panic for now rather
+ * than try to determine whether this is safe in this
+ * instance. See:
+ * http://infocenter.arm.com/help/index.jsp?\
+ * topic=/com.arm.doc.ddi0504c/CJHHECBF.html
+ */
+ EMSG("TZC : Filter %d Gatekeeper already enabled.\n",
+ filter);
+ panic();
+ }
+ tzc_set_gate_keeper(tzc.base, filter, 1);
+ }
+}
+
+
+void tzc_disable_filters(void)
+{
+ uint32_t filter;
+
+ assert(tzc.base);
+
+ /*
+ * We don't do the same state check as above as the Gatekeepers are
+ * disabled after reset.
+ */
+ for (filter = 0; filter < tzc.num_filters; filter++)
+ tzc_set_gate_keeper(tzc.base, filter, 0);
+}
+
+#if TRACE_LEVEL >= TRACE_DEBUG
+
+static uint32_t tzc_read_region_attributes(vaddr_t base, uint32_t region)
+{
+ return read32(base + REGION_ATTRIBUTES_OFF + REGION_NUM_OFF(region));
+}
+
+static uint32_t tzc_read_region_base_low(vaddr_t base, uint32_t region)
+{
+ return read32(base + REGION_BASE_LOW_OFF + REGION_NUM_OFF(region));
+}
+
+static uint32_t tzc_read_region_base_high(vaddr_t base, uint32_t region)
+{
+ return read32(base + REGION_BASE_HIGH_OFF + REGION_NUM_OFF(region));
+}
+
+static uint32_t tzc_read_region_top_low(vaddr_t base, uint32_t region)
+{
+ return read32(base + REGION_TOP_LOW_OFF + REGION_NUM_OFF(region));
+}
+
+static uint32_t tzc_read_region_top_high(vaddr_t base, uint32_t region)
+{
+ return read32(base + REGION_TOP_HIGH_OFF + REGION_NUM_OFF(region));
+}
+
+#define REGION_MAX 8
+static const __maybe_unused char * const tzc_attr_msg[] = {
+ "TZC_REGION_S_NONE",
+ "TZC_REGION_S_RD",
+ "TZC_REGION_S_WR",
+ "TZC_REGION_S_RDWR"
+};
+
+void tzc_dump_state(void)
+{
+ uint32_t n;
+ uint32_t temp_32reg, temp_32reg_h;
+
+ DMSG("enter");
+ for (n = 0; n <= REGION_MAX; n++) {
+ temp_32reg = tzc_read_region_attributes(tzc.base, n);
+ if (!(temp_32reg & REG_ATTR_F_EN_MASK))
+ continue;
+
+ DMSG("\n");
+ DMSG("region %d", n);
+ temp_32reg = tzc_read_region_base_low(tzc.base, n);
+ temp_32reg_h = tzc_read_region_base_high(tzc.base, n);
+ DMSG("region_base: 0x%08x%08x", temp_32reg_h, temp_32reg);
+ temp_32reg = tzc_read_region_top_low(tzc.base, n);
+ temp_32reg_h = tzc_read_region_top_high(tzc.base, n);
+ DMSG("region_top: 0x%08x%08x", temp_32reg_h, temp_32reg);
+ temp_32reg = tzc_read_region_attributes(tzc.base, n);
+ DMSG("secure rw: %s",
+ tzc_attr_msg[temp_32reg >> REG_ATTR_SEC_SHIFT]);
+ if (temp_32reg & (1 << 0))
+ DMSG("filter 0 enable");
+ if (temp_32reg & (1 << 1))
+ DMSG("filter 1 enable");
+ if (temp_32reg & (1 << 2))
+ DMSG("filter 2 enable");
+ if (temp_32reg & (1 << 3))
+ DMSG("filter 3 enable");
+ }
+ DMSG("exit");
+}
+
+#endif /* CFG_TRACE_LEVEL >= TRACE_DEBUG */