1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020-2021 Intel Corporation <www.intel.com> 4 * 5 */ 6 7#include <asm/arch/handoff_soc64.h> 8#include <asm/io.h> 9#include <common.h> 10#include <errno.h> 11#include "log.h" 12 13#ifndef __ASSEMBLY__ 14enum endianness { 15 LITTLE_ENDIAN = 0, 16 BIG_ENDIAN, 17 UNKNOWN_ENDIANNESS 18}; 19#endif 20 21static enum endianness check_endianness(u32 handoff) 22{ 23 switch (handoff) { 24 case SOC64_HANDOFF_MAGIC_BOOT: 25 case SOC64_HANDOFF_MAGIC_MUX: 26 case SOC64_HANDOFF_MAGIC_IOCTL: 27 case SOC64_HANDOFF_MAGIC_FPGA: 28 case SOC64_HANDOFF_MAGIC_DELAY: 29 case SOC64_HANDOFF_MAGIC_CLOCK: 30 case SOC64_HANDOFF_MAGIC_MISC: 31 return BIG_ENDIAN; 32#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) 33 case SOC64_HANDOFF_DDR_UMCTL2_MAGIC: 34 debug("%s: umctl2 handoff data\n", __func__); 35 return LITTLE_ENDIAN; 36 case SOC64_HANDOFF_DDR_PHY_MAGIC: 37 debug("%s: PHY handoff data\n", __func__); 38 return LITTLE_ENDIAN; 39 case SOC64_HANDOFF_DDR_PHY_INIT_ENGINE_MAGIC: 40 debug("%s: PHY engine handoff data\n", __func__); 41 return LITTLE_ENDIAN; 42#endif 43 default: 44 debug("%s: Unknown endianness!!\n", __func__); 45 return UNKNOWN_ENDIANNESS; 46 } 47} 48 49static int getting_endianness(void *handoff_address, enum endianness *endian_t) 50{ 51 /* Checking handoff data is little endian ? */ 52 *endian_t = check_endianness(readl(handoff_address)); 53 54 if (*endian_t == UNKNOWN_ENDIANNESS) { 55 /* Trying to check handoff data is big endian? */ 56 *endian_t = check_endianness(swab32(readl(handoff_address))); 57 if (*endian_t == UNKNOWN_ENDIANNESS) { 58 debug("%s: Cannot find HANDOFF MAGIC ", __func__); 59 debug("at addr 0x%p\n", (u32 *)handoff_address); 60 return -EPERM; 61 } 62 } 63 64 return 0; 65} 66 67int socfpga_get_handoff_size(void *handoff_address) 68{ 69 u32 size; 70 int ret; 71 enum endianness endian_t; 72 73 ret = getting_endianness(handoff_address, &endian_t); 74 if (ret) 75 return ret; 76 77 size = readl(handoff_address + SOC64_HANDOFF_OFFSET_LENGTH); 78 if (endian_t == BIG_ENDIAN) 79 size = swab32(size); 80 81 size = (size - SOC64_HANDOFF_OFFSET_DATA) / sizeof(u32); 82 83 debug("%s: handoff address = 0x%p handoff size = 0x%08x\n", __func__, 84 (u32 *)handoff_address, size); 85 86 return size; 87} 88 89int socfpga_handoff_read(void *handoff_address, void *table, u32 table_len) 90{ 91 u32 temp; 92 u32 *table_x32 = table; 93 u32 i = 0; 94 int ret; 95 enum endianness endian_t; 96 97 ret = getting_endianness(handoff_address, &endian_t); 98 if (ret) 99 return ret; 100 101 temp = readl(handoff_address + SOC64_HANDOFF_OFFSET_DATA + 102 (i * sizeof(u32))); 103 104 if (endian_t == BIG_ENDIAN) { 105 debug("%s: Handoff addr = 0x%p ", __func__, (u32 *)handoff_address); 106 debug("Handoff table address = 0x%p ", table_x32); 107 debug("table length = 0x%x\n", table_len); 108 debug("%s: handoff data =\n{\n", __func__); 109 *table_x32 = swab32(temp); 110 } else if (endian_t == LITTLE_ENDIAN) { 111 debug(" {\n"); 112 *table_x32 = temp; 113 } 114 115 debug(" No.%d Addr 0x%08x: ", i, *table_x32); 116 117 for (i = 1; i < table_len; i++) { 118 table_x32++; 119 120 temp = readl(handoff_address + 121 SOC64_HANDOFF_OFFSET_DATA + 122 (i * sizeof(u32))); 123 124 if (endian_t == BIG_ENDIAN) 125 *table_x32 = swab32(temp); 126 else if (endian_t == LITTLE_ENDIAN) 127 *table_x32 = temp; 128 129 if (!(i % 2)) 130 debug(" No.%d Addr 0x%08x: ", i, 131 *table_x32); 132 else 133 debug(" 0x%08x\n", *table_x32); 134 } 135 debug("\n}\n"); 136 137 return 0; 138} 139