From 8caa4a5390be3eb0ae8022b553c1c77ece9a6bfd Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 24 Sep 2012 14:08:19 +0200 Subject: [PATCH] zynq: Use new zynq arch core + Support new Xilinx Zynq platform Add timer driver. Signed-off-by: Michal Simek Acked-by: Marek Vasut CC: Joe Hershberger --- arch/arm/cpu/armv7/zynq/Makefile | 12 +- arch/arm/cpu/armv7/zynq/cpu.c | 32 +++++ arch/arm/cpu/armv7/zynq/timer.c | 171 +++++++++++-------------- arch/arm/cpu/armv7/zynq/xscutimer_hw.h | 76 ----------- include/configs/zynq_common.h | 12 +- include/configs/zynq_ep107.h | 2 + 6 files changed, 123 insertions(+), 182 deletions(-) create mode 100644 arch/arm/cpu/armv7/zynq/cpu.c delete mode 100644 arch/arm/cpu/armv7/zynq/xscutimer_hw.h diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile index 1392b1e47f1..499ace4a629 100644 --- a/arch/arm/cpu/armv7/zynq/Makefile +++ b/arch/arm/cpu/armv7/zynq/Makefile @@ -28,13 +28,17 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o -COBJS-y = timer.o +COBJS-y := timer.o +COBJS-y += cpu.o -OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) +COBJS := $(COBJS-y) -all: $(obj).depend $(START) $(LIB) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) -$(LIB): $(OBJS) +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) $(call cmd_link_o_target, $(OBJS)) ######################################################################### diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c new file mode 100644 index 00000000000..e06a3863a72 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/cpu.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 Michal Simek + * Copyright (C) 2012 Xilinx, Inc. All rights reserved. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include + +__weak void lowlevel_init(void) {} + +__weak void reset_cpu(ulong addr) +{ + while (1) + ; +} diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c index 160baf8136d..323e7b5a49b 100644 --- a/arch/arm/cpu/armv7/zynq/timer.c +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -1,4 +1,16 @@ /* + * Copyright (C) 2012 Michal Simek + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, + * * (C) Copyright 2003 * Texas Instruments * @@ -10,15 +22,6 @@ * Sysgo Real-Time Solutions, GmbH * Alex Zuepke * - * (C) Copyright 2002-2004 - * Gary Jennejohn, DENX Software Engineering, - * - * (C) Copyright 2004 - * Philippe Robin, ARM Ltd. - * - * (C) Copyright 2008 - * Guennadi Liakhovetki, DENX Software Engineering, - * * See file CREDITS for list of people who contributed to this * project. * @@ -39,135 +42,109 @@ */ #include -#include #include +#include -#include "xscutimer_hw.h" +DECLARE_GLOBAL_DATA_PTR; -#define TIMER_LOAD_VAL 0xFFFFFFFF +struct scu_timer { + u32 load; /* Timer Load Register */ + u32 counter; /* Timer Counter Register */ + u32 control; /* Timer Control Register */ +}; -/* Internal tick units */ -/* Last decremneter snapshot */ -static unsigned long lastdec; -/* Monotonic incrementing timer */ -static unsigned long long timestamp; +static struct scu_timer *timer_base = + (struct scu_timer *) CONFIG_SCUTIMER_BASEADDR; -static void XScuTimer_WriteReg (u32 Reg, u32 Data) -{ - *(volatile u32 *) (XPAR_SCUTIMER_BASEADDR + Reg) = Data; -} - -static u32 XScuTimer_ReadReg (u32 Reg) -{ - return *(u32 *) (XPAR_SCUTIMER_BASEADDR + Reg); -} - -#define XScuTimer_GetCounterValue() \ - XScuTimer_ReadReg(XSCUTIMER_COUNTER_OFFSET) +#define SCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /* Prescaler */ +#define SCUTIMER_CONTROL_PRESCALER_SHIFT 8 +#define SCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /* Auto-reload */ +#define SCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /* Timer enable */ +#define TIMER_LOAD_VAL 0xFFFFFFFF +#define TIMER_PRESCALE 255 +#define TIMER_TICK_HZ (CONFIG_CPU_FREQ_HZ / 2 / TIMER_PRESCALE) -int timer_init() +int timer_init(void) { - u32 val; + const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK | + (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | + SCUTIMER_CONTROL_ENABLE_MASK; - /* - * Load the timer counter register. - */ - XScuTimer_WriteReg(XSCUTIMER_LOAD_OFFSET, 0xFFFFFFFF); + /* Load the timer counter register */ + writel(0xFFFFFFFF, &timer_base->counter); /* - * Start the A9Timer device. + * Start the A9Timer device + * Enable Auto reload mode, Clear prescaler control bits + * Set prescaler value, Enable the decrementer */ - val = XScuTimer_ReadReg(XSCUTIMER_CONTROL_OFFSET); - /* Enable Auto reload mode. */ - val |= XSCUTIMER_CONTROL_AUTO_RELOAD_MASK; - /* Clear prescaler control bits */ - val &= ~XSCUTIMER_CONTROL_PRESCALER_MASK; - /* Set prescaler value */ - val |= (CONFIG_TIMER_PRESCALE << XSCUTIMER_CONTROL_PRESCALER_SHIFT); - /* Enable the decrementer */ - val |= XSCUTIMER_CONTROL_ENABLE_MASK; - XScuTimer_WriteReg(XSCUTIMER_CONTROL_OFFSET, val); - - /* This must not be called before relocation */ - /*reset_timer_masked();*/ + clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK, + emask); + + /* Reset time */ + gd->lastinc = readl(&timer_base->counter) / + (TIMER_TICK_HZ / CONFIG_SYS_HZ); + gd->tbl = 0; return 0; } -/* - * timer without interrupts - */ - /* * This function is derived from PowerPC code (read timebase as long long). * On ARM it just returns the timer value. */ -unsigned long long get_ticks(void) +ulong get_timer_masked(void) { ulong now; - now = XScuTimer_GetCounterValue() / (TIMER_TICK_HZ/CONFIG_SYS_HZ); + now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ); - if (lastdec >= now) { - /* normal mode */ - timestamp += lastdec - now; + if (gd->lastinc >= now) { + /* Normal mode */ + gd->tbl += gd->lastinc - now; } else { - /* we have an overflow ... */ - timestamp += lastdec + TIMER_LOAD_VAL - now; + /* We have an overflow ... */ + gd->tbl += gd->lastinc + TIMER_LOAD_VAL - now; } - lastdec = now; + gd->lastinc = now; - return timestamp; + return gd->tbl; } -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - return (ulong)CONFIG_SYS_HZ; -} - -void reset_timer_masked(void) +void __udelay(unsigned long usec) { - /* reset time */ - lastdec = XScuTimer_GetCounterValue() / (TIMER_TICK_HZ/CONFIG_SYS_HZ); - timestamp = 0; -} + unsigned long long tmp; + ulong tmo; -void reset_timer(void) -{ - reset_timer_masked(); -} + tmo = usec / (1000000 / CONFIG_SYS_HZ); + tmp = get_ticks() + tmo; /* Get current timestamp */ -ulong get_timer_masked(void) -{ - unsigned long long res = get_ticks(); - return res; + while (get_ticks() < tmp) { /* Loop till event */ + /* NOP */; + } } +/* Timer without interrupts */ ulong get_timer(ulong base) { return get_timer_masked() - base; } -void set_timer(ulong t) +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) { - timestamp = t; + return get_timer(0); } -void __udelay(unsigned long usec) +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) { - unsigned long long tmp; - ulong tmo; - - tmo = usec / (1000000 / CONFIG_SYS_HZ); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) { /* loop till event */ - /*NOP*/; - } + return CONFIG_SYS_HZ; } - diff --git a/arch/arm/cpu/armv7/zynq/xscutimer_hw.h b/arch/arm/cpu/armv7/zynq/xscutimer_hw.h deleted file mode 100644 index d42557706e7..00000000000 --- a/arch/arm/cpu/armv7/zynq/xscutimer_hw.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * (C) Copyright 2012 Xilinx - * - * Xilinx hardware interface to the Timer. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef XSCUTIMER_HW_H /* prevent circular inclusions */ -#define XSCUTIMER_HW_H /* by using protection macros */ - -#ifdef __cplusplus -extern "C" { -#endif - -/***************************** Include Files *********************************/ -#ifdef NOTNOW_BHILL -#include "xil_types.h" -#include "xil_io.h" -#endif -/************************** Constant Definitions *****************************/ - -/** @name Register Map - * Offsets of registers from the start of the device - * @{ - */ - -#define XSCUTIMER_LOAD_OFFSET 0x00 /**< Timer Load Register */ -#define XSCUTIMER_COUNTER_OFFSET 0x04 /**< Timer Counter Register */ -#define XSCUTIMER_CONTROL_OFFSET 0x08 /**< Timer Control Register */ -#define XSCUTIMER_ISR_OFFSET 0x0C /**< Timer Interrupt - Status Register */ -/* @} */ - -/** @name Timer Control register - * This register bits control the prescaler, Intr enable, - * auto-reload and timer enable. - * @{ - */ - -#define XSCUTIMER_CONTROL_PRESCALER_MASK 0x0000FF00 /**< Prescaler */ -#define XSCUTIMER_CONTROL_PRESCALER_SHIFT 8 -#define XSCUTIMER_CONTROL_IRQ_ENABLE_MASK 0x00000004 /**< Intr enable */ -#define XSCUTIMER_CONTROL_AUTO_RELOAD_MASK 0x00000002 /**< Auto-reload */ -#define XSCUTIMER_CONTROL_ENABLE_MASK 0x00000001 /**< Timer enable */ -/* @} */ - -/** @name Interrupt Status register - * This register indicates the Timer counter register has reached zero. - * @{ - */ - -#define XSCUTIMER_ISR_EVENT_FLAG_MASK 0x00000001 /**< Event flag */ -/*@}*/ - -/**************************** Type Definitions *******************************/ - -/***************** Macros (Inline Functions) Definitions *********************/ - -/************************** Function Prototypes ******************************/ - -/************************** Variable Definitions *****************************/ - -#ifdef __cplusplus -} -#endif - -#endif /* end of protection macro */ diff --git a/include/configs/zynq_common.h b/include/configs/zynq_common.h index d7fae391596..5aaf4fe05b0 100644 --- a/include/configs/zynq_common.h +++ b/include/configs/zynq_common.h @@ -63,6 +63,13 @@ # define CONFIG_PHY_MARVELL #endif +/* SCU timer address is hardcoded */ +#define CONFIG_SCUTIMER_BASEADDR 0xF8F00600 +#ifndef CONFIG_CPU_FREQ_HZ +#define CONFIG_CPU_FREQ_HZ 800000000 +#endif +#define CONFIG_SYS_HZ 1000 + #include #define CONFIG_SYS_TEXT_BASE 0x04000000 @@ -155,11 +162,6 @@ #define CONFIG_SYS_CBSIZE 2048 #define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16) -/* HW to use */ -#define TIMER_INPUT_CLOCK (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ / 2) -#define CONFIG_TIMER_PRESCALE 255 -#define TIMER_TICK_HZ (TIMER_INPUT_CLOCK / CONFIG_TIMER_PRESCALE) -#define CONFIG_SYS_HZ 1000 #define CONFIG_SYS_LOAD_ADDR 0 /* default? */ diff --git a/include/configs/zynq_ep107.h b/include/configs/zynq_ep107.h index 2411f7de22f..4742041183d 100644 --- a/include/configs/zynq_ep107.h +++ b/include/configs/zynq_ep107.h @@ -24,6 +24,8 @@ #define CONFIG_ZYNQ_GEM0 #define CONFIG_PHY_ADDR 23 +#define CONFIG_CPU_FREQ_HZ 12500000 + #include #undef CONFIG_ZYNQ_XIL_LQSPI -- 2.47.3