diff options
Diffstat (limited to 'arch/arm/mach-zynq/ps7_spl_init.c')
-rw-r--r-- | arch/arm/mach-zynq/ps7_spl_init.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/arch/arm/mach-zynq/ps7_spl_init.c b/arch/arm/mach-zynq/ps7_spl_init.c new file mode 100644 index 0000000000..6dc4e0364d --- /dev/null +++ b/arch/arm/mach-zynq/ps7_spl_init.c @@ -0,0 +1,148 @@ +/* + * (c) Copyright 2010-2017 Xilinx, Inc. All rights reserved. + * (c) Copyright 2016 Topic Embedded Products. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/io.h> +#include <asm/spl.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/ps7_init_gpl.h> + +__weak int ps7_init(void) +{ + /* + * This function is overridden by the one in + * board/xilinx/zynq/(platform)/ps7_init_gpl.c, if it exists. + */ + return 0; +} + +__weak int ps7_post_config(void) +{ + /* + * This function is overridden by the one in + * board/xilinx/zynq/(platform)/ps7_init_gpl.c, if it exists. + */ + return 0; +} + +/* For delay calculation using global registers*/ +#define SCU_GLOBAL_TIMER_COUNT_L32 0xF8F00200 +#define SCU_GLOBAL_TIMER_COUNT_U32 0xF8F00204 +#define SCU_GLOBAL_TIMER_CONTROL 0xF8F00208 +#define SCU_GLOBAL_TIMER_AUTO_INC 0xF8F00218 +#define APU_FREQ 666666666 + +#define PS7_MASK_POLL_TIME 100000000 + +/* IO accessors. No memory barriers desired. */ +static inline void iowrite(unsigned long val, unsigned long addr) +{ + __raw_writel(val, addr); +} + +static inline unsigned long ioread(unsigned long addr) +{ + return __raw_readl(addr); +} + +/* start timer */ +static void perf_start_clock(void) +{ + iowrite((1 << 0) | /* Timer Enable */ + (1 << 3) | /* Auto-increment */ + (0 << 8), /* Pre-scale */ + SCU_GLOBAL_TIMER_CONTROL); +} + +/* Compute mask for given delay in miliseconds*/ +static int get_number_of_cycles_for_delay(unsigned int delay) +{ + return (APU_FREQ / (2 * 1000)) * delay; +} + +/* stop timer */ +static void perf_disable_clock(void) +{ + iowrite(0, SCU_GLOBAL_TIMER_CONTROL); +} + +/* stop timer and reset timer count regs */ +static void perf_reset_clock(void) +{ + perf_disable_clock(); + iowrite(0, SCU_GLOBAL_TIMER_COUNT_L32); + iowrite(0, SCU_GLOBAL_TIMER_COUNT_U32); +} + +static void perf_reset_and_start_timer(void) +{ + perf_reset_clock(); + perf_start_clock(); +} + +int __weak ps7_config(unsigned long *ps7_config_init) +{ + unsigned long *ptr = ps7_config_init; + unsigned long opcode; + unsigned long addr; + unsigned long val; + unsigned long mask; + unsigned int numargs; + int i; + int delay; + + for (;;) { + opcode = ptr[0]; + if (opcode == OPCODE_EXIT) + return PS7_INIT_SUCCESS; + addr = (opcode & OPCODE_ADDRESS_MASK); + + switch (opcode & ~OPCODE_ADDRESS_MASK) { + case OPCODE_MASKWRITE: + numargs = 3; + mask = ptr[1]; + val = ptr[2]; + iowrite((ioread(addr) & ~mask) | (val & mask), addr); + break; + + case OPCODE_WRITE: + numargs = 2; + val = ptr[1]; + iowrite(val, addr); + break; + + case OPCODE_MASKPOLL: + numargs = 2; + mask = ptr[1]; + i = 0; + while (!(ioread(addr) & mask)) { + if (i == PS7_MASK_POLL_TIME) + return PS7_INIT_TIMEOUT; + i++; + } + break; + + case OPCODE_MASKDELAY: + numargs = 2; + mask = ptr[1]; + delay = get_number_of_cycles_for_delay(mask); + perf_reset_and_start_timer(); + while (ioread(addr) < delay) + ; + break; + + default: + return PS7_INIT_CORRUPT; + } + + ptr += numargs; + } +} + +unsigned long __weak __maybe_unused ps7GetSiliconVersion(void) +{ + return zynq_get_silicon_version(); +} |