Michal Simek | 85dc76a | 2017-11-08 16:14:47 +0100 | [diff] [blame] | 1 | /* |
| 2 | * (c) Copyright 2010-2017 Xilinx, Inc. All rights reserved. |
Michal Simek | 351ee11 | 2017-11-10 09:47:28 +0100 | [diff] [blame] | 3 | * (c) Copyright 2016 Topic Embedded Products. |
Michal Simek | 85dc76a | 2017-11-08 16:14:47 +0100 | [diff] [blame] | 4 | * |
| 5 | * SPDX-License-Identifier: GPL-2.0+ |
| 6 | */ |
| 7 | |
| 8 | #include <asm/io.h> |
| 9 | #include <asm/spl.h> |
Michal Simek | aac307b | 2017-11-10 11:06:02 +0100 | [diff] [blame^] | 10 | #include <asm/arch/sys_proto.h> |
Michal Simek | 85dc76a | 2017-11-08 16:14:47 +0100 | [diff] [blame] | 11 | #include <asm/arch/ps7_init_gpl.h> |
| 12 | |
| 13 | __weak int ps7_init(void) |
| 14 | { |
| 15 | /* |
| 16 | * This function is overridden by the one in |
| 17 | * board/xilinx/zynq/(platform)/ps7_init_gpl.c, if it exists. |
| 18 | */ |
| 19 | return 0; |
| 20 | } |
| 21 | |
| 22 | __weak int ps7_post_config(void) |
| 23 | { |
| 24 | /* |
| 25 | * This function is overridden by the one in |
| 26 | * board/xilinx/zynq/(platform)/ps7_init_gpl.c, if it exists. |
| 27 | */ |
| 28 | return 0; |
| 29 | } |
Michal Simek | 351ee11 | 2017-11-10 09:47:28 +0100 | [diff] [blame] | 30 | |
| 31 | /* For delay calculation using global registers*/ |
| 32 | #define SCU_GLOBAL_TIMER_COUNT_L32 0xF8F00200 |
| 33 | #define SCU_GLOBAL_TIMER_COUNT_U32 0xF8F00204 |
| 34 | #define SCU_GLOBAL_TIMER_CONTROL 0xF8F00208 |
| 35 | #define SCU_GLOBAL_TIMER_AUTO_INC 0xF8F00218 |
| 36 | #define APU_FREQ 666666666 |
| 37 | |
| 38 | #define PS7_MASK_POLL_TIME 100000000 |
| 39 | |
| 40 | /* IO accessors. No memory barriers desired. */ |
| 41 | static inline void iowrite(unsigned long val, unsigned long addr) |
| 42 | { |
| 43 | __raw_writel(val, addr); |
| 44 | } |
| 45 | |
| 46 | static inline unsigned long ioread(unsigned long addr) |
| 47 | { |
| 48 | return __raw_readl(addr); |
| 49 | } |
| 50 | |
| 51 | /* start timer */ |
| 52 | static void perf_start_clock(void) |
| 53 | { |
| 54 | iowrite((1 << 0) | /* Timer Enable */ |
| 55 | (1 << 3) | /* Auto-increment */ |
| 56 | (0 << 8), /* Pre-scale */ |
| 57 | SCU_GLOBAL_TIMER_CONTROL); |
| 58 | } |
| 59 | |
| 60 | /* Compute mask for given delay in miliseconds*/ |
| 61 | static int get_number_of_cycles_for_delay(unsigned int delay) |
| 62 | { |
| 63 | return (APU_FREQ / (2 * 1000)) * delay; |
| 64 | } |
| 65 | |
| 66 | /* stop timer */ |
| 67 | static void perf_disable_clock(void) |
| 68 | { |
| 69 | iowrite(0, SCU_GLOBAL_TIMER_CONTROL); |
| 70 | } |
| 71 | |
| 72 | /* stop timer and reset timer count regs */ |
| 73 | static void perf_reset_clock(void) |
| 74 | { |
| 75 | perf_disable_clock(); |
| 76 | iowrite(0, SCU_GLOBAL_TIMER_COUNT_L32); |
| 77 | iowrite(0, SCU_GLOBAL_TIMER_COUNT_U32); |
| 78 | } |
| 79 | |
| 80 | static void perf_reset_and_start_timer(void) |
| 81 | { |
| 82 | perf_reset_clock(); |
| 83 | perf_start_clock(); |
| 84 | } |
| 85 | |
| 86 | int __weak ps7_config(unsigned long *ps7_config_init) |
| 87 | { |
| 88 | unsigned long *ptr = ps7_config_init; |
| 89 | unsigned long opcode; |
| 90 | unsigned long addr; |
| 91 | unsigned long val; |
| 92 | unsigned long mask; |
| 93 | unsigned int numargs; |
| 94 | int i; |
| 95 | int delay; |
| 96 | |
| 97 | for (;;) { |
| 98 | opcode = ptr[0]; |
| 99 | if (opcode == OPCODE_EXIT) |
| 100 | return PS7_INIT_SUCCESS; |
| 101 | addr = (opcode & OPCODE_ADDRESS_MASK); |
| 102 | |
| 103 | switch (opcode & ~OPCODE_ADDRESS_MASK) { |
| 104 | case OPCODE_MASKWRITE: |
| 105 | numargs = 3; |
| 106 | mask = ptr[1]; |
| 107 | val = ptr[2]; |
| 108 | iowrite((ioread(addr) & ~mask) | (val & mask), addr); |
| 109 | break; |
| 110 | |
| 111 | case OPCODE_MASKPOLL: |
| 112 | numargs = 2; |
| 113 | mask = ptr[1]; |
| 114 | i = 0; |
| 115 | while (!(ioread(addr) & mask)) { |
| 116 | if (i == PS7_MASK_POLL_TIME) |
| 117 | return PS7_INIT_TIMEOUT; |
| 118 | i++; |
| 119 | } |
| 120 | break; |
| 121 | |
| 122 | case OPCODE_MASKDELAY: |
| 123 | numargs = 2; |
| 124 | mask = ptr[1]; |
| 125 | delay = get_number_of_cycles_for_delay(mask); |
| 126 | perf_reset_and_start_timer(); |
| 127 | while (ioread(addr) < delay) |
| 128 | ; |
| 129 | break; |
| 130 | |
| 131 | default: |
| 132 | return PS7_INIT_CORRUPT; |
| 133 | } |
| 134 | |
| 135 | ptr += numargs; |
| 136 | } |
| 137 | } |
Michal Simek | aac307b | 2017-11-10 11:06:02 +0100 | [diff] [blame^] | 138 | |
| 139 | unsigned long __weak __maybe_unused ps7GetSiliconVersion(void) |
| 140 | { |
| 141 | return zynq_get_silicon_version(); |
| 142 | } |