// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2020-2021 Intel Corporation * */ #include #include #include #include #include "log.h" static enum endianness check_endianness(u32 handoff) { switch (handoff) { case SOC64_HANDOFF_MAGIC_BOOT: case SOC64_HANDOFF_MAGIC_MUX: case SOC64_HANDOFF_MAGIC_IOCTL: case SOC64_HANDOFF_MAGIC_FPGA: case SOC64_HANDOFF_MAGIC_DELAY: case SOC64_HANDOFF_MAGIC_CLOCK: case SOC64_HANDOFF_MAGIC_MISC: return BIG_ENDIAN; #if IS_ENABLED(CONFIG_TARGET_SOCFPGA_N5X) case SOC64_HANDOFF_DDR_UMCTL2_MAGIC: debug("%s: umctl2 handoff data\n", __func__); return LITTLE_ENDIAN; case SOC64_HANDOFF_DDR_PHY_MAGIC: debug("%s: PHY handoff data\n", __func__); return LITTLE_ENDIAN; case SOC64_HANDOFF_DDR_PHY_INIT_ENGINE_MAGIC: debug("%s: PHY engine handoff data\n", __func__); return LITTLE_ENDIAN; #endif default: debug("%s: Unknown endianness!!\n", __func__); return UNKNOWN_ENDIANNESS; } } static int getting_endianness(void *handoff_address, enum endianness *endian_t) { /* Checking handoff data is little endian ? */ *endian_t = check_endianness(readl(handoff_address)); if (*endian_t == UNKNOWN_ENDIANNESS) { /* Trying to check handoff data is big endian? */ *endian_t = check_endianness(swab32(readl(handoff_address))); if (*endian_t == UNKNOWN_ENDIANNESS) { debug("%s: Cannot find HANDOFF MAGIC ", __func__); debug("at addr 0x%p\n", (u32 *)handoff_address); return -EPERM; } } return 0; } int socfpga_get_handoff_size(void *handoff_address) { u32 size; int ret; enum endianness endian_t; ret = getting_endianness(handoff_address, &endian_t); if (ret) return ret; size = readl(handoff_address + SOC64_HANDOFF_OFFSET_LENGTH); if (endian_t == BIG_ENDIAN) size = swab32(size); size = (size - SOC64_HANDOFF_OFFSET_DATA) / sizeof(u32); debug("%s: handoff address = 0x%p handoff size = 0x%08x\n", __func__, (u32 *)handoff_address, size); return size; } int socfpga_handoff_read(void *handoff_address, void *table, u32 table_len) { u32 temp; u32 *table_x32 = table; u32 i = 0; int ret; enum endianness endian_t; ret = getting_endianness(handoff_address, &endian_t); if (ret) return ret; temp = readl(handoff_address + SOC64_HANDOFF_OFFSET_DATA + (i * sizeof(u32))); if (endian_t == BIG_ENDIAN) { debug("%s: Handoff addr = 0x%p ", __func__, (u32 *)handoff_address); debug("Handoff table address = 0x%p ", table_x32); debug("table length = 0x%x\n", table_len); debug("%s: handoff data =\n{\n", __func__); *table_x32 = swab32(temp); } else if (endian_t == LITTLE_ENDIAN) { debug(" {\n"); *table_x32 = temp; } debug(" No.%d Addr 0x%08x: ", i, *table_x32); for (i = 1; i < table_len; i++) { table_x32++; temp = readl(handoff_address + SOC64_HANDOFF_OFFSET_DATA + (i * sizeof(u32))); if (endian_t == BIG_ENDIAN) *table_x32 = swab32(temp); else if (endian_t == LITTLE_ENDIAN) *table_x32 = temp; if (!(i % 2)) debug(" No.%d Addr 0x%08x: ", i, *table_x32); else debug(" 0x%08x\n", *table_x32); } debug("\n}\n"); return 0; }