diff options
Diffstat (limited to 'src/vendorcode/cavium/bdk/libbdk-hal')
-rw-r--r-- | src/vendorcode/cavium/bdk/libbdk-hal/bdk-clock.c | 221 | ||||
-rw-r--r-- | src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c | 1946 | ||||
-rw-r--r-- | src/vendorcode/cavium/bdk/libbdk-hal/bdk-gpio.c | 197 | ||||
-rw-r--r-- | src/vendorcode/cavium/bdk/libbdk-hal/bdk-l2c.c | 270 | ||||
-rw-r--r-- | src/vendorcode/cavium/bdk/libbdk-hal/bdk-twsi.c | 318 |
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; +} |