diff options
Diffstat (limited to 'arch/arm/cpu/armv7/zynq')
-rw-r--r-- | arch/arm/cpu/armv7/zynq/Makefile | 52 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/zynq/cpu.c | 57 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/zynq/slcr.c | 124 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/zynq/timer.c | 179 |
4 files changed, 412 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/zynq/Makefile b/arch/arm/cpu/armv7/zynq/Makefile new file mode 100644 index 0000000..388085d --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2008 +# Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y := timer.o +COBJS-y += cpu.o +COBJS-y += slcr.o + +COBJS := $(COBJS-y) + +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/zynq/cpu.c b/arch/arm/cpu/armv7/zynq/cpu.c new file mode 100644 index 0000000..e8f4c19 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/cpu.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> + * 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 <common.h> +#include <asm/io.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/hardware.h> + +void lowlevel_init(void) +{ + zynq_slcr_unlock(); + /* remap DDR to zero, FILTERSTART */ + writel(0, &scu_base->filter_start); + + /* Device config APB, unlock the PCAP */ + writel(0x757BDF0D, &devcfg_base->unlock); + writel(0xFFFFFFFF, &devcfg_base->rom_shadow); + + /* OCM_CFG, Mask out the ROM, map ram into upper addresses */ + writel(0x1F, &slcr_base->ocm_cfg); + /* FPGA_RST_CTRL, clear resets on AXI fabric ports */ + writel(0x0, &slcr_base->fpga_rst_ctrl); + /* TZ_DDR_RAM, Set DDR trust zone non-secure */ + writel(0xFFFFFFFF, &slcr_base->trust_zone); + /* Set urgent bits with register */ + writel(0x0, &slcr_base->ddr_urgent_sel); + /* Urgent write, ports S2/S3 */ + writel(0xC, &slcr_base->ddr_urgent); + + zynq_slcr_lock(); +} + +void reset_cpu(ulong addr) +{ + zynq_slcr_cpu_reset(); + while (1) + ; +} diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c new file mode 100644 index 0000000..52048c6 --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/slcr.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2013 Xilinx Inc. + * + * 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 <common.h> +#include <asm/io.h> +#include <malloc.h> +#include <asm/arch/hardware.h> + +#define SLCR_LOCK_MAGIC 0x767B +#define SLCR_UNLOCK_MAGIC 0xDF0D + +#define SLCR_IDCODE_MASK 0x1F000 +#define SLCR_IDCODE_SHIFT 12 + +static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */ + +void zynq_slcr_lock(void) +{ + if (!slcr_lock) + writel(SLCR_LOCK_MAGIC, &slcr_base->slcr_lock); +} + +void zynq_slcr_unlock(void) +{ + if (slcr_lock) + writel(SLCR_UNLOCK_MAGIC, &slcr_base->slcr_unlock); +} + +/* Reset the entire system */ +void zynq_slcr_cpu_reset(void) +{ + /* + * Unlock the SLCR then reset the system. + * Note that this seems to require raw i/o + * functions or there's a lockup? + */ + zynq_slcr_unlock(); + + /* + * Clear 0x0F000000 bits of reboot status register to workaround + * the FSBL not loading the bitstream after soft-reboot + * This is a temporary solution until we know more. + */ + clrbits_le32(&slcr_base->reboot_status, 0xF000000); + + writel(1, &slcr_base->pss_rst_ctrl); +} + +/* Setup clk for network */ +void zynq_slcr_gem_clk_setup(u32 gem_id, u32 rclk, u32 clk) +{ + zynq_slcr_unlock(); + + if (gem_id > 1) { + printf("Non existing GEM id %d\n", gem_id); + goto out; + } + + if (gem_id) { + /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ + writel(clk, &slcr_base->gem1_clk_ctrl); + /* Configure GEM_RCLK_CTRL */ + writel(rclk, &slcr_base->gem1_rclk_ctrl); + } else { + /* Set divisors for appropriate frequency in GEM_CLK_CTRL */ + writel(clk, &slcr_base->gem0_clk_ctrl); + /* Configure GEM_RCLK_CTRL */ + writel(rclk, &slcr_base->gem0_rclk_ctrl); + } + +out: + zynq_slcr_lock(); +} + +void zynq_slcr_devcfg_disable(void) +{ + zynq_slcr_unlock(); + + /* Disable AXI interface */ + writel(0xFFFFFFFF, &slcr_base->fpga_rst_ctrl); + + /* Set Level Shifters DT618760 */ + writel(0xA, &slcr_base->lvl_shftr_en); + + zynq_slcr_lock(); +} + +void zynq_slcr_devcfg_enable(void) +{ + zynq_slcr_unlock(); + + /* Set Level Shifters DT618760 */ + writel(0xF, &slcr_base->lvl_shftr_en); + + /* Disable AXI interface */ + writel(0x0, &slcr_base->fpga_rst_ctrl); + + zynq_slcr_lock(); +} + +u32 zynq_slcr_get_idcode(void) +{ + return (readl(&slcr_base->pss_idcode) & SLCR_IDCODE_MASK) >> + SLCR_IDCODE_SHIFT; +} diff --git a/arch/arm/cpu/armv7/zynq/timer.c b/arch/arm/cpu/armv7/zynq/timer.c new file mode 100644 index 0000000..8c4357d --- /dev/null +++ b/arch/arm/cpu/armv7/zynq/timer.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2012 Michal Simek <monstr@monstr.eu> + * Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved. + * + * (C) Copyright 2008 + * Guennadi Liakhovetki, DENX Software Engineering, <lg@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * 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 <common.h> +#include <div64.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct scu_timer { + u32 load; /* Timer Load Register */ + u32 counter; /* Timer Counter Register */ + u32 control; /* Timer Control Register */ +}; + +static struct scu_timer *timer_base = + (struct scu_timer *)ZYNQ_SCUTIMER_BASEADDR; + +#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(void) +{ + const u32 emask = SCUTIMER_CONTROL_AUTO_RELOAD_MASK | + (TIMER_PRESCALE << SCUTIMER_CONTROL_PRESCALER_SHIFT) | + SCUTIMER_CONTROL_ENABLE_MASK; + + /* Load the timer counter register */ + writel(0xFFFFFFFF, &timer_base->counter); + + /* + * Start the A9Timer device + * Enable Auto reload mode, Clear prescaler control bits + * Set prescaler value, Enable the decrementer + */ + clrsetbits_le32(&timer_base->control, SCUTIMER_CONTROL_PRESCALER_MASK, + emask); + + /* Reset time */ + gd->arch.lastinc = readl(&timer_base->counter) / + (TIMER_TICK_HZ / CONFIG_SYS_HZ); + gd->arch.tbl = 0; + + return 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +ulong get_timer_masked(void) +{ + ulong now; + + now = readl(&timer_base->counter) / (TIMER_TICK_HZ / CONFIG_SYS_HZ); + + if (gd->arch.lastinc >= now) { + /* Normal mode */ + gd->arch.tbl += gd->arch.lastinc - now; + } else { + /* We have an overflow ... */ + gd->arch.tbl += gd->arch.lastinc + TIMER_LOAD_VAL - now; + } + gd->arch.lastinc = now; + + return gd->arch.tbl; +} + +void __udelay(unsigned long usec) +{ + u32 countticks; + u32 timeend; + u32 timediff; + u32 timenow; + + if (usec == 0) + return; + + countticks = (u32) (((unsigned long long) TIMER_TICK_HZ * usec) / + 1000000); + + /* decrementing timer */ + timeend = readl(&timer_base->counter) - countticks; + +#if TIMER_LOAD_VAL != 0xFFFFFFFF + /* do not manage multiple overflow */ + if (countticks >= TIMER_LOAD_VAL) + countticks = TIMER_LOAD_VAL - 1; +#endif + + do { + timenow = readl(&timer_base->counter); + + if (timenow >= timeend) { + /* normal case */ + timediff = timenow - timeend; + } else { + if ((TIMER_LOAD_VAL - timeend + timenow) <= + countticks) { + /* overflow */ + timediff = TIMER_LOAD_VAL - timeend + timenow; + } else { + /* missed the exact match */ + break; + } + } + } while (timediff > 0); +} + +/* Timer without interrupts */ +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* + * 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) +{ + return get_timer(0); +} + +/* + * 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 CONFIG_SYS_HZ; +} |