Mike Looijmans | 5ae48b1 | 2016-09-30 08:13:13 +0200 | [diff] [blame^] | 1 | /* |
| 2 | * (c) Copyright 2010-2014 Xilinx, Inc. All rights reserved. |
| 3 | * (c) Copyright 2016 Topic Embedded Products. |
| 4 | * |
| 5 | * SPDX-License-Identifier: GPL-2.0+ |
| 6 | */ |
| 7 | |
| 8 | #include "ps7_init_gpl.h" |
| 9 | #include <asm/io.h> |
| 10 | |
| 11 | /* For delay calculation using global registers*/ |
| 12 | #define SCU_GLOBAL_TIMER_COUNT_L32 0xF8F00200 |
| 13 | #define SCU_GLOBAL_TIMER_COUNT_U32 0xF8F00204 |
| 14 | #define SCU_GLOBAL_TIMER_CONTROL 0xF8F00208 |
| 15 | #define SCU_GLOBAL_TIMER_AUTO_INC 0xF8F00218 |
| 16 | #define APU_FREQ 666666666 |
| 17 | |
| 18 | #define PS7_MASK_POLL_TIME 100000000 |
| 19 | |
| 20 | /* IO accessors. No memory barriers desired. */ |
| 21 | static inline void iowrite(unsigned long val, unsigned long addr) |
| 22 | { |
| 23 | __raw_writel(val, addr); |
| 24 | } |
| 25 | |
| 26 | static inline unsigned long ioread(unsigned long addr) |
| 27 | { |
| 28 | return __raw_readl(addr); |
| 29 | } |
| 30 | |
| 31 | /* start timer */ |
| 32 | static void perf_start_clock(void) |
| 33 | { |
| 34 | iowrite((1 << 0) | /* Timer Enable */ |
| 35 | (1 << 3) | /* Auto-increment */ |
| 36 | (0 << 8), /* Pre-scale */ |
| 37 | SCU_GLOBAL_TIMER_CONTROL); |
| 38 | } |
| 39 | |
| 40 | /* Compute mask for given delay in miliseconds*/ |
| 41 | static int get_number_of_cycles_for_delay(unsigned int delay) |
| 42 | { |
| 43 | return (APU_FREQ / (2 * 1000)) * delay; |
| 44 | } |
| 45 | |
| 46 | /* stop timer */ |
| 47 | static void perf_disable_clock(void) |
| 48 | { |
| 49 | iowrite(0, SCU_GLOBAL_TIMER_CONTROL); |
| 50 | } |
| 51 | |
| 52 | /* stop timer and reset timer count regs */ |
| 53 | static void perf_reset_clock(void) |
| 54 | { |
| 55 | perf_disable_clock(); |
| 56 | iowrite(0, SCU_GLOBAL_TIMER_COUNT_L32); |
| 57 | iowrite(0, SCU_GLOBAL_TIMER_COUNT_U32); |
| 58 | } |
| 59 | |
| 60 | static void perf_reset_and_start_timer(void) |
| 61 | { |
| 62 | perf_reset_clock(); |
| 63 | perf_start_clock(); |
| 64 | } |
| 65 | |
| 66 | int ps7_config(unsigned long *ps7_config_init) |
| 67 | { |
| 68 | unsigned long *ptr = ps7_config_init; |
| 69 | unsigned long opcode; |
| 70 | unsigned long addr; |
| 71 | unsigned long val; |
| 72 | unsigned long mask; |
| 73 | unsigned int numargs; |
| 74 | int i; |
| 75 | int delay; |
| 76 | |
| 77 | for (;;) { |
| 78 | opcode = ptr[0]; |
| 79 | if (opcode == OPCODE_EXIT) |
| 80 | return PS7_INIT_SUCCESS; |
| 81 | addr = (opcode & OPCODE_ADDRESS_MASK); |
| 82 | |
| 83 | switch (opcode & ~OPCODE_ADDRESS_MASK) { |
| 84 | case OPCODE_MASKWRITE: |
| 85 | numargs = 3; |
| 86 | mask = ptr[1]; |
| 87 | val = ptr[2]; |
| 88 | iowrite((ioread(addr) & ~mask) | (val & mask), addr); |
| 89 | break; |
| 90 | |
| 91 | case OPCODE_MASKPOLL: |
| 92 | numargs = 2; |
| 93 | mask = ptr[1]; |
| 94 | i = 0; |
| 95 | while (!(ioread(addr) & mask)) { |
| 96 | if (i == PS7_MASK_POLL_TIME) |
| 97 | return PS7_INIT_TIMEOUT; |
| 98 | i++; |
| 99 | } |
| 100 | break; |
| 101 | |
| 102 | case OPCODE_MASKDELAY: |
| 103 | numargs = 2; |
| 104 | mask = ptr[1]; |
| 105 | delay = get_number_of_cycles_for_delay(mask); |
| 106 | perf_reset_and_start_timer(); |
| 107 | while (ioread(addr) < delay) |
| 108 | ; |
| 109 | break; |
| 110 | |
| 111 | default: |
| 112 | return PS7_INIT_CORRUPT; |
| 113 | } |
| 114 | |
| 115 | ptr += numargs; |
| 116 | } |
| 117 | } |