From 9055c7d149758f2f2a646f40f08d6d24b07dfff3 Mon Sep 17 00:00:00 2001 From: Ryan Harkin Date: Tue, 17 Mar 2015 14:50:05 +0000 Subject: [PATCH 1/3] Add a simple delay timer driver API The API is simple. The BSP or specific timer driver creates an instance of timer_ops_t, fills in the timer specific data, then calls timer_init(). The timer specific data includes a function pointer to return the timer value and a clock multiplier/divider. The ratio of the multiplier and the divider is the clock frequency in MHz. After that, mdelay() or udelay() can be called to delay execution for the specified time (milliseconds or microseconds, respectively). Change-Id: Icf8a295e1d25874f789bf28b7412156329dc975c Co-authored-by: Dan Handley --- drivers/delay_timer/delay_timer.c | 87 +++++++++++++++++++++++++++++++ include/drivers/delay_timer.h | 55 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 drivers/delay_timer/delay_timer.c create mode 100644 include/drivers/delay_timer.h diff --git a/drivers/delay_timer/delay_timer.c b/drivers/delay_timer/delay_timer.c new file mode 100644 index 000000000..0bee876f3 --- /dev/null +++ b/drivers/delay_timer/delay_timer.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, 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 +#include +#include + +/*********************************************************** + * The delay timer implementation + ***********************************************************/ +static const timer_ops_t *ops; + +/*********************************************************** + * Delay for the given number of microseconds. The driver must + * be initialized before calling this function. + ***********************************************************/ +void udelay(uint32_t usec) +{ + assert(ops != 0 && + (ops->clk_mult != 0) && + (ops->clk_div != 0) && + (ops->get_timer_value != 0)); + + uint32_t start, cnt, delta, delta_us; + + /* counter is decreasing */ + start = ops->get_timer_value(); + do { + cnt = ops->get_timer_value(); + if (cnt > start) { + delta = UINT32_MAX - cnt; + delta += start; + } else + delta = start - cnt; + delta_us = (delta * ops->clk_mult) / ops->clk_div; + } while (delta_us < usec); +} + +/*********************************************************** + * Delay for the given number of milliseconds. The driver must + * be initialized before calling this function. + ***********************************************************/ +void mdelay(uint32_t msec) +{ + udelay(msec*1000); +} + +/*********************************************************** + * Initialize the timer. The fields in the provided timer + * ops pointer must be valid. + ***********************************************************/ +void timer_init(const timer_ops_t *ops_ptr) +{ + assert(ops_ptr != 0 && + (ops_ptr->clk_mult != 0) && + (ops_ptr->clk_div != 0) && + (ops_ptr->get_timer_value != 0)); + + ops = ops_ptr; +} diff --git a/include/drivers/delay_timer.h b/include/drivers/delay_timer.h new file mode 100644 index 000000000..4f3bdc88a --- /dev/null +++ b/include/drivers/delay_timer.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef __DELAY_TIMER_H__ +#define __DELAY_TIMER_H__ + +#include + +/******************************************************************** + * A simple timer driver providing synchronous delay functionality. + * The driver must be initialized with a structure that provides a + * function pointer to return the timer value and a clock + * multiplier/divider. The ratio of the multiplier and the divider is + * the clock frequency in MHz. + ********************************************************************/ + +typedef struct timer_ops { + uint32_t (*get_timer_value)(void); + uint32_t clk_mult; + uint32_t clk_div; +} timer_ops_t; + +void mdelay(uint32_t msec); +void udelay(uint32_t usec); +void timer_init(const timer_ops_t *ops); + + +#endif /* __DELAY_TIMER_H__ */ From cc58b2d0f5698560d9f8c26e136fd0afc1d5d71b Mon Sep 17 00:00:00 2001 From: Ryan Harkin Date: Tue, 17 Mar 2015 14:52:39 +0000 Subject: [PATCH 2/3] Add SP804 delay timer driver Add a delay timer driver for the ARM SP804 dual timer. This driver only uses the first timer, called timer 1 in the SP804 Technical Reference Manual (ARM DDI 0271D). To use this driver, the BSP must provide three constants: * The base address of the SP804 dual timer * The clock multiplier * The clock divider The BSP is responsible for calling sp804_timer_init(). The SP804 driver instantiates a constant timer_ops_t and calls the generic timer_init(). Change-Id: I49ba0a52bdf6072f403d1d0a20e305151d4bc086 Co-authored-by: Dan Handley --- drivers/arm/sp804/sp804_delay_timer.c | 79 +++++++++++++++++++++++++ include/drivers/arm/sp804_delay_timer.h | 47 +++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 drivers/arm/sp804/sp804_delay_timer.c create mode 100644 include/drivers/arm/sp804_delay_timer.h diff --git a/drivers/arm/sp804/sp804_delay_timer.c b/drivers/arm/sp804/sp804_delay_timer.c new file mode 100644 index 000000000..78940bfb7 --- /dev/null +++ b/drivers/arm/sp804/sp804_delay_timer.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 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 +#include +#include + +uintptr_t sp804_base_addr; + +#define SP804_TIMER1_LOAD (sp804_base_addr + 0x000) +#define SP804_TIMER1_VALUE (sp804_base_addr + 0x004) +#define SP804_TIMER1_CONTROL (sp804_base_addr + 0x008) +#define SP804_TIMER1_BGLOAD (sp804_base_addr + 0x018) + +#define TIMER_CTRL_ONESHOT (1 << 0) +#define TIMER_CTRL_32BIT (1 << 1) +#define TIMER_CTRL_DIV1 (0 << 2) +#define TIMER_CTRL_DIV16 (1 << 2) +#define TIMER_CTRL_DIV256 (2 << 2) +#define TIMER_CTRL_IE (1 << 5) +#define TIMER_CTRL_PERIODIC (1 << 6) +#define TIMER_CTRL_ENABLE (1 << 7) + +/******************************************************************** + * The SP804 timer delay function + ********************************************************************/ +uint32_t sp804_get_timer_value(void) +{ + return mmio_read_32(SP804_TIMER1_VALUE); +} + +/******************************************************************** + * Initialize the 1st timer in the SP804 dual timer with a base + * address and a timer ops + ********************************************************************/ +void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops) +{ + assert(base_addr != 0); + assert(ops != 0 && ops->get_timer_value == sp804_get_timer_value); + + sp804_base_addr = base_addr; + timer_init(ops); + + /* disable timer1 */ + mmio_write_32(SP804_TIMER1_CONTROL, 0); + mmio_write_32(SP804_TIMER1_LOAD, UINT32_MAX); + mmio_write_32(SP804_TIMER1_VALUE, UINT32_MAX); + + /* enable as a free running 32-bit counter */ + mmio_write_32(SP804_TIMER1_CONTROL, + TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE); +} diff --git a/include/drivers/arm/sp804_delay_timer.h b/include/drivers/arm/sp804_delay_timer.h new file mode 100644 index 000000000..5a335716c --- /dev/null +++ b/include/drivers/arm/sp804_delay_timer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef __SP804_DELAY_TIMER_H__ +#define __SP804_DELAY_TIMER_H__ + +#include +#include + + +uint32_t sp804_get_timer_value(void); + +void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops); + +#define sp804_timer_init(base_addr, clk_mult, clk_div) \ + sp804_timer_ops_init((base_addr), &(const timer_ops_t) \ + { sp804_get_timer_value, (clk_mult), (clk_div) }) + + +#endif /* __SP804_DELAY_TIMER_H__ */ From b49b3221900e4bc1d223227273815492da599f20 Mon Sep 17 00:00:00 2001 From: Ryan Harkin Date: Tue, 17 Mar 2015 14:54:01 +0000 Subject: [PATCH 3/3] FVP: Add SP804 delay timer Add SP804 delay timer support to the FVP BSP. This commit simply provides the 3 constants needed by the SP804 delay timer driver and calls sp804_timer_init() in bl2_platform_setup(). The BSP does not currently use the delay timer functions. Note that the FVP SP804 is a normal world accessible peripheral and should not be used by the secure world after transition to the normal world. Change-Id: I5f91d2ac9eb336fd81943b3bb388860dfb5f2b39 Co-authored-by: Dan Handley --- include/plat/arm/board/common/v2m_def.h | 3 +++ plat/arm/board/fvp/fvp_bl2_setup.c | 12 ++++++++++++ plat/arm/board/fvp/fvp_def.h | 3 +++ plat/arm/board/fvp/platform.mk | 4 +++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/plat/arm/board/common/v2m_def.h b/include/plat/arm/board/common/v2m_def.h index c16e9bc2f..7a4ef5add 100644 --- a/include/plat/arm/board/common/v2m_def.h +++ b/include/plat/arm/board/common/v2m_def.h @@ -105,6 +105,9 @@ #define V2M_IOFPGA_UART2_CLK_IN_HZ 24000000 #define V2M_IOFPGA_UART3_CLK_IN_HZ 24000000 +/* SP804 timer related constants */ +#define V2M_SP804_TIMER0_BASE 0x1C110000 +#define V2M_SP804_TIMER1_BASE 0x1C120000 #define V2M_MAP_FLASH0 MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c index a08f42c22..b1cdef487 100644 --- a/plat/arm/board/fvp/fvp_bl2_setup.c +++ b/plat/arm/board/fvp/fvp_bl2_setup.c @@ -29,6 +29,9 @@ */ #include +#include +#include +#include "fvp_def.h" #include "fvp_private.h" @@ -39,3 +42,12 @@ void bl2_early_platform_setup(meminfo_t *mem_layout) /* Initialize the platform config for future decision making */ fvp_config_setup(); } + +void bl2_platform_setup(void) +{ + arm_bl2_platform_setup(); + + /* Initialize delay timer driver using SP804 dual timer 0 */ + sp804_timer_init(V2M_SP804_TIMER0_BASE, + SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV); +} diff --git a/plat/arm/board/fvp/fvp_def.h b/plat/arm/board/fvp/fvp_def.h index 47723c78d..68ef297ce 100644 --- a/plat/arm/board/fvp/fvp_def.h +++ b/plat/arm/board/fvp/fvp_def.h @@ -83,6 +83,9 @@ /* FVP Power controller base address*/ #define PWRC_BASE 0x1c100000 +/* FVP SP804 timer frequency is 35 MHz*/ +#define SP804_TIMER_CLKMULT 35 +#define SP804_TIMER_CLKDIV 1 /******************************************************************************* * GIC-400 & interrupt handling related constants diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index cba18c799..949e6addf 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -46,7 +46,9 @@ BL1_SOURCES += drivers/io/io_semihosting.c \ plat/arm/board/fvp/fvp_bl1_setup.c \ plat/arm/board/fvp/fvp_io_storage.c -BL2_SOURCES += drivers/io/io_semihosting.c \ +BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c \ + drivers/io/io_semihosting.c \ + drivers/delay_timer/delay_timer.c \ lib/semihosting/semihosting.c \ lib/semihosting/aarch64/semihosting_call.S \ plat/arm/board/fvp/fvp_bl2_setup.c \