diff options
Diffstat (limited to 'core/drivers')
-rw-r--r-- | core/drivers/cdns_uart.c | 100 | ||||
-rw-r--r-- | core/drivers/dra7_rng.c | 204 | ||||
-rw-r--r-- | core/drivers/frame_buffer.c | 59 | ||||
-rw-r--r-- | core/drivers/gic.c | 457 | ||||
-rw-r--r-- | core/drivers/hi16xx_rng.c | 113 | ||||
-rw-r--r-- | core/drivers/hi16xx_uart.c | 131 | ||||
-rw-r--r-- | core/drivers/imx_uart.c | 112 | ||||
-rw-r--r-- | core/drivers/ns16550.c | 57 | ||||
-rw-r--r-- | core/drivers/pl011.c | 147 | ||||
-rw-r--r-- | core/drivers/pl022_spi.c | 530 | ||||
-rw-r--r-- | core/drivers/pl050.c | 102 | ||||
-rw-r--r-- | core/drivers/pl061_gpio.c | 243 | ||||
-rw-r--r-- | core/drivers/pl111.c | 126 | ||||
-rw-r--r-- | core/drivers/ps2mouse.c | 160 | ||||
-rw-r--r-- | core/drivers/scif.c | 65 | ||||
-rw-r--r-- | core/drivers/serial8250_uart.c | 93 | ||||
-rw-r--r-- | core/drivers/sprd_uart.c | 78 | ||||
-rw-r--r-- | core/drivers/sub.mk | 19 | ||||
-rw-r--r-- | core/drivers/sunxi_uart.c | 97 | ||||
-rw-r--r-- | core/drivers/tzc400.c | 417 |
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 */ |