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