aboutsummaryrefslogtreecommitdiff
path: root/src/vendorcode/cavium/bdk/libbdk-hal
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/cavium/bdk/libbdk-hal')
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c221
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c1946
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c197
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c270
-rw-r--r--src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c318
5 files changed, 2952 insertions, 0 deletions
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c
new file mode 100644
index 0000000000..f81285dffd
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c
@@ -0,0 +1,221 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+* reserved.
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+*
+* * Neither the name of Cavium Inc. nor the names of
+* its contributors may be used to endorse or promote products
+* derived from this software without specific prior written
+* permission.
+*
+* This Software, including technical data, may be subject to U.S. export
+* control laws, including the U.S. Export Administration Act and its
+* associated regulations, and may be subject to export or import
+* regulations in other countries.
+*
+* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
+* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
+* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
+* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
+* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
+* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
+* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
+* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+***********************license end**************************************/
+#include <bdk.h>
+#include "libbdk-arch/bdk-csrs-gti.h"
+#include "libbdk-arch/bdk-csrs-ocx.h"
+
+/**
+ * Called in __bdk_init to setup the global timer
+ */
+void bdk_clock_setup(bdk_node_t node)
+{
+ const bdk_node_t local_node = bdk_numa_local();
+
+ /* Check if the counter was already setup */
+ BDK_CSR_INIT(cntcr, node, BDK_GTI_CC_CNTCR);
+ if (cntcr.s.en)
+ return;
+
+ /* Configure GTI to tick at BDK_GTI_RATE */
+ uint64_t sclk = bdk_clock_get_rate(node, BDK_CLOCK_SCLK);
+ uint64_t inc = (BDK_GTI_RATE << 32) / sclk;
+ BDK_CSR_WRITE(node, BDK_GTI_CC_CNTRATE, inc);
+ BDK_CSR_WRITE(node, BDK_GTI_CTL_CNTFRQ, BDK_GTI_RATE);
+ cntcr.s.en = 1;
+ if (node != local_node)
+ {
+ /* Synchronize with local node. Very simple set of counter, will be
+ off a little */
+ BDK_CSR_WRITE(node, BDK_GTI_CC_CNTCV, bdk_clock_get_count(BDK_CLOCK_TIME));
+ }
+ /* Enable the counter */
+ BDK_CSR_WRITE(node, BDK_GTI_CC_CNTCR, cntcr.u);
+ BDK_CSR_READ(node, BDK_GTI_CC_CNTCR);
+
+ if (node != local_node)
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ {
+ /* Assume the delay in each direction is the same, sync the counters */
+ int64_t local1 = bdk_clock_get_count(BDK_CLOCK_TIME);
+ int64_t remote = BDK_CSR_READ(node, BDK_GTI_CC_CNTCV);
+ int64_t local2 = bdk_clock_get_count(BDK_CLOCK_TIME);
+ int64_t expected = (local1 + local2) / 2;
+ BDK_CSR_WRITE(node, BDK_GTI_CC_CNTADD, expected - remote);
+ BDK_TRACE(INIT, "N%d.GTI: Clock synchronization with master\n"
+ " expected: %ld, remote %ld\n"
+ " Counter correction: %ld\n",
+ node, expected, remote, expected - remote);
+ }
+ else
+ {
+ /* Due to errata TBD, we need to use OCX_PP_CMD to write
+ GTI_CC_CNTMB in order for timestamps to update. These constants
+ are the addresses we need for both local and remote GTI_CC_CNTMB */
+ const uint64_t LOCAL_GTI_CC_CNTMB = bdk_numa_get_address(local_node, BDK_GTI_CC_CNTMB);
+ const uint64_t REMOTE_GTI_CC_CNTMB = bdk_numa_get_address(node, BDK_GTI_CC_CNTMB);
+ /* Build partial OCX_PP_CMD command used for writes. Address will
+ be filled later */
+ BDK_CSR_DEFINE(pp_cmd, BDK_OCX_PP_CMD);
+ pp_cmd.u = 0;
+ pp_cmd.s.wr_mask = 0xff;
+
+ const int NUM_AVERAGE = 16; /* Choose a power of two to avoid division */
+ int64_t local_to_remote_sum = 0;
+ int64_t local_to_remote_min = 1000000;
+ int64_t local_to_remote_max = -1000000;
+ int64_t remote_to_local_sum = 0;
+ int64_t remote_to_local_min = 1000000;
+ int64_t remote_to_local_max = -1000000;
+ for (int loop = 0; loop < NUM_AVERAGE; loop++)
+ {
+ /* Perform a write to the remote GTI_CC_CNTMB to cause timestamp
+ update. We don't care about the value actually written */
+ pp_cmd.s.addr = REMOTE_GTI_CC_CNTMB;
+ BDK_CSR_WRITE(local_node, BDK_OCX_PP_CMD, pp_cmd.u);
+ BDK_CSR_READ(local_node, BDK_OCX_PP_CMD);
+
+ int64_t remote = BDK_CSR_READ(node, BDK_GTI_CC_CNTMBTS);
+ int64_t local = BDK_CSR_READ(local_node, BDK_GTI_CC_CNTMBTS);
+ int64_t delta = remote - local;
+
+ local_to_remote_sum += delta;
+ if (delta < local_to_remote_min)
+ local_to_remote_min = delta;
+ if (delta > local_to_remote_max)
+ local_to_remote_max = delta;
+
+ /* Perform a write to the local GTI_CC_CNTMB to cause timestamp
+ update. We don't care about the value actually written */
+ pp_cmd.s.addr = LOCAL_GTI_CC_CNTMB;
+ BDK_CSR_WRITE(node, BDK_OCX_PP_CMD, pp_cmd.u);
+ BDK_CSR_READ(node, BDK_OCX_PP_CMD);
+
+ remote = BDK_CSR_READ(node, BDK_GTI_CC_CNTMBTS);
+ local = BDK_CSR_READ(local_node, BDK_GTI_CC_CNTMBTS);
+ delta = local - remote;
+
+ remote_to_local_sum += delta;
+ if (delta < remote_to_local_min)
+ remote_to_local_min = delta;
+ if (delta > remote_to_local_max)
+ remote_to_local_max = delta;
+ }
+ /* Calculate average, rounding to nearest */
+ int64_t local_to_remote = (local_to_remote_sum + NUM_AVERAGE/2) / NUM_AVERAGE;
+ int64_t remote_to_local = (remote_to_local_sum + NUM_AVERAGE/2) / NUM_AVERAGE;
+ /* Calculate remote node offset */
+ int64_t remote_offset = (remote_to_local - local_to_remote) / 2;
+ BDK_CSR_WRITE(node, BDK_GTI_CC_CNTADD, remote_offset);
+ BDK_TRACE(INIT, "N%d.GTI: Clock synchronization with master\n"
+ " local -> remote: min %ld, avg %ld, max %ld\n"
+ " remote -> local: min %ld, avg %ld, max %ld\n"
+ " Counter correction: %ld\n",
+ node,
+ local_to_remote_min, local_to_remote, local_to_remote_max,
+ remote_to_local_min, remote_to_local, remote_to_local_max,
+ remote_offset);
+ }
+ }
+}
+
+/**
+ * Get cycle count based on the clock type.
+ *
+ * @param clock - Enumeration of the clock type.
+ * @return - Get the number of cycles executed so far.
+ */
+uint64_t __bdk_clock_get_count_slow(bdk_clock_t clock)
+{
+ bdk_node_t node = bdk_numa_local();
+ BDK_CSR_INIT(rst_boot, node, BDK_RST_BOOT);
+ if (bdk_is_platform(BDK_PLATFORM_EMULATOR))
+ {
+ /* Force RCLK and SCLK to be 1GHz on emulator */
+ rst_boot.s.c_mul = 20;
+ rst_boot.s.pnr_mul = 20;
+ }
+ uint64_t ref_cntr = BDK_CSR_READ(node, BDK_RST_REF_CNTR);
+ switch(clock)
+ {
+ case BDK_CLOCK_TIME:
+ return 0; /* Handled in fast path */
+ case BDK_CLOCK_MAIN_REF:
+ return ref_cntr;
+ case BDK_CLOCK_RCLK:
+ return ref_cntr * rst_boot.s.c_mul;
+ case BDK_CLOCK_SCLK:
+ return ref_cntr * rst_boot.s.pnr_mul;
+ }
+ return 0;
+}
+
+/**
+ * Get clock rate based on the clock type.
+ *
+ * @param node Node to use in a Numa setup. Can be an exact ID or a special value.
+ * @param clock - Enumeration of the clock type.
+ * @return - return the clock rate.
+ */
+uint64_t __bdk_clock_get_rate_slow(bdk_node_t node, bdk_clock_t clock)
+{
+ /* This is currently defined to be 50Mhz */
+ const uint64_t REF_CLOCK = 50000000;
+
+ BDK_CSR_INIT(mio_rst_boot, node, BDK_RST_BOOT);
+ if (bdk_is_platform(BDK_PLATFORM_EMULATOR))
+ {
+ /* Force RCLK and SCLK to be 1GHz on emulator */
+ mio_rst_boot.s.c_mul = 20;
+ mio_rst_boot.s.pnr_mul = 20;
+ }
+ switch (clock)
+ {
+ case BDK_CLOCK_TIME:
+ return BDK_GTI_RATE; /* Programed as part of setup */
+ case BDK_CLOCK_MAIN_REF:
+ return REF_CLOCK;
+ case BDK_CLOCK_RCLK:
+ return REF_CLOCK * mio_rst_boot.s.c_mul;
+ case BDK_CLOCK_SCLK:
+ return REF_CLOCK * mio_rst_boot.s.pnr_mul;
+ }
+ return 0;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c
new file mode 100644
index 0000000000..d4b412d439
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c
@@ -0,0 +1,1946 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+* reserved.
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+*
+* * Neither the name of Cavium Inc. nor the names of
+* its contributors may be used to endorse or promote products
+* derived from this software without specific prior written
+* permission.
+*
+* This Software, including technical data, may be subject to U.S. export
+* control laws, including the U.S. Export Administration Act and its
+* associated regulations, and may be subject to export or import
+* regulations in other countries.
+*
+* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
+* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
+* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
+* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
+* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
+* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
+* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
+* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+***********************license end**************************************/
+#include <bdk.h>
+#include <stdarg.h>
+#include <libfdt.h>
+#include <unistd.h>
+#include "libbdk-arch/bdk-csrs-mio_fus.h"
+#include "libbdk-arch/bdk-csrs-fus.h"
+
+/* Set this define to override the trace the BDK uses. This is most
+ useful with trusted boot when the setup menus are not able to
+ configure the trace level. A possible example: */
+//#define BDK_TRACE_OVERRIDE (1ull << BDK_TRACE_ENABLE_INIT)
+#define BDK_TRACE_OVERRIDE 0
+
+typedef enum
+{
+ BDK_CONFIG_TYPE_INT,
+ BDK_CONFIG_TYPE_STR,
+ BDK_CONFIG_TYPE_STR_LIST,
+ BDK_CONFIG_TYPE_BINARY,
+} bdk_config_type_t;
+
+typedef struct
+{
+ const char *format; /* Printf style format string to create the item name */
+ const bdk_config_type_t ctype;/* Type of this item */
+ int64_t default_value; /* Default value when no present. String defaults are cast to pointers from this */
+ const int64_t min_value;/* Minimum valid value for INT parameters. Unused for Strings */
+ const int64_t max_value;/* Maximum valid value for INT parameters. Unused for Strings */
+} bdk_config_info_t;
+
+static void config_set_defaults(void);
+
+/* Tracing defaults to the level specified here before config files are loaded */
+uint64_t bdk_trace_enables = BDK_TRACE_OVERRIDE;
+
+/* Global variables that contain the config inside a FDT */
+static void *config_fdt;
+static int config_node;
+
+static bdk_config_info_t config_info[__BDK_CONFIG_END] = {
+ /* Board manufacturing data */
+ [BDK_CONFIG_BOARD_MODEL] = {
+ .format = "BOARD-MODEL", /* String, No parameters */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"unknown",
+ },
+ [BDK_CONFIG_BOARD_REVISION] = {
+ .format = "BOARD-REVISION", /* String, No parameters */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"unknown",
+ },
+ [BDK_CONFIG_BOARD_SERIAL] = {
+ .format = "BOARD-SERIAL", /* String, No parameters */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"unknown",
+ },
+ [BDK_CONFIG_MAC_ADDRESS] = {
+ .format = "BOARD-MAC-ADDRESS", /* Int64, No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Default updated at boot based on fuses */
+ .min_value = 0,
+ .max_value = 0xffffffffffffll,
+ },
+ [BDK_CONFIG_MAC_ADDRESS_NUM] = {
+ .format = "BOARD-MAC-ADDRESS-NUM", /* Int, No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 256,
+ },
+ [BDK_CONFIG_MAC_ADDRESS_NUM_OVERRIDE] = {
+ .format = "BOARD-MAC-ADDRESS-NUM-OVERRIDE", /* Int, No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1,
+ .min_value = -1,
+ .max_value = 256,
+ },
+
+ /* Board generic */
+ [BDK_CONFIG_BMC_TWSI] = {
+ .format = "BMC-TWSI", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* TWSI bus number, -1 = disabled */
+ .min_value = -1,
+ .max_value = 5,
+ },
+ [BDK_CONFIG_WATCHDOG_TIMEOUT] = {
+ .format = "WATCHDOG-TIMEOUT", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = disabled */
+ .min_value = 0,
+ .max_value = 10000,
+ },
+ [BDK_CONFIG_TWSI_WRITE] = {
+ .format = "TWSI-WRITE", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_STR_LIST,
+ },
+ [BDK_CONFIG_MDIO_WRITE] = {
+ .format = "MDIO-WRITE", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_STR_LIST,
+ },
+
+ /* Board wiring of network ports and PHYs */
+ [BDK_CONFIG_PHY_ADDRESS] = {
+ .format = "PHY-ADDRESS.N%d.BGX%d.P%d", /* Parameters: Node, Interface, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default to no PHY */
+ .min_value = -1,
+ .max_value = 0xffffffffll,
+ },
+ [BDK_CONFIG_BGX_ENABLE] = {
+ .format = "BGX-ENABLE.N%d.BGX%d.P%d", /* Parameters: Node, BGX, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1, /* 0 = disable, 1 = enable */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ /* Non-EBB specific SFF8104 board and alike */
+ [BDK_CONFIG_AQUANTIA_PHY] = {
+ .format = "AQUANTIA-PHY.N%d.BGX%d.P%d", /*Parameters: Node, BGX, Port */
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffffll,
+ },
+
+
+ /* BDK Configuration params */
+ [BDK_CONFIG_VERSION] = {
+ .format = "BDK-VERSION",
+ .ctype = BDK_CONFIG_TYPE_STR,
+ },
+ [BDK_CONFIG_NUM_PACKET_BUFFERS] = {
+ .format = "BDK-NUM-PACKET-BUFFERS",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Default updated at boot */
+ .min_value = 0,
+ .max_value = 1000000,
+ },
+ [BDK_CONFIG_PACKET_BUFFER_SIZE] = {
+ .format = "BDK-PACKET-BUFFER-SIZE",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1024, /* bytes */
+ .min_value = 128,
+ .max_value = 32768,
+ },
+ [BDK_CONFIG_SHOW_LINK_STATUS] = {
+ .format = "BDK-SHOW-LINK-STATUS",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1, /* 0 = off, 1 = on */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_COREMASK] = {
+ .format = "BDK-COREMASK",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Zero means all cores */
+ .min_value = 0,
+ .max_value = 0xffffffffffffll,
+ },
+ [BDK_CONFIG_BOOT_MENU_TIMEOUT] = {
+ .format = "BDK-BOOT-MENU-TIMEOUT",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 10, /* seconds */
+ .min_value = 0,
+ .max_value = 300,
+ },
+ [BDK_CONFIG_BOOT_PATH_OPTION] = {
+ .format = "BDK-BOOT-PATH-OPTION",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = normal, 1 = diagnostics */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_BOOT_NEXT_STAGE] = {
+ .format = "BDK-CONFIG-BOOT-NEXT-STAGE-%s",
+ .ctype = BDK_CONFIG_TYPE_STR,
+ },
+ [BDK_CONFIG_TRACE] = {
+ .format = "BDK-CONFIG-TRACE",
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* bitmask */
+ .min_value = 0,
+ .max_value = 0x7fffffffffffffffull,
+ },
+
+ /* Chip feature items */
+ [BDK_CONFIG_MULTI_NODE] = {
+ .format = "MULTI-NODE", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 2, /* 2 = Auto */
+ .min_value = 0,
+ .max_value = 2,
+ },
+ [BDK_CONFIG_PCIE_EA] = {
+ .format = "PCIE-ENHANCED-ALLOCATION", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1, /* 1 = EA supported, 0 = EA not supported */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_PCIE_ORDERING] = {
+ .format = "PCIE-ORDERING", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 1 = Wait for commit, 0 = Don't wait for commit */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_PCIE_PRESET_REQUEST_VECTOR] = {
+ .format = "PCIE-PRESET-REQUEST-VECTOR.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0x593, /* Value for PCIERCX_CFG554[PRV] */
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_PCIE_WIDTH] = {
+ .format = "PCIE-WIDTH.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Width override for PCIe links */
+ .min_value = -1,
+ .max_value = 16,
+ },
+ [BDK_CONFIG_PCIE_PHYSICAL_SLOT] = {
+ .format = "PCIE-PHYSICAL-SLOT.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Define which physical slot we connect to on the board */
+ .min_value = -1,
+ .max_value = 8191,
+ },
+ [BDK_CONFIG_PCIE_FLASH] = {
+ .format = "PCIE-FLASH.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_STR_LIST,
+ },
+ [BDK_CONFIG_CCPI_LANE_REVERSE] = {
+ .format = "CCPI-LANE-REVERSE", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = No forced lane reversal, 1 = forced lane reversal */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_CHIP_SKU] = {
+ .format = "CHIP-SKU.NODE%d", /* Parameter: Node */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"TBD",
+ },
+ [BDK_CONFIG_CHIP_SERIAL] = {
+ .format = "CHIP-SERIAL.NODE%d", /* Parameter: Node */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"TBD",
+ },
+ [BDK_CONFIG_CHIP_UNIQUE_ID] = {
+ .format = "CHIP-UNIQUE-ID.NODE%d", /* Parameter: Node */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ .default_value = (long)"TBD",
+ },
+
+ /* QLM related config */
+ [BDK_CONFIG_QLM_AUTO_CONFIG] = {
+ .format = "QLM-AUTO-CONFIG", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = off, 1 = on */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ /* SFF8104 related QLM config */
+ [BDK_CONFIG_QLM_DIP_AUTO_CONFIG] = {
+ .format = "QLM-DIP-AUTO-CONFIG", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = off, 1 = on */
+ .min_value = 0,
+ .max_value = 1,
+ },
+
+ [BDK_CONFIG_QLM_MODE] = {
+ .format = "QLM-MODE.N%d.QLM%d", /* Parameters: Node, QLM */
+ .ctype = BDK_CONFIG_TYPE_STR,
+ },
+ [BDK_CONFIG_QLM_FREQ] = {
+ .format = "QLM-FREQ.N%d.QLM%d", /* Parameters: Node, QLM */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Mhz */
+ .min_value = 0,
+ .max_value = 10312,
+ },
+ [BDK_CONFIG_QLM_CLK] = {
+ .format = "QLM-CLK.N%d.QLM%d", /* Parameters: Node, QLM */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 2, /* 2 = External */
+ .min_value = 0,
+ .max_value = 2,
+ },
+ [BDK_CONFIG_QLM_TUNING_TX_SWING] = {
+ .format = "QLM-TUNING-TX-SWING.N%d.QLM%d.LANE%d", /* Parameters: Node, QLM, Lane */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default of no tuning */
+ .min_value = -1,
+ .max_value = 31,
+ },
+ [BDK_CONFIG_QLM_TUNING_TX_PREMPTAP] = {
+ .format = "QLM-TUNING-TX-PREMPTAP.N%d.QLM%d.LANE%d", /* Parameters: Node, QLM, Lane */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default of no tuning */
+ .min_value = -1,
+ .max_value = 511,
+ },
+ [BDK_CONFIG_QLM_TUNING_TX_GAIN] = {
+ .format = "QLM-TUNING-TX-GAIN.N%d.QLM%d.LANE%d", /* Parameters: Node, QLM, Lane */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default of no tuning */
+ .min_value = -1,
+ .max_value = 7,
+ },
+ [BDK_CONFIG_QLM_TUNING_TX_VBOOST] = {
+ .format = "QLM-TUNING-TX-VBOOST.N%d.QLM%d.LANE%d", /* Parameters: Node, QLM, Lane */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default of no tuning */
+ .min_value = -1,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_QLM_CHANNEL_LOSS] = {
+ .format = "QLM-CHANNEL-LOSS.N%d.QLM%d", /* Parameters: Node, QLM */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Default will use Cavium defaults */
+ .min_value = -1,
+ .max_value = 40,
+ },
+
+ /* DRAM configuration options */
+ [BDK_CONFIG_DDR_SPEED] = {
+ .format = "DDR-SPEED.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* In MT/s */
+ .min_value = 0,
+ .max_value = 2400,
+ },
+ [BDK_CONFIG_DDR_ALT_REFCLK] = {
+ .format = "DDR-ALT-REFCLK.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Mhz */
+ .min_value = 0,
+ .max_value = 100,
+ },
+ [BDK_CONFIG_DDR_SPD_ADDR] = {
+ .format = "DDR-CONFIG-SPD-ADDR.DIMM%d.LMC%d.N%d", /* Parameters: DIMM, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_SPD_DATA] = {
+ .format = "DDR-CONFIG-SPD-DATA.DIMM%d.LMC%d.N%d", /* Parameters: DIMM, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_BINARY,
+ },
+ [BDK_CONFIG_DDR_RANKS_DQX_CTL] = {
+ .format = "DDR-CONFIG-DQX-CTL.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xf,
+ },
+ [BDK_CONFIG_DDR_RANKS_WODT_MASK] = {
+ .format = "DDR-CONFIG-WODT-MASK.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xfffffff,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_PASR] = {
+ .format = "DDR-CONFIG-MODE1-PASR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x7,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_ASR] = {
+ .format = "DDR-CONFIG-MODE1-ASR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_SRT] = {
+ .format = "DDR-CONFIG-MODE1-SRT.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_RTT_WR] = {
+ .format = "DDR-CONFIG-MODE1-RTT-WR.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // Split for extension bit
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x7,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_DIC] = {
+ .format = "DDR-CONFIG-MODE1-DIC.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x3,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_RTT_NOM] = {
+ .format = "DDR-CONFIG-MODE1-RTT-NOM.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x7,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE1_DB_OUTPUT_IMPEDANCE] = {
+ .format = "DDR-CONFIG-MODE1-DB-OUTPUT-IMPEDANCE.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // Not per RANK, only one
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x7,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE2_RTT_PARK] = {
+ .format = "DDR-CONFIG-MODE2-RTT-PARK.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x7,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE2_VREF_VALUE] = {
+ .format = "DDR-CONFIG-MODE2-VREF-VALUE.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0x3f,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE2_VREF_RANGE] = {
+ .format = "DDR-CONFIG-MODE2-VREF-RANGE.RANKS%d.DIMMS%d.RANK%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, Rank, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_RANKS_MODE2_VREFDQ_TRAIN_EN] = {
+ .format = "DDR-CONFIG-MODE2-VREFDQ-TRAIN-EN.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // Not per RANK, only one
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+
+ [BDK_CONFIG_DDR_RANKS_RODT_CTL] = {
+ .format = "DDR-CONFIG-RODT-CTL.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xf,
+ },
+ [BDK_CONFIG_DDR_RANKS_RODT_MASK] = {
+ .format = "DDR-CONFIG-RODT-MASK.RANKS%d.DIMMS%d.LMC%d.N%d", /* Parameters: Num Ranks, Num DIMMs, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xfffffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MIN_RTT_NOM_IDX] = {
+ .format = "DDR-CONFIG-CUSTOM-MIN-RTT-NOM-IDX.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1,
+ .min_value = 0,
+ .max_value = 7,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MAX_RTT_NOM_IDX] = {
+ .format = "DDR-CONFIG-CUSTOM-MAX-RTT-NOM-IDX.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 5,
+ .min_value = 0,
+ .max_value = 7,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MIN_RODT_CTL] = {
+ .format = "DDR-CONFIG-CUSTOM-MIN-RODT-CTL.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1,
+ .min_value = 0,
+ .max_value = 7,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MAX_RODT_CTL] = {
+ .format = "DDR-CONFIG-CUSTOM-MAX-RODT-CTL.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 5,
+ .min_value = 0,
+ .max_value = 7,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_CK_CTL] = {
+ .format = "DDR-CONFIG-CUSTOM-CK-CTL.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_CMD_CTL] = {
+ .format = "DDR-CONFIG-CUSTOM-CMD-CTL.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_CTL_CTL] = {
+ .format = "DDR-CONFIG-CUSTOM-CTL-CTL.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xf,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MIN_CAS_LATENCY] = {
+ .format = "DDR-CONFIG-CUSTOM-MIN-CAS-LATENCY.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_OFFSET_EN] = {
+ .format = "DDR-CONFIG-CUSTOM-OFFSET-EN.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_OFFSET] = {
+ .format = "DDR-CONFIG-CUSTOM-OFFSET.%s.LMC%d.N%d", /* Parameters: Type(UDIMM,RDIMM), LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // UDIMM or RDIMM
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xf,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_RLEVEL_COMPUTE] = {
+ .format = "DDR-CONFIG-CUSTOM-RLEVEL-COMPUTE.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_RLEVEL_COMP_OFFSET] = {
+ .format = "DDR-CONFIG-CUSTOM-RLEVEL-COMP-OFFSET.%s.LMC%d.N%d", /* Parameters: Type(UDIMM,RDIMM), LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // UDIMM or RDIMM
+ .default_value = 2,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_DDR2T] = {
+ .format = "DDR-CONFIG-CUSTOM-DDR2T.%s.LMC%d.N%d", /* Parameters: Type(UDIMM,RDIMM), LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT, // UDIMM or RDIMM
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_DISABLE_SEQUENTIAL_DELAY_CHECK] = {
+ .format = "DDR-CONFIG-CUSTOM-DISABLE-SEQUENTIAL-DELAY-CHECK.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MAXIMUM_ADJACENT_RLEVEL_DELAY_INCREMENT] = {
+ .format = "DDR-CONFIG-CUSTOM-MAXIMUM-ADJACENT-RLEVEL-DELAY-INCREMENT.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xffff,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_PARITY] = {
+ .format = "DDR-CONFIG-CUSTOM-PARITY.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_FPRCH2] = {
+ .format = "DDR-CONFIG-CUSTOM-FPRCH2.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 0xf,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MODE32B] = {
+ .format = "DDR-CONFIG-CUSTOM-MODE32B.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_MEASURED_VREF] = {
+ .format = "DDR-CONFIG-CUSTOM-MEASURED-VREF.LMC%d.N%d", /* Parameters: LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_DLL_WRITE_OFFSET] = {
+ .format = "DDR-CONFIG-CUSTOM-DLL-WRITE-OFFSET.BYTE%d.LMC%d.N%d", /* Parameters: Byte, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = -63,
+ .max_value = 63,
+ },
+ [BDK_CONFIG_DDR_CUSTOM_DLL_READ_OFFSET] = {
+ .format = "DDR-CONFIG-CUSTOM-DLL-READ-OFFSET.BYTE%d.LMC%d.N%d", /* Parameters: Byte, LMC, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0,
+ .min_value = -63,
+ .max_value = 63,
+ },
+
+ /* High level DRAM options */
+ [BDK_CONFIG_DRAM_VERBOSE] = {
+ .format = "DDR-VERBOSE", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = off */
+ .min_value = 0,
+ .max_value = 255,
+ },
+ [BDK_CONFIG_DRAM_BOOT_TEST] = {
+ .format = "DDR-TEST-BOOT", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* 0 = off, 1 = on */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_DRAM_CONFIG_GPIO] = {
+ .format = "DDR-CONFIG-GPIO", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* -1 = disabled, otherwise GPIO number */
+ .min_value = -1,
+ .max_value = 63,
+ },
+ [BDK_CONFIG_DRAM_SCRAMBLE] = {
+ .format = "DDR-CONFIG-SCRAMBLE", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 2, /* 0=off, 1=on, 2=trust on, non-trust off */
+ .min_value = 0,
+ .max_value = 2,
+ },
+
+ /* USB */
+ [BDK_CONFIG_USB_PWR_GPIO] = {
+ .format = "USB-PWR-GPIO.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 49,
+ },
+ [BDK_CONFIG_USB_PWR_GPIO_POLARITY] = {
+ .format = "USB-PWR-GPIO-POLARITY.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 1, /* GPIO polarity: 1=high, 0=low */
+ .min_value = 0,
+ .max_value = 1,
+ },
+ [BDK_CONFIG_USB_REFCLK_SRC] = {
+ .format = "USB-REFCLK-SRC.N%d.PORT%d", /* Parameters: Node, Port */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Clock Source (SS:HS)
+ ** 0 - SS(USB_REF_CLK) HS(USB_REF_CLK)
+ ** 1 - SS(DLMC_REF_CLK0) HS(DLMC_REF_CLK0)
+ ** 2 - SS(DLMC_REF_CLK1) HS(DLMC_REF_CLK1)
+ ** 3 - SS(USB_REF_CLK) HS(PLL_REF_CLK)
+ ** 4 - SS(DLMC_REF_CLK0) HS(PLL_REF_CLK)
+ ** 5 - SS(DLMC_REF_CLK1) HS(PLL_REF_CLK)
+ */
+ .min_value = 0,
+ .max_value = 5,
+ },
+
+ /* Nitrox reset - For CN88XX SC and SNT part. High drives Nitrox DC_OK high */
+ [BDK_CONFIG_NITROX_GPIO] = {
+ .format = "NITROX-GPIO.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 49,
+ },
+
+ /* How EYE diagrams are captured from a QLM */
+ [BDK_CONFIG_EYE_ZEROS] = {
+ .format = "QLM-EYE-NUM-ZEROS", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 2,
+ .min_value = 1,
+ .max_value = 63,
+ },
+ [BDK_CONFIG_EYE_SAMPLE_TIME] = {
+ .format = "QLM-EYE-SAMPLE-TIME", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 400, /* us */
+ .min_value = 20, /* us */
+ .max_value = 10000000, /* us */
+ },
+ [BDK_CONFIG_EYE_SETTLE_TIME] = {
+ .format = "QLM-EYE-SETTLE-TIME", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 50, /* us */
+ .min_value = 20, /* us */
+ .max_value = 100000, /* us */
+ },
+
+ /* SGPIO */
+ [BDK_CONFIG_SGPIO_SCLOCK_FREQ] = {
+ .format = "SGPIO-SCLOCK-FREQ.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 10000, /* Hz */
+ .min_value = 128, /* Hz */
+ .max_value = 100000, /* Hz */
+ },
+ [BDK_CONFIG_SGPIO_PIN_POWER] = {
+ .format = "SGPIO-PIN-POWER.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 50,
+ },
+ [BDK_CONFIG_SGPIO_PIN_SCLOCK] = {
+ .format = "SGPIO-PIN-SCLOCK.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 50,
+ },
+ [BDK_CONFIG_SGPIO_PIN_SLOAD] = {
+ .format = "SGPIO-PIN-SLOAD.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 50,
+ },
+ [BDK_CONFIG_SGPIO_PIN_SDATAOUT] = {
+ .format = "SGPIO-PIN-SDATAOUT.N%d.D%d", /* Parameters: Node, Dataline */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* GPIO number, or -1 for none */
+ .min_value = -1,
+ .max_value = 50,
+ },
+
+ /* VRM temperature throttling */
+ [BDK_CONFIG_VRM_TEMP_TRIP] = {
+ .format = "VRM-TEMP-TRIP.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 110, /* Degrees C */
+ .min_value = 0, /* Degrees C */
+ .max_value = 110, /* Degrees C. Max die temp plus 5 for uncertainty of measurement */
+ },
+ [BDK_CONFIG_VRM_TEMP_HIGH] = {
+ .format = "VRM-TEMP-HIGH.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 110, /* Degrees C */
+ .min_value = 0, /* Degrees C */
+ .max_value = 110, /* Degrees C. Max die temp plus 5 for uncertainty of measurement */
+ },
+ [BDK_CONFIG_VRM_TEMP_LOW] = {
+ .format = "VRM-TEMP-LOW.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 100, /* Degrees C */
+ .min_value = 0, /* Degrees C */
+ .max_value = 110, /* Degrees C. Max die temp plus 5 for uncertainty of measurement */
+ },
+ [BDK_CONFIG_VRM_THROTTLE_NORMAL] = {
+ .format = "VRM-THROTTLE-NORMAL.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 65, /* Percentage */
+ .min_value = 1, /* Percentage */
+ .max_value = 100, /* Percentage */
+ },
+ [BDK_CONFIG_VRM_THROTTLE_THERM] = {
+ .format = "VRM-THROTTLE-THERM.N%d", /* Parameters: Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 15, /* Percentage */
+ .min_value = 1, /* Percentage */
+ .max_value = 100, /* Percentage */
+ },
+
+ /* Generic GPIO, unrelated to a specific block */
+ [BDK_CONFIG_GPIO_PIN_SELECT] = {
+ .format = "GPIO-PIN-SELECT-GPIO%d.N%d", /* Parameters: GPIO, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = -1, /* Hardware default, normal GPIO pin */
+ .min_value = 0, /* GPIO_PIN_SEL_E enumeration */
+ .max_value = 65535, /* GPIO_PIN_SEL_E enumeration */
+ },
+ [BDK_CONFIG_GPIO_POLARITY] = {
+ .format = "GPIO-POLARITY-GPIO%d.N%d", /* Parameters: GPIO, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Hardware default, not inverted */
+ .min_value = 0, /* Not inverted */
+ .max_value = 1, /* Inverted */
+ },
+
+ /* PBUS */
+ [BDK_CONFIG_PBUS_CFG] = {
+ .format = "PBUS-CFG.REGION%d.N%d", /* Parameters: Region, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Hardware default */
+ .min_value = 0, /* No change */
+ .max_value = 0x0000ffffffffffffll, /* PBUS_REGX_CFG value */
+ },
+ [BDK_CONFIG_PBUS_TIM] = {
+ .format = "PBUS-TIM.REGION%d.N%d", /* Parameters: Region, Node */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Hardware default, not inverted */
+ .min_value = 0x8000000000000000ll, /* PBUS_REGX_TIM value, zero is no change */
+ .max_value = 0x7fffffffffffffffll, /* PBUS_REGX_TIM value */
+ },
+
+ /* Trusted boot information */
+ [BDK_CONFIG_TRUST_CSIB] = {
+ .format = "TRUST-CSIB", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_BINARY,
+ .default_value = 0, /* Hardware default */
+ },
+ [BDK_CONFIG_TRUST_ROT_ADDR] = {
+ .format = "TRUST-ROT-ADDR", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* Non-trusted */
+ .min_value = 0, /* No key */
+ .max_value = 0x0000ffffffffffffll, /* Address in key memory */
+ },
+ [BDK_CONFIG_TRUST_BSSK_ADDR] = {
+ .format = "TRUST-BSSK-ADDR", /* No parameters */
+ .ctype = BDK_CONFIG_TYPE_INT,
+ .default_value = 0, /* No HUK, so no BSSK */
+ .min_value = 0, /* No HUK, so no BSSK */
+ .max_value = 0x0000ffffffffffffll, /* Address in key memory */
+ },
+};
+
+/**
+ * Look up a configuration item in the environment.
+ *
+ * @param name
+ *
+ * @return
+ */
+static const char *get_value(const char *name, int *blob_size)
+{
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config asked for %s before configuration loaded\n", name);
+ return NULL;
+ }
+
+ char n[64];
+ strncpy(n, name, sizeof(n));
+ n[sizeof(n)-1] = '\0';
+
+ while (*n)
+ {
+ const char *val = fdt_getprop(config_fdt, config_node, n, blob_size);
+ if (val)
+ return val;
+
+ char *p = strrchr(n, '.');
+ if (p)
+ *p = '\0';
+ else
+ break;
+ }
+ return NULL;
+}
+
+/**
+ * Get an integer configuration item
+ *
+ * @param cfg_item Config item to get. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ *
+ * @return The value of the configuration item, or def_value if the item is not set
+ */
+int64_t bdk_config_get_int(bdk_config_t cfg_item, ...)
+{
+ /* Make sure the correct access function was called */
+ if (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_INT)
+ bdk_fatal("bdk_config_get_int() called for %s, not an int\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ va_list args;
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ const char *val = get_value(name, NULL);
+ if (val)
+ {
+ int count;
+ int64_t tmp;
+ if ((val[0] == '0') && (val[1] == 'x'))
+ count = sscanf(val + 2, "%lx", &tmp);
+ else
+ count = sscanf(val, "%li", &tmp);
+ if (count == 1)
+ {
+ if ((tmp < config_info[cfg_item].min_value) || (tmp > config_info[cfg_item].max_value))
+ {
+ bdk_warn("Out of range for %s = \"%s\", using default\n", name, val);
+ return config_info[cfg_item].default_value;
+ }
+ return tmp;
+ }
+ else
+ {
+ bdk_warn("Failed to parse %s = \"%s\", using default\n", name, val);
+ return config_info[cfg_item].default_value;
+ }
+ }
+ else
+ return config_info[cfg_item].default_value;
+}
+
+/**
+ * Get a string configuration item
+ *
+ * @param cfg_item Config item to get. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ *
+ * @return The value of the configuration item, or def_value if the item is not set
+ */
+const char *bdk_config_get_str(bdk_config_t cfg_item, ...)
+{
+ /* Make sure the correct access function was called */
+ if (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_STR)
+ bdk_fatal("bdk_config_get_str() called for %s, not a str\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ va_list args;
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+
+ if (BDK_CONFIG_QLM_MODE == cfg_item)
+ {
+ char name2[64];
+ vsnprintf(name2, sizeof(name2)-1,"QLM-MODE.N%d.DLM%d" , args);
+ const char *val = get_value(name2, NULL);
+ if (val)
+ bdk_warn("%s: QLM-MODE.N%%d.DLM%%d format depricated. Please use QLM-MODE.N%%d.QLM%%d instead\n", name2);
+
+ }
+ va_end(args);
+
+ const char *val = get_value(name, NULL);
+ if (val)
+ return val;
+ else
+ return (const char *)config_info[cfg_item].default_value;
+}
+
+/**
+ * Get a binary blob
+ *
+ * @param blob_size Integer to receive the size of the blob
+ * @param cfg_item Config item to get. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ *
+ * @return The value of the configuration item, or def_value if the item is not set
+ */
+const void* bdk_config_get_blob(int *blob_size, bdk_config_t cfg_item, ...)
+{
+ char name[64];
+ va_list args;
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ const void *val = get_value(name, blob_size);
+ if (val)
+ return val;
+ else
+ return (const void *)config_info[cfg_item].default_value;
+}
+
+/**
+ * Set an integer configuration item. Note this only sets the item in memory,
+ * persistent storage is not updated. The optional parameters for the setting are
+ * not supplied, meaning this function only changes the global default.
+ *
+ * @param value Configuration item value
+ * @param cfg_item Config item to set. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ */
+void bdk_config_set_int_no_param(int64_t value, bdk_config_t cfg_item)
+{
+ /* Make sure the correct access function was called */
+ if (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_INT)
+ bdk_fatal("bdk_config_set_int_no_param() called for %s, not an int\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ char valstr[20];
+ /* Create a name without the optional parameters */
+ strncpy(name, config_info[cfg_item].format, sizeof(name) - 1);
+ name[sizeof(name) - 1] = 0;
+ char *ptr = strchr(name, '.');
+ if (ptr)
+ *ptr = 0;
+
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config set %s before configuration loaded\n", name);
+ return;
+ }
+ if ((value < config_info[cfg_item].min_value) || (value > config_info[cfg_item].max_value))
+ {
+ bdk_error("Set out of range for %s = \"0x%lx\", ignoring\n", name, value);
+ return;
+ }
+
+ if (value < 10)
+ snprintf(valstr, sizeof(valstr), "%ld", value);
+ else
+ snprintf(valstr, sizeof(valstr), "0x%lx", value);
+
+ int status = fdt_setprop_string(config_fdt, config_node, name, valstr);
+ if (status < 0)
+ bdk_fatal("Failed to set %s=%s in FDT\n", name, valstr);
+}
+
+/**
+ * Set an integer configuration item. Note this only sets the item in memory,
+ * persistent storage is not updated.
+ *
+ * @param value Configuration item value
+ * @param cfg_item Config item to set. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ */
+void bdk_config_set_int(int64_t value, bdk_config_t cfg_item, ...)
+{
+ /* Make sure the correct access function was called */
+ if (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_INT)
+ bdk_fatal("bdk_config_set_int() called for %s, not an int\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ char valstr[20];
+ va_list args;
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config set %s before configuration loaded\n", name);
+ return;
+ }
+ if ((value < config_info[cfg_item].min_value) || (value > config_info[cfg_item].max_value))
+ {
+ bdk_error("Set out of range for %s = \"0x%lx\", ignoring\n", name, value);
+ return;
+ }
+
+ if (value < 10)
+ snprintf(valstr, sizeof(valstr), "%ld", value);
+ else
+ snprintf(valstr, sizeof(valstr), "0x%lx", value);
+
+ int status = fdt_setprop_string(config_fdt, config_node, name, valstr);
+ if (status < 0)
+ bdk_fatal("Failed to set %s=%s in FDT\n", name, valstr);
+}
+
+/**
+ * Set an integer configuration item. Note this only sets the item in memory,
+ * persistent storage is not updated.
+ *
+ * @param value Configuration item value
+ * @param cfg_item Config item to set. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ */
+void bdk_config_set_str(const char *value, bdk_config_t cfg_item, ...)
+{
+ /* Make sure the correct access function was called */
+ if (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_STR)
+ bdk_fatal("bdk_config_set_str() called for %s, not a str\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ va_list args;
+
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config set %s before configuration loaded\n", name);
+ return;
+ }
+
+ int status;
+ if (value)
+ status = fdt_setprop_string(config_fdt, config_node, name, value);
+ else
+ status = fdt_delprop(config_fdt, config_node, name);
+
+ if ((status < 0) && (status != -FDT_ERR_NOTFOUND))
+ bdk_fatal("Failed to set %s=%s in FDT\n", name, value);
+}
+
+/**
+ * Set a blob configuration item. Note this only sets the
+ * item in memory, persistent storage is not updated. The optional
+ * parameters for the setting are not supplied, meaning this function
+ * only changes the global default.
+ *
+ * @param size Size of the item in bytes. A size of zero removes the device tree field
+ * @param value Configuration item value
+ * @param cfg_item Config item to set. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ */
+void bdk_config_set_blob_no_param(int size, const void *value, bdk_config_t cfg_item)
+{
+ /* Make sure the correct access function was called */
+ if ((config_info[cfg_item].ctype != BDK_CONFIG_TYPE_BINARY) &&
+ (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_STR_LIST))
+ bdk_fatal("bdk_config_set_blob() called for %s, not binary\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ /* Create a name without the optional parameters */
+ strncpy(name, config_info[cfg_item].format, sizeof(name) - 1);
+ name[sizeof(name) - 1] = 0;
+ char *ptr = strchr(name, '.');
+ if (ptr)
+ *ptr = 0;
+
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config set %s before configuration loaded\n", name);
+ return;
+ }
+
+ int status;
+ if (size)
+ status = fdt_setprop(config_fdt, config_node, name, value, size);
+ else
+ status = fdt_delprop(config_fdt, config_node, name);
+
+ if ((status < 0) && (status != -FDT_ERR_NOTFOUND))
+ bdk_fatal("Failed to set %s in FDT\n", name);
+}
+
+/**
+ * Set a blob configuration item. Note this only sets the
+ * item in memory, persistent storage is not updated.
+ *
+ * @param size Size of the item in bytes. A size of zero removes the device tree field
+ * @param value Configuration item value
+ * @param cfg_item Config item to set. If the item takes parameters (see bdk_config_t), then the
+ * parameters are listed following cfg_item.
+ */
+void bdk_config_set_blob(int size, const void *value, bdk_config_t cfg_item, ...)
+{
+ /* Make sure the correct access function was called */
+ if ((config_info[cfg_item].ctype != BDK_CONFIG_TYPE_BINARY) &&
+ (config_info[cfg_item].ctype != BDK_CONFIG_TYPE_STR_LIST))
+ bdk_fatal("bdk_config_set_blob() called for %s, not binary\n",
+ config_info[cfg_item].format);
+
+ char name[64];
+ va_list args;
+
+ va_start(args, cfg_item);
+ vsnprintf(name, sizeof(name)-1, config_info[cfg_item].format, args);
+ va_end(args);
+
+ if (!config_fdt)
+ {
+ bdk_error("bdk-config set %s before configuration loaded\n", name);
+ return;
+ }
+
+ int status;
+ if (size)
+ status = fdt_setprop(config_fdt, config_node, name, value, size);
+ else
+ status = fdt_delprop(config_fdt, config_node, name);
+
+ if ((status < 0) && (status != -FDT_ERR_NOTFOUND))
+ bdk_fatal("Failed to set %s in FDT\n", name);
+}
+
+/**
+ * Multiple functions need to display the config item help string in a format
+ * suitable for inclusion in a device tree. This function displays the help
+ * message properly indented and such.
+ *
+ * @param cfg Config item to display help for
+ */
+static void display_help(bdk_config_t cfg)
+{
+ /* Print the help text as a comment before the entry */
+ /* Indent with tabs like Linux requires */
+ printf("\n");
+ printf("\t/* ");
+ const char *ptr = bdk_config_get_help(cfg);
+ while (*ptr)
+ {
+ putchar(*ptr);
+ if (*ptr == '\n')
+ putchar('\t');
+ ptr++;
+ }
+ printf(" */\n");
+ /* Print the parameter and its default value a comment. This will be
+ a reference that is easy for the user to change */
+ printf("\t//%s = ", config_info[cfg].format);
+ switch (config_info[cfg].ctype)
+ {
+ case BDK_CONFIG_TYPE_INT:
+ if (config_info[cfg].default_value < 10)
+ printf("\"%ld\"", config_info[cfg].default_value);
+ else
+ printf("\"0x%lx\"", config_info[cfg].default_value);
+ break;
+ case BDK_CONFIG_TYPE_STR:
+ case BDK_CONFIG_TYPE_STR_LIST:
+ if (config_info[cfg].default_value)
+ printf("\"%s\"", (const char *)config_info[cfg].default_value);
+ else
+ printf("\"\"");
+ break;
+ case BDK_CONFIG_TYPE_BINARY:
+ printf("[]");
+ break;
+ }
+ printf(";\n");
+}
+
+/**
+ * Display the active configuration as a valid device tree
+ */
+void bdk_config_show(void)
+{
+ /* Output the standard DTS headers */
+ printf("/dts-v1/;\n");
+ printf("\n");
+ printf("/ {\n");
+ printf("cavium,bdk {\n");
+ for (bdk_config_t cfg = 0; cfg < __BDK_CONFIG_END; cfg++)
+ {
+ /* Show the help message */
+ display_help(cfg);
+
+ /* Figure out how much of the config item is fixed versus
+ the optional parameters */
+ const char *format = config_info[cfg].format;
+ const char *format_param = strchr(format, '.');
+ int format_length = 0;
+ if (format_param)
+ format_length = format_param - format;
+
+ /* Loop through all device tree entries displaying the ones that
+ match this format */
+ int offset = fdt_first_property_offset(config_fdt, config_node);
+ while (offset >= 0)
+ {
+ /* Get the device tree item */
+ const char *name = NULL;
+ int data_size = 0;
+ const char *data = fdt_getprop_by_offset(config_fdt, offset, &name, &data_size);
+ const char *data_end = data + data_size;
+ /* Find the first param */
+ const char *name_param = strchr(name, '.');
+ int name_length = 0;
+ if (name_param)
+ {
+ /* We want to compare up to the first param */
+ name_length = name_param - name;
+ /* If the lengths are different not including the parameters,
+ then we force a full matchn which will always fail */
+ if (name_length != format_length)
+ name_length = 0;
+ }
+ else /* No params, match base of format */
+ name_length = format_length;
+
+ /* Check if it matches the current config format */
+ int match;
+ if (name_length)
+ {
+ /* Check the prefix */
+ match = strncmp(name, format, name_length);
+ if (match == 0)
+ {
+ /* Prefix matched. We only really match if the next
+ character is the end of the string or a '.' */
+ if ((name[name_length] != 0) && (name[name_length] != '.'))
+ match = 1;
+ }
+ }
+ else
+ match = strcmp(name, format);
+ /* Print matching entries */
+ if (match == 0)
+ {
+ if (config_info[cfg].ctype == BDK_CONFIG_TYPE_BINARY)
+ {
+ printf("\t%s = [", name);
+ const char *ptr = data;
+ while (ptr < data_end)
+ {
+ printf(" %02x", (int)*ptr);
+ ptr++;
+ }
+ printf(" ]");
+ }
+ else
+ {
+ printf("\t%s = \"%s\"", name, data);
+ data += strlen(data) + 1;
+ while (data < data_end)
+ {
+ printf(",\n\t\t\"%s\"", data);
+ data += strlen(data) + 1;
+ }
+ }
+ printf(";\n");
+ }
+ offset = fdt_next_property_offset(config_fdt, offset);
+ }
+ }
+ /* Output the standard DTS footers */
+ printf("}; /* cavium,bdk */\n");
+ printf("}; /* / */\n");
+}
+
+/**
+ * Display a list of all possible config items with help text
+ */
+void bdk_config_help(void)
+{
+ /* Write out formatted as part of a device tree source (dts) file */
+ printf("/dts-v1/;\n");
+ printf("\n");
+ printf("/ {\n");
+ printf("cavium,bdk {\n");
+ for (bdk_config_t cfg = 0; cfg < __BDK_CONFIG_END; cfg++)
+ display_help(cfg);
+ printf("}; /* cavium,bdk */\n");
+ printf("}; /* / */\n");
+}
+
+
+/**
+ * Save the current configuration to flash
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_config_save(void)
+{
+ /* Pack the FDT so it uses less space */
+ int status = fdt_pack(config_fdt);
+ if (status < 0)
+ {
+ bdk_error("FDT error %d: %s\n", status, fdt_strerror(status));
+ return -1;
+ }
+
+ /* Calculate a CRC32 of the FDT */
+ int fdt_size = fdt_totalsize(config_fdt);
+ uint32_t crc32 = bdk_crc32(config_fdt, fdt_size, 0);
+
+ /* Open the output file */
+ FILE *outf = fopen("/fatfs/default.dtb", "wb");
+ if (!outf)
+ {
+ bdk_error("Failed to open flash");
+ return -1;
+ }
+
+ /* Write the FDT */
+ if (fwrite(config_fdt, fdt_size, 1, outf) != 1)
+ {
+ bdk_error("Failed to write FDT");
+ fclose(outf);
+ return -1;
+ }
+
+ /* Save the CRC32 in the same endianness as the FDT */
+ crc32 = cpu_to_fdt32(crc32);
+ if (fwrite(&crc32, sizeof(crc32), 1, outf) != 1)
+ {
+ bdk_error("Failed to write FDT CRC32");
+ fclose(outf);
+ return -1;
+ }
+
+ fclose(outf);
+ return 0;
+}
+
+/**
+ * Takes the current live device tree and exports it to a memory address suitable
+ * for passing to the next binary in register X1.
+ *
+ * @return Physical address of the device tree, or 0 on failure
+ */
+uint64_t __bdk_config_export_to_mem(void)
+{
+ void *end_ptr = sbrk(0);
+ bdk_node_t node = bdk_numa_master();
+ int fdt_size = fdt_totalsize(config_fdt);
+
+ /* Round size up to 4KB boundary, be sure to add 4 bytes for CRC32 */
+ int fdt_space = (fdt_size + 4 + 0xfff) & -4096;
+ /* First try 4MB - FDT size as this keeps the FDT in the 4MB secure space
+ setup by ATF */
+ void *fdt_ptr = bdk_phys_to_ptr(0x400000 - fdt_space);
+ if (!__bdk_is_dram_enabled(node))
+ {
+ /* Address must be in L2 */
+ int l2_size = bdk_l2c_get_cache_size_bytes(node);
+ void *l2_ptr = bdk_phys_to_ptr(l2_size - fdt_space);
+ if (l2_ptr < fdt_ptr)
+ fdt_ptr = l2_ptr;
+ if (fdt_ptr < end_ptr)
+ {
+ bdk_error("No room for FDT to pass to next binary\n");
+ return 0;
+ }
+ }
+ else
+ {
+ /* We have DRAM, make sure we're past the end of this image */
+ if (fdt_ptr < end_ptr)
+ fdt_ptr = end_ptr;
+ }
+ uint32_t crc32 = bdk_crc32(config_fdt, fdt_size, 0);
+ fdt_move(config_fdt, fdt_ptr, fdt_size);
+ /* CRC32 is stored in same endianness as FDT at the end */
+ *(uint32_t *)((const char *)fdt_ptr + fdt_size) = cpu_to_fdt32(crc32);
+ BDK_TRACE(FDT_OS, "Exported device tree to memory %p, size 0x%x, CRC32 %08x\n",
+ fdt_ptr, fdt_size, crc32);
+ return bdk_ptr_to_phys(fdt_ptr);
+}
+
+/**
+ * Return a pointer to the device tree used for configuration
+ *
+ * @return FDT or NULL on failure
+ */
+void* bdk_config_get_fdt(void)
+{
+ return config_fdt;
+}
+
+/**
+ * Set the device tree used for configuration
+ *
+ * @param fdt Device tree to use. Memory is assumed to be from malloc() and bdk_config takes
+ * over ownership on success
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_config_set_fdt(void *fdt)
+{
+ int offset = fdt_path_offset(fdt, "/cavium,bdk"); /* Find our node */
+ if (offset < 0)
+ return -1;
+ free(config_fdt);
+ config_fdt = fdt;
+ config_node = offset;
+ return 0;
+}
+
+/**
+ * Write all default values to a FDT. Missing config items get defaults in the
+ * BDK config, this function adds those defaults to the FDT. This way other code
+ * gets the default value without needing special code.
+ *
+ * @param fdt FDT structure to fill defaults into
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_config_expand_defaults(void *fdt)
+{
+ const struct fdt_property *prop;
+
+ /* The best defaults may have changed while this image was running if DRAM
+ is setup. Update the defaults before expanding them */
+ config_set_defaults();
+
+ int fdt_node = fdt_path_offset(fdt, "/cavium,bdk"); /* Find our node */
+ if (fdt_node < 0)
+ {
+ bdk_error("Failed to find top node, FDT error %d: %s\n",
+ fdt_node, fdt_strerror(fdt_node));
+ return -1;
+ }
+
+ /* Loop through all configuration items */
+ for (bdk_config_t cfg = 0; cfg < __BDK_CONFIG_END; cfg++)
+ {
+ /* Figure out the base name without and dot parameters */
+ const char *name = config_info[cfg].format;
+ const char *name_end = strchr(name, '.');
+ int name_len;
+ if (name_end)
+ name_len = name_end - name;
+ else
+ name_len = strlen(name);
+ /* Try and find the base name in the FDT */
+ prop = fdt_get_property_namelen(fdt, fdt_node, name, name_len, NULL);
+ /* If it wasn't found, then we need to add the default */
+ if (prop == NULL)
+ {
+ /* Create a copy of the name for use in FDT calls */
+ char temp_name[name_len + 1];
+ memcpy(temp_name, name, name_len);
+ temp_name[name_len] = 0;
+ /* Call the correct FDT call based on the type */
+ int status = 0;
+ switch (config_info[cfg].ctype)
+ {
+ case BDK_CONFIG_TYPE_INT:
+ {
+ char temp_value[20];
+ if (config_info[cfg].default_value < 10)
+ snprintf(temp_value, sizeof(temp_value), "%ld", config_info[cfg].default_value);
+ else
+ snprintf(temp_value, sizeof(temp_value), "0x%lx", config_info[cfg].default_value);
+ /* Store the default int value */
+ status = fdt_setprop_string(fdt, fdt_node, temp_name, temp_value);
+ break;
+ }
+ case BDK_CONFIG_TYPE_STR:
+ /* Store the default string value, if present */
+ if (config_info[cfg].default_value)
+ {
+ status = fdt_setprop_string(fdt, fdt_node, temp_name,
+ (const char *)config_info[cfg].default_value);
+ }
+ break;
+ case BDK_CONFIG_TYPE_STR_LIST:
+ /* Do nothing, string list default to empty */
+ break;
+ case BDK_CONFIG_TYPE_BINARY:
+ /* Do nothing, binary defaults to empty */
+ break;
+ }
+ if (status < 0)
+ {
+ bdk_error("Failed to set default for %s, FDT error %d: %s\n",
+ temp_name, status, fdt_strerror(status));
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Some of the default config values can vary based on runtime parameters. This
+ * function sets those default parameters. It must be run before anyone calls
+ * bdk_config_get_*().
+ */
+static void config_set_defaults(void)
+{
+ bool isEmulation = bdk_is_platform(BDK_PLATFORM_EMULATOR);
+ /* This is Cavium's OUI with the local admin bit. We will use this as a
+ default as it won't collide with official addresses, but is sort of
+ part of the Cavium range. The lower three bytes will be updated with
+ the wafer info */
+ uint64_t mac_address = 0x020fb7000000ull;
+ /* Set the lower MAC address bits based on the chip manufacturing
+ information. This should give reasonable MAC address defaults
+ for production parts */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ BDK_CSR_INIT(fus_dat0, bdk_numa_local(), BDK_MIO_FUS_DAT0);
+ mac_address |= fus_dat0.u & 0xffffff;
+ }
+ else
+ {
+ mac_address |= bdk_fuse_read_range(bdk_numa_local(), BDK_FUS_FUSE_NUM_E_MFG_INFOX(0), 24);
+ }
+ config_info[BDK_CONFIG_MAC_ADDRESS].default_value = mac_address;
+
+ /* Set the number of packet buffers */
+ int num_packet_buffers = 4096;
+ /* If DRAM is setup, allocate 8K buffers for 8 ports plus some slop */
+ if (__bdk_is_dram_enabled(bdk_numa_master()))
+ num_packet_buffers = 8192 * 16 + 1024;
+ else if (isEmulation) {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ num_packet_buffers = 4096 * 4;
+ }
+ config_info[BDK_CONFIG_NUM_PACKET_BUFFERS].default_value = num_packet_buffers;
+ config_info[BDK_CONFIG_PACKET_BUFFER_SIZE].default_value = 1024;
+
+ /* Asim doesn't scale to 48 cores well. Limit to 4 */
+ if (bdk_is_platform(BDK_PLATFORM_ASIM))
+ config_info[BDK_CONFIG_COREMASK].default_value = 0xf;
+ /* CN88XX pass 1.x doesn't support EA */
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X))
+ config_info[BDK_CONFIG_PCIE_EA].default_value = 0;
+ /* Emulator only supports 4 cores */
+ if (isEmulation)
+ config_info[BDK_CONFIG_COREMASK].default_value = 0xf;
+}
+
+/**
+ * BDK configuration items are stored in a device tree so thay can be passed to
+ * other software later. This function creates the initial empty device tree
+ * used for BDK configuration items. The values will be populated as configuration
+ * files are read from flash.
+ */
+static void config_setup_fdt(void)
+{
+ const int FDT_SIZE = 0x10000;
+ config_fdt = calloc(1, FDT_SIZE);
+ if (!config_fdt)
+ bdk_fatal("Unable to allocate memory for config FDT\n");
+ if (fdt_create_empty_tree(config_fdt, FDT_SIZE) < 0)
+ bdk_fatal("Unable to create FDT for config\n");
+ config_node = fdt_add_subnode(config_fdt, 0, "cavium,bdk");
+ if (config_node < 0)
+ bdk_fatal("Unable to create cavium,bdk node in FDT\n");
+}
+
+/**
+ * Parse a FDT and copy its properties to our configuration FDT
+ *
+ * @param fdt FDT to parse
+ */
+static int config_parse_fdt(const void *fdt, const char *base_path)
+{
+ /* Check the FDT header */
+ int result = fdt_check_header(fdt);
+ if (result)
+ goto fail;
+
+ /* Find our node */
+ result = fdt_path_offset(fdt, base_path);
+ if (result < 0)
+ goto fail;
+
+ /* Copy all parameters to our in memory FDT */
+ int offset = fdt_first_property_offset(fdt, result);
+ while (offset >= 0)
+ {
+ const char *name = NULL;
+ int blob_size = 0;
+ const char *data = fdt_getprop_by_offset(fdt, offset, &name, &blob_size);
+ result = fdt_setprop(config_fdt, config_node, name, data, blob_size);
+ offset = fdt_next_property_offset(fdt, offset);
+ }
+ return 0;
+fail:
+ bdk_error("FDT error %d: %s\n", result, fdt_strerror(result));
+ return -1;
+}
+
+/**
+ * Load a FDT from a file and pull in its configuration properties
+ *
+ * @param filename File to read from
+ * @param offset Offset into the file to read from
+ *
+ * @return Zero on success, negative on failure
+ */
+static int config_load_file(const char *filename, uint64_t offset)
+{
+ uint64_t ftd_size = 0;
+ bdk_signed_flags_t sign_flags = BDK_SIGNED_FLAG_NONE;
+ if (offset)
+ sign_flags = BDK_SIGNED_FLAG_ALLOW_UNSIGNED | BDK_SIGNED_FLAG_NOT_ENCRYPTED;
+ void *fdt = bdk_signed_load(filename, offset, BDK_SIGNED_DTS, sign_flags, &ftd_size);
+ if (!fdt)
+ return -1;
+
+ /* Make sure the read succeeded */
+ if (ftd_size < (int)sizeof(struct fdt_header))
+ {
+ bdk_error("Invalid device tee %s\n", filename);
+ free(fdt);
+ return -1;
+ }
+
+ if (fdt_check_header(fdt))
+ {
+ bdk_error("Invalid FDT header read from %s\n", filename);
+ free(fdt);
+ return -1;
+ }
+
+ /* Make sure we read enough data to contain the FDT */
+ int correct_size = fdt_totalsize(fdt);
+ if ((int)ftd_size < correct_size)
+ {
+ bdk_error("Unable to read FDT from %s\n", filename);
+ free(fdt);
+ return -1;
+ }
+
+ /* Check if a CRC32 was added on the end of the FDT */
+ if ((int)ftd_size >= correct_size + 4)
+ {
+ uint32_t crc32 = bdk_crc32(fdt, correct_size, 0);
+ uint32_t correct_crc32 = *(uint32_t *)((const char *)fdt + correct_size);
+ /* CRC32 is stored in same endianness as FDT */
+ correct_crc32 = fdt32_to_cpu(correct_crc32);
+ if (crc32 != correct_crc32)
+ {
+ bdk_error("FDT failed CRC32 verification (%s)\n", filename);
+ free(fdt);
+ return -1;
+ }
+ //printf("PASS: FDT CRC32 verification (%s)\n", filename);
+ }
+
+ /* Parse the device tree, adding its configuration to ours */
+ if (config_parse_fdt(fdt, "/cavium,bdk"))
+ {
+ free(fdt);
+ return -1;
+ }
+
+ free(fdt);
+ return 0;
+}
+
+/**
+ * Internal BDK function to initialize the config system. Must be called before
+ * any configuration functions are called
+ */
+void __bdk_config_init(void)
+{
+ bool done_trust_init = false;
+ /* Set default that can vary dynamically at runtime */
+ config_set_defaults();
+
+ /* Regsiter X1 is expected to be a device tree when we boot. Check that
+ the physical address seems correct, then load the device tree */
+ if ((__bdk_init_reg_x1 > 0) && /* Not zero */
+ (__bdk_init_reg_x1 < 0x1000000) && /* In the lower 16MB */
+ ((__bdk_init_reg_x1 & 0xfff) == 0)) /* Aligned on a 4KB boundary */
+ {
+ const void *fdt = (const void *)__bdk_init_reg_x1;
+ /* Check the FDT header */
+ int result = fdt_check_header(fdt);
+ if (result)
+ result = -1; /* Invalid tree */
+ else
+ {
+ int fdt_size = fdt_totalsize(fdt);
+ uint32_t crc32 = bdk_crc32(fdt, fdt_size, 0);
+ uint32_t correct_crc32 = *(uint32_t *)((const char *)fdt + fdt_size);
+ /* CRC32 is stored in same endianness as FDT */
+ correct_crc32 = fdt32_to_cpu(correct_crc32);
+ if (crc32 == correct_crc32)
+ {
+ //printf("Previous image FDT passed CRC32 verification(%p, size 0x%x, CRC32 %08x)\n", fdt, fdt_size, crc32);
+ result = fdt_path_offset(fdt, "/cavium,bdk"); /* Find our node */
+ }
+ else
+ {
+ bdk_error("Previous image FDT failed CRC32 verification(%p, size 0x%x)\n", fdt, fdt_size);
+ result = -1; /* Invalid tree */
+ }
+ }
+ /* If tree is valid so far, attempt to move it into our memory space */
+ if (result > 0)
+ {
+ /* 4KB extra room for growth */
+ const int fdt_size = fdt_totalsize(fdt) + 4096;
+ config_fdt = calloc(1, fdt_size);
+ if (config_fdt)
+ {
+ int result = fdt_move(fdt, config_fdt, fdt_size);
+ if (result == 0)
+ {
+ /* Find our node */
+ config_node = fdt_path_offset(config_fdt, "/cavium,bdk");
+ if (config_node > 0)
+ {
+ printf("Using configuration from previous image\n");
+ goto done;
+ }
+ else
+ {
+ bdk_error("Unable to find BDK node after move\n");
+ free(config_fdt);
+ config_node = 0;
+ config_fdt = NULL;
+ }
+ }
+ else
+ {
+ bdk_error("Unable to move passed device tree\n");
+ free(config_fdt);
+ config_fdt = NULL;
+ }
+ }
+ else
+ bdk_error("Failed to allocate memory for passed device tree (%d bytes)\n", fdt_size);
+ }
+ }
+
+ /* Create the global device tree used to store config items */
+ config_setup_fdt();
+ /* Setup trust level so reading device trees works */
+ __bdk_trust_init();
+ done_trust_init = true;
+
+ if (bdk_is_platform(BDK_PLATFORM_ASIM))
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ bdk_config_set_str("ASIM-CN88XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ bdk_config_set_str("ASIM-CN83XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ bdk_config_set_str("ASIM-CN81XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
+ bdk_config_set_str("ASIM-CN93XX", BDK_CONFIG_BOARD_MODEL);
+ }
+ else if (bdk_is_platform(BDK_PLATFORM_EMULATOR))
+ {
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ bdk_config_set_str("EMUL-CN88XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ bdk_config_set_str("EMUL-CN83XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ bdk_config_set_str("EMUL-CN81XX", BDK_CONFIG_BOARD_MODEL);
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
+ bdk_config_set_str("EMUL-CN93XX", BDK_CONFIG_BOARD_MODEL);
+ }
+ else if (config_load_file("/rom/boardcfg.dtb", 0) == 0)
+ {
+ printf("Board manufacturing information loaded from ROM-FS\n");
+ }
+ /* Load manufacturing data from the top 64KB of flash */
+ else if (config_load_file("/boot", BDK_CONFIG_MANUFACTURING_ADDRESS) != 0)
+ {
+ printf("\33[1m"); /* Bold */
+ bdk_warn("\n");
+ bdk_warn("********************************************************\n");
+ bdk_warn("* Board manufacturing information not found. Program\n");
+ bdk_warn("* the board manufacturing information in the Setup menu.\n");
+ bdk_warn("********************************************************\n");
+ bdk_warn("\n");
+ printf("\33[0m"); /* Normal */
+ goto done;
+ }
+
+ const char *model = bdk_config_get_str(BDK_CONFIG_BOARD_MODEL);
+ const char *revision = bdk_config_get_str(BDK_CONFIG_BOARD_REVISION);
+
+ /* Load BOARD-REVISION.cfg if it is on ROM-FS */
+ if (model && revision)
+ {
+ char filename[64];
+ snprintf(filename, sizeof(filename), "/rom/%s-%s.dtb", model, revision);
+ if (config_load_file(filename, 0) == 0)
+ goto done;
+ }
+
+ /* Load BOARD.cfg if it is on ROM-FS */
+ if (model)
+ {
+ char filename[64];
+ snprintf(filename, sizeof(filename), "/rom/%s.dtb", model);
+ if (config_load_file(filename, 0) == 0)
+ goto done;
+ }
+
+ /* Load default.dtb if it is there */
+ if (config_load_file("/fatfs/default.dtb", 0) == 0)
+ goto done;
+
+ /* Load BOARD-REVISION.cfg if it is there */
+ if (model && revision)
+ {
+ char filename[64];
+ snprintf(filename, sizeof(filename), "/fatfs/%s-%s.dtb", model, revision);
+ if (config_load_file(filename, 0) == 0)
+ goto done;
+ }
+
+ /* Load BOARD.cfg if it is there */
+ if (model)
+ {
+ char filename[64];
+ snprintf(filename, sizeof(filename), "/fatfs/%s.dtb", model);
+ if (config_load_file(filename, 0) == 0)
+ goto done;
+ }
+
+ /* No board specific configuration was found. Warn the user */
+ printf("\33[1m"); /* Bold */
+ bdk_warn("\n");
+ bdk_warn("********************************************************\n");
+ bdk_warn("* Board configuration file not found. Either the board\n");
+ bdk_warn("* model is incorrect, or factory settings are not\n");
+ bdk_warn("* available. DTB file not found for board \"%s\".\n", model);
+ bdk_warn("********************************************************\n");
+ bdk_warn("\n");
+ printf("\33[0m"); /* Normal */
+
+done:
+ bdk_config_set_str(bdk_version_string(), BDK_CONFIG_VERSION);
+ /* Load the tracing level */
+ bdk_trace_enables = bdk_config_get_int(BDK_CONFIG_TRACE);
+ if (BDK_TRACE_OVERRIDE)
+ bdk_trace_enables = BDK_TRACE_OVERRIDE;
+ if (!done_trust_init)
+ __bdk_trust_init();
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c
new file mode 100644
index 0000000000..55f0dbf3f2
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c
@@ -0,0 +1,197 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+* reserved.
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+*
+* * Neither the name of Cavium Inc. nor the names of
+* its contributors may be used to endorse or promote products
+* derived from this software without specific prior written
+* permission.
+*
+* This Software, including technical data, may be subject to U.S. export
+* control laws, including the U.S. Export Administration Act and its
+* associated regulations, and may be subject to export or import
+* regulations in other countries.
+*
+* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
+* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
+* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
+* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
+* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
+* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
+* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
+* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+***********************license end**************************************/
+#include <bdk.h>
+#include "libbdk-arch/bdk-csrs-gpio.h"
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(GPIO);
+
+/**
+ * Initialize a single GPIO as either an input or output. If it is
+ * an output, also set its output value.
+ *
+ * @param gpio GPIO to initialize
+ * @param is_output Non zero if this GPIO should be an output
+ * @param output_value
+ * Value of the GPIO if it should be an output. Not used if the
+ * GPIO isn't an output.
+ *
+ * @return Zero on success, negative ob failure
+ */
+int bdk_gpio_initialize(bdk_node_t node, int gpio, int is_output, int output_value)
+{
+ if ((gpio >= 0) && (gpio < bdk_gpio_get_num()))
+ {
+ int gpio_group = gpio >> 6;
+ int gpio_index = gpio & 63;
+ if (output_value)
+ bdk_gpio_set(node, gpio_group, 1ull << gpio_index);
+ else
+ bdk_gpio_clear(node, gpio_group, 1ull << gpio_index);
+
+ BDK_CSR_DEFINE(cfg, BDK_GPIO_BIT_CFGX(gpio));
+ cfg.u = 0;
+ cfg.s.tx_oe = !!is_output;
+ BDK_CSR_WRITE(node, BDK_GPIO_BIT_CFGX(gpio), cfg.u);
+ }
+ else
+ {
+ bdk_error("bdk_gpio_initialize: Illegal GPIO\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * GPIO Read Data
+ *
+ * @param node Node GPIO block is on
+ * @param gpio_block GPIO block to access. Each block contains up to 64 GPIOs
+ *
+ * @return Status of the GPIO pins for the given block
+ */
+uint64_t bdk_gpio_read(bdk_node_t node, int gpio_block)
+{
+ bdk_gpio_rx_dat_t gpio_rx_dat;
+ switch (gpio_block)
+ {
+ case 0:
+ gpio_rx_dat.u = BDK_CSR_READ(node, BDK_GPIO_RX_DAT);
+ break;
+ case 1:
+ gpio_rx_dat.u = BDK_CSR_READ(node, BDK_GPIO_RX1_DAT);
+ break;
+ default:
+ bdk_error("GPIO block %d not supported\n", gpio_block);
+ gpio_rx_dat.u = 0;
+ break;
+ }
+ return gpio_rx_dat.s.dat;
+}
+
+
+/**
+ * GPIO Clear pin
+ *
+ * @param node Node GPIO block is on
+ * @param gpio_block GPIO block to access. Each block contains up to 64 GPIOs
+ * @param clear_mask Bit mask to indicate which bits to drive to '0'.
+ */
+void bdk_gpio_clear(bdk_node_t node, int gpio_block, uint64_t clear_mask)
+{
+ switch (gpio_block)
+ {
+ case 0:
+ BDK_CSR_WRITE(node, BDK_GPIO_TX_CLR, clear_mask);
+ break;
+ case 1:
+ BDK_CSR_WRITE(node, BDK_GPIO_TX1_CLR, clear_mask);
+ break;
+ default:
+ bdk_error("GPIO block %d not supported\n", gpio_block);
+ break;
+ }
+}
+
+
+/**
+ * GPIO Set pin
+ *
+ * @param node Node GPIO block is on
+ * @param gpio_block GPIO block to access. Each block contains up to 64 GPIOs
+ * @param set_mask Bit mask to indicate which bits to drive to '1'.
+ */
+void bdk_gpio_set(bdk_node_t node, int gpio_block, uint64_t set_mask)
+{
+ switch (gpio_block)
+ {
+ case 0:
+ BDK_CSR_WRITE(node, BDK_GPIO_TX_SET, set_mask);
+ break;
+ case 1:
+ BDK_CSR_WRITE(node, BDK_GPIO_TX1_SET, set_mask);
+ break;
+ default:
+ bdk_error("GPIO block %d not supported\n", gpio_block);
+ break;
+ }
+}
+
+
+/** GPIO Select pin
+ *
+ * @param node CPU node
+ * @param gpio GPIO number
+ * @param pin Pin number
+ */
+void bdk_gpio_select_pin(bdk_node_t node, int gpio, int pin)
+{
+ if ((gpio < 0) || (gpio >= bdk_gpio_get_num()))
+ {
+ bdk_warn("bdk_gpio_select_pin: Illegal GPIO %d\n", gpio);
+ return;
+ }
+
+ BDK_CSR_MODIFY(c, node, BDK_GPIO_BIT_CFGX(gpio), c.s.pin_sel = pin);
+}
+
+
+/**
+ * Return the number of GPIO pins on this chip
+ *
+ * @return Number of GPIO pins
+ */
+int bdk_gpio_get_num(void)
+{
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ return 51;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN81XX))
+ return 48;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN83XX))
+ return 80;
+ else if (CAVIUM_IS_MODEL(CAVIUM_CN93XX))
+ return 96;
+ else
+ {
+ bdk_error("bdk_gpio_get_num(): Unsupported chip");
+ return 0;
+ }
+}
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c
new file mode 100644
index 0000000000..b1e2a88ce1
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c
@@ -0,0 +1,270 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+* reserved.
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+*
+* * Neither the name of Cavium Inc. nor the names of
+* its contributors may be used to endorse or promote products
+* derived from this software without specific prior written
+* permission.
+*
+* This Software, including technical data, may be subject to U.S. export
+* control laws, including the U.S. Export Administration Act and its
+* associated regulations, and may be subject to export or import
+* regulations in other countries.
+*
+* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
+* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
+* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
+* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
+* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
+* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
+* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
+* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+***********************license end**************************************/
+#include <bdk.h>
+#include "libbdk-arch/bdk-csrs-ap.h"
+#include "libbdk-arch/bdk-csrs-l2c.h"
+#include "libbdk-arch/bdk-csrs-l2c_cbc.h"
+#include "libbdk-arch/bdk-csrs-mio_fus.h"
+
+typedef struct
+{
+ int sets;
+ int ways;
+ bool is_locked;
+} l2_node_state_t;
+
+static l2_node_state_t l2_node_state[BDK_NUMA_MAX_NODES];
+
+/**
+ * Perform one time initialization of L2 for improved
+ * performance. This can be called after L2 is in use.
+ *
+ * @return Zero on success, negative on failure.
+ */
+int bdk_l2c_initialize(bdk_node_t node)
+{
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* Tell L2 to give the IOB statically higher priority compared to the
+ cores. This avoids conditions where IO blocks might be starved under
+ very high L2 loads */
+ BDK_CSR_MODIFY(c, node, BDK_L2C_CTL,
+ c.s.rsp_arb_mode = 1;
+ c.s.xmc_arb_mode = 0);
+ }
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS1_X) && !bdk_is_platform(BDK_PLATFORM_ASIM))
+ {
+ /* Errata: (L2C-22279) RCAS/RSTC which hits S/S can use wrong compare data */
+ BDK_CSR_MODIFY(c, node, BDK_L2C_CTL,
+ c.s.dissblkdty = 1);
+ /* Errata: (L2C-22249) Broadcast invals can cause starvation on the INV bus */
+ for (int i = 0; i < 4; i++)
+ BDK_CSR_MODIFY(c, node, BDK_L2C_CBCX_SCRATCH(i),
+ c.s.invdly = 1);
+ }
+
+ // FIXME: Disable partial writes on pass 2 until it is debugged
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX_PASS2_X) && !bdk_is_platform(BDK_PLATFORM_ASIM))
+ {
+ BDK_CSR_MODIFY(c, node, BDK_L2C_CTL,
+ c.s.dissblkdty = 1);
+ }
+
+ if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX) && bdk_is_platform(BDK_PLATFORM_EMULATOR))
+ {
+ /* The emulator requires L2C_CTL[DISSBLKDTY] to be set */
+ BDK_CSR_MODIFY(c, node, BDK_L2C_CTL,
+ c.s.dissblkdty = 1);
+ }
+ return 0;
+}
+
+int bdk_l2c_get_core_way_partition(bdk_node_t node, int core)
+{
+ return (BDK_CSR_READ(node, BDK_L2C_WPAR_PPX(core)) & 0xffff);
+}
+
+int bdk_l2c_set_core_way_partition(bdk_node_t node, int core, uint32_t mask)
+{
+ uint32_t valid_mask = (1 << bdk_l2c_get_num_assoc(node)) - 1;
+ mask &= valid_mask;
+
+ BDK_CSR_WRITE(node, BDK_L2C_WPAR_PPX(core), mask);
+ return 0;
+}
+
+
+int bdk_l2c_set_hw_way_partition(bdk_node_t node, uint32_t mask)
+{
+ uint32_t valid_mask = (1 << bdk_l2c_get_num_assoc(node)) - 1;
+ mask &= valid_mask;
+
+ BDK_CSR_WRITE(node, BDK_L2C_WPAR_IOBX(0), mask);
+ return 0;
+}
+
+
+int bdk_l2c_get_hw_way_partition(bdk_node_t node)
+{
+ return (BDK_CSR_READ(node, BDK_L2C_WPAR_IOBX(0)) & 0xffff);
+}
+
+
+int bdk_l2c_lock_mem_region(bdk_node_t node, uint64_t start, uint64_t len)
+{
+ /* Round start/end to cache line boundaries */
+ len += start & BDK_CACHE_LINE_MASK;
+ start &= ~BDK_CACHE_LINE_MASK;
+ len = (len + BDK_CACHE_LINE_MASK) & ~BDK_CACHE_LINE_MASK;
+ void *ptr = (start) ? bdk_phys_to_ptr(start) : NULL;
+
+ while (len)
+ {
+ BDK_CACHE_LCK_L2(ptr);
+ ptr += BDK_CACHE_LINE_SIZE;
+ len -= BDK_CACHE_LINE_SIZE;
+ }
+ l2_node_state[node].is_locked = true;
+ return 0;
+}
+
+void bdk_l2c_flush(bdk_node_t node)
+{
+ /* The number of ways can be reduced with fuses, but the equations below
+ assume the max number of ways */
+ const int MAX_WAYS = 16;
+ int num_sets = bdk_l2c_get_num_sets(node);
+ int num_ways = bdk_l2c_get_num_assoc(node);
+
+ int is_rtg = 1; /* Clear remote tags */
+ for (int l2_way = 0; l2_way < num_ways; l2_way++)
+ {
+ for (int l2_set = 0; l2_set < num_sets; l2_set++)
+ {
+ uint64_t encoded = 128 * (l2_set + num_sets * (l2_way + (is_rtg * MAX_WAYS)));
+ BDK_CACHE_WBI_L2_INDEXED(encoded);
+ }
+ }
+
+ is_rtg = 0; /* Clear local tags */
+ for (int l2_way = 0; l2_way < num_ways; l2_way++)
+ {
+ for (int l2_set = 0; l2_set < num_sets; l2_set++)
+ {
+ uint64_t encoded = 128 * (l2_set + num_sets * (l2_way + (is_rtg * MAX_WAYS)));
+ BDK_CACHE_WBI_L2_INDEXED(encoded);
+ }
+ }
+ l2_node_state[node].is_locked = false;
+}
+
+int bdk_l2c_unlock_mem_region(bdk_node_t node, uint64_t start, uint64_t len)
+{
+ /* Round start/end to cache line boundaries */
+ len += start & BDK_CACHE_LINE_MASK;
+ start &= ~BDK_CACHE_LINE_MASK;
+ len = (len + BDK_CACHE_LINE_MASK) & ~BDK_CACHE_LINE_MASK;
+ void *ptr = (start) ? bdk_phys_to_ptr(start) : NULL;
+
+ while (len > 0)
+ {
+ /* Must use invalidate version to release lock */
+ BDK_CACHE_WBI_L2(ptr);
+ ptr += BDK_CACHE_LINE_SIZE;
+ len -= BDK_CACHE_LINE_SIZE;
+ }
+
+ l2_node_state[node].is_locked = false;
+ return 0;
+}
+
+
+int bdk_l2c_get_cache_size_bytes(bdk_node_t node)
+{
+ return bdk_l2c_get_num_sets(node) * bdk_l2c_get_num_assoc(node) * BDK_CACHE_LINE_SIZE;
+}
+
+/* Return the number of sets in the L2 Cache */
+int bdk_l2c_get_num_sets(bdk_node_t node)
+{
+ if (bdk_unlikely(l2_node_state[node].sets == 0))
+ {
+ /* Select the L2 cache */
+ bdk_ap_csselr_el1_t csselr_el1;
+ csselr_el1.u = 0;
+ csselr_el1.s.ind = 0;
+ csselr_el1.s.level = CAVIUM_IS_MODEL(CAVIUM_CN8XXX) ? 1 : 2;
+ BDK_MSR(CSSELR_EL1, csselr_el1.u);
+ /* Read its size */
+ bdk_ap_ccsidr_el1_t ccsidr_el1;
+ BDK_MRS(CCSIDR_EL1, ccsidr_el1.u);
+ /* Store it for use later */
+ l2_node_state[node].sets = ccsidr_el1.s.numsets + 1;
+ l2_node_state[node].ways = ccsidr_el1.s.associativity + 1;
+
+ /* Early chips didn't update the number of ways based on fusing */
+ if ((l2_node_state[node].ways == 16) && CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
+ {
+ /* The l2 can be reduced in 25% increments */
+ BDK_CSR_INIT(mio_fus_dat3, node, BDK_MIO_FUS_DAT3);
+ switch (mio_fus_dat3.s.l2c_crip)
+ {
+ case 3: /* 1/4 size */
+ l2_node_state[node].ways *= 1;
+ break;
+ case 2: /* 1/2 size */
+ l2_node_state[node].ways *= 2;
+ break;
+ case 1: /* 3/4 size */
+ l2_node_state[node].ways *= 3;
+ break;
+ default: /* Full size */
+ l2_node_state[node].ways *= 4;
+ break;
+ }
+ l2_node_state[node].ways /= 4;
+ }
+ }
+ return l2_node_state[node].sets;
+}
+
+/* Return the number of associations in the L2 Cache */
+int bdk_l2c_get_num_assoc(bdk_node_t node)
+{
+ /* Get the number of sets if the global sets/ways is not setup */
+ if (bdk_unlikely(l2_node_state[node].ways == 0))
+ bdk_l2c_get_num_sets(node);
+ return l2_node_state[node].ways;
+}
+
+/**
+ * Return true if the BDK has locked itself in L2
+ *
+ * @return
+ */
+int bdk_l2c_is_locked(bdk_node_t node)
+{
+ /* Determining the lock state of L2 requires reading exact tags from L2
+ which varies per chip. Rather than deal with that complexity, we just
+ keep a flag around saying if the L2 lock functions have been called.
+ This works for the BDK as its use of locking is very simple */
+ return l2_node_state[node].is_locked;
+}
+
diff --git a/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c
new file mode 100644
index 0000000000..4fbb78a876
--- /dev/null
+++ b/src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c
@@ -0,0 +1,318 @@
+/***********************license start***********************************
+* Copyright (c) 2003-2017 Cavium Inc. (support@cavium.com). All rights
+* reserved.
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+*
+* * Neither the name of Cavium Inc. nor the names of
+* its contributors may be used to endorse or promote products
+* derived from this software without specific prior written
+* permission.
+*
+* This Software, including technical data, may be subject to U.S. export
+* control laws, including the U.S. Export Administration Act and its
+* associated regulations, and may be subject to export or import
+* regulations in other countries.
+*
+* TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+* AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
+* WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT
+* TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
+* REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
+* DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
+* OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
+* PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
+* QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
+* ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+***********************license end**************************************/
+#include <bdk.h>
+#include "libbdk-arch/bdk-csrs-mio_tws.h"
+
+#define RECOVERY_UDELAY 5
+#define RECOVERY_CLK_CNT 9
+#define ARBLOST_UDELAY 5000 /* 5ms */
+
+/* This code is an optional part of the BDK. It is only linked in
+ if BDK_REQUIRE() needs it */
+BDK_REQUIRE_DEFINE(TWSI);
+
+/**
+ * Initialize the TWSI blocks. This just sets the clock rate.
+ * Many times stuff will work without calling this, but some
+ * TWSI devices will fail. This is normally called automatically
+ * in bdk-init-main.c.
+ *
+ * @return Zero on success, negative on failure
+ */
+int bdk_twsix_initialize(bdk_node_t node)
+{
+ const int TWSI_BUS_FREQ = 100000; /* 100 KHz */
+ const int TWSI_THP = 24; /* TCLK half period (default 24) */
+ const int io_clock_hz = bdk_clock_get_rate(node, BDK_CLOCK_SCLK);
+ int N_divider;
+ int M_divider;
+
+ /* Set the TWSI clock to a conservative TWSI_BUS_FREQ. Compute the
+ clocks M divider based on the SCLK.
+ TWSI freq = (core freq) / (20 x (M+1) x (thp+1) x 2^N)
+ M = ((core freq) / (20 x (TWSI freq) x (thp+1) x 2^N)) - 1 */
+ for (N_divider = 0; N_divider < 8; N_divider++)
+ {
+ M_divider = (io_clock_hz / (20 * TWSI_BUS_FREQ * (TWSI_THP + 1) * (1 << N_divider))) - 1;
+ if (M_divider < 16)
+ break;
+ }
+
+ BDK_CSR_DEFINE(sw_twsi, BDK_MIO_TWSX_SW_TWSI(bus));
+ sw_twsi.u = 0;
+ sw_twsi.s.v = 1; /* Clear valid bit */
+ sw_twsi.s.op = 0x6; /* See EOP field */
+ sw_twsi.s.r = 0; /* Select CLKCTL when R = 0 */
+ sw_twsi.s.eop_ia = 3; /* R=0 selects CLKCTL, R=1 selects STAT */
+ sw_twsi.s.data = ((M_divider & 0xf) << 3) | ((N_divider & 0x7) << 0);
+
+ int num_busses = 2;
+ if (CAVIUM_IS_MODEL(CAVIUM_CN88XX))
+ num_busses = 6;
+
+ for (int bus = 0; bus < num_busses; bus++)
+ {
+ /* Only init non-slave ports */
+ BDK_CSR_INIT(state, node, BDK_MIO_TWSX_SW_TWSI(bus));
+ if (!state.s.slonly)
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_SW_TWSI(bus), sw_twsi.u);
+ }
+ return 0;
+}
+
+/**
+ * Do a twsi bus recovery in the case when the last transaction
+ * on the bus has been left unfinished.
+ *
+ * @param twsi_id which TWSI bus to use
+ */
+static void bdk_twsix_recover_bus(bdk_node_t node, int twsi_id)
+{
+ /* read TWSX_INT */
+ BDK_CSR_INIT(twsx_int, node, BDK_MIO_TWSX_INT(twsi_id));
+
+ for (int i = 0; i < RECOVERY_CLK_CNT * 2; i++)
+ {
+ if (!twsx_int.s.scl_ovr)
+ {
+ /* SCL shouldn't be low here */
+ if (!twsx_int.s.scl)
+ {
+ bdk_error("N%d.TWSI%d: SCL is stuck low\n", node, twsi_id);
+ return;
+ }
+
+ /* Break if SDA is high */
+ if (twsx_int.s.sda)
+ break;
+ }
+
+ twsx_int.s.scl_ovr = !twsx_int.s.scl_ovr;
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_INT(twsi_id), twsx_int.u);
+ bdk_wait_usec(RECOVERY_UDELAY);
+ }
+
+ /*
+ * Generate STOP condition using the register overrides
+ * in order to move the higher level controller out of
+ * the bad state. This is a workaround for the TWSI hardware.
+ */
+ twsx_int.s.scl_ovr = 1;
+ twsx_int.s.sda_ovr = 1;
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_INT(twsi_id), twsx_int.u);
+ bdk_wait_usec(RECOVERY_UDELAY);
+ twsx_int.s.scl_ovr = 0;
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_INT(twsi_id), twsx_int.u);
+ bdk_wait_usec(RECOVERY_UDELAY);
+ twsx_int.s.sda_ovr = 0;
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_INT(twsi_id), twsx_int.u);
+}
+
+/**
+ * Do a twsi read from a 7 bit device address using an (optional)
+ * internal address. Up to 4 bytes can be read at a time.
+ *
+ * @param twsi_id which TWSI bus to use
+ * @param dev_addr Device address (7 bit)
+ * @param internal_addr
+ * Internal address. Can be 0, 1 or 2 bytes in width
+ * @param num_bytes Number of data bytes to read (1-4)
+ * @param ia_width_bytes
+ * Internal address size in bytes (0, 1, or 2)
+ *
+ * @return Read data, or -1 on failure
+ */
+int64_t bdk_twsix_read_ia(bdk_node_t node, int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes)
+{
+ bdk_mio_twsx_sw_twsi_t sw_twsi_val;
+ bdk_mio_twsx_sw_twsi_ext_t twsi_ext;
+ int retry_limit = 5;
+
+ if (num_bytes < 1 || num_bytes > 4 || ia_width_bytes < 0 || ia_width_bytes > 2)
+ return -1;
+retry:
+ twsi_ext.u = 0;
+ sw_twsi_val.u = 0;
+ sw_twsi_val.s.v = 1;
+ sw_twsi_val.s.r = 1;
+ sw_twsi_val.s.sovr = 1;
+ sw_twsi_val.s.size = num_bytes - 1;
+ sw_twsi_val.s.addr = dev_addr;
+
+ if (ia_width_bytes > 0)
+ {
+ sw_twsi_val.s.op = 1;
+ sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
+ sw_twsi_val.s.eop_ia = internal_addr & 0x7;
+ if (ia_width_bytes == 2)
+ {
+ sw_twsi_val.s.eia = 1;
+ twsi_ext.s.ia = internal_addr >> 8;
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u);
+ }
+ }
+
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u);
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_MIO_TWSX_SW_TWSI(twsi_id), v, ==, 0, 10000))
+ {
+ bdk_warn("N%d.TWSI%d: Timeout waiting for read to complete...start recovering process\n",
+ node, twsi_id);
+ /* perform bus recovery */
+ bdk_twsix_recover_bus(node, twsi_id);
+ if (retry_limit-- > 0)
+ goto retry;
+
+ bdk_error("N%d.TWSI%d: Timeout waiting for operation to complete\n", node, twsi_id);
+ return -1;
+ }
+ sw_twsi_val.u = BDK_CSR_READ(node, BDK_MIO_TWSX_SW_TWSI(twsi_id));
+ if (!sw_twsi_val.s.r)
+ {
+ /* Check the reason for the failure. We may need to retry to handle multi-master
+ ** configurations.
+ ** Lost arbitration : 0x38, 0x68, 0xB0, 0x78
+ ** Core busy as slave: 0x80, 0x88, 0xA0, 0xA8, 0xB8, 0xC0, 0xC8
+ */
+ if (sw_twsi_val.s.data == 0x38
+ || sw_twsi_val.s.data == 0x68
+ || sw_twsi_val.s.data == 0xB0
+ || sw_twsi_val.s.data == 0x78
+ || sw_twsi_val.s.data == 0x80
+ || sw_twsi_val.s.data == 0x88
+ || sw_twsi_val.s.data == 0xA0
+ || sw_twsi_val.s.data == 0xA8
+ || sw_twsi_val.s.data == 0xB8
+ || sw_twsi_val.s.data == 0xC8)
+ {
+ /*
+ * One of the arbitration lost conditions is recognized.
+ * The TWSI hardware has switched to the slave mode and
+ * expects the STOP condition on the bus.
+ * Make a delay before next retry.
+ */
+ bdk_wait_usec(ARBLOST_UDELAY);
+ if (retry_limit-- > 0)
+ goto retry;
+ }
+ /* For all other errors, return an error code */
+ return -1;
+ }
+
+ return (sw_twsi_val.s.data & (0xFFFFFFFF >> (32 - num_bytes*8)));
+}
+
+
+/**
+ * Write 1-8 bytes to a TWSI device using an internal address.
+ *
+ * @param twsi_id which TWSI interface to use
+ * @param dev_addr TWSI device address (7 bit only)
+ * @param internal_addr
+ * TWSI internal address (0, 8, or 16 bits)
+ * @param num_bytes Number of bytes to write (1-8)
+ * @param ia_width_bytes
+ * internal address width, in bytes (0, 1, 2)
+ * @param data Data to write. Data is written MSB first on the twsi bus, and
+ * only the lower num_bytes bytes of the argument are valid. (If
+ * a 2 byte write is done, only the low 2 bytes of the argument is
+ * used.
+ *
+ * @return Zero on success, -1 on error
+ */
+int bdk_twsix_write_ia(bdk_node_t node, int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data)
+{
+ bdk_mio_twsx_sw_twsi_t sw_twsi_val;
+ bdk_mio_twsx_sw_twsi_ext_t twsi_ext;
+ int retry_limit = 5;
+ int to;
+
+ if (num_bytes < 1 || num_bytes > 8 || ia_width_bytes < 0 || ia_width_bytes > 2)
+ return -1;
+
+retry:
+ twsi_ext.u = 0;
+ sw_twsi_val.u = 0;
+ sw_twsi_val.s.v = 1;
+ sw_twsi_val.s.sovr = 1;
+ sw_twsi_val.s.size = num_bytes - 1;
+ sw_twsi_val.s.addr = dev_addr;
+ sw_twsi_val.s.data = 0xFFFFFFFF & data;
+
+ if (ia_width_bytes > 0)
+ {
+ sw_twsi_val.s.op = 1;
+ sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
+ sw_twsi_val.s.eop_ia = internal_addr & 0x7;
+ }
+ if (ia_width_bytes == 2)
+ {
+ sw_twsi_val.s.eia = 1;
+ twsi_ext.s.ia = internal_addr >> 8;
+ }
+ if (num_bytes > 4)
+ twsi_ext.s.data = data >> 32;
+
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u);
+ BDK_CSR_WRITE(node, BDK_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u);
+ if (BDK_CSR_WAIT_FOR_FIELD(node, BDK_MIO_TWSX_SW_TWSI(twsi_id), v, ==, 0, 10000))
+ {
+ bdk_warn("N%d.TWSI%d: Timeout waiting for write to complete...start recovering process\n",
+ node, twsi_id);
+ /* perform bus recovery */
+ bdk_twsix_recover_bus(node, twsi_id);
+ if (retry_limit-- > 0)
+ goto retry;
+
+ // After retry but still not success, report error and return
+ bdk_error("N%d.TWSI%d: Timeout waiting for operation to complete\n", node, twsi_id);
+ return -1;
+ }
+
+ /* Poll until reads succeed, or polling times out */
+ to = 100;
+ while (to-- > 0)
+ {
+ if (bdk_twsix_read_ia(node, twsi_id, dev_addr, 0, 1, 0) >= 0)
+ break;
+ }
+ if (to <= 0)
+ return -1;
+
+ return 0;
+}