diff options
author | David Hendricks <dhendricks@fb.com> | 2018-03-09 13:58:27 -0800 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2018-04-06 06:48:11 +0000 |
commit | 2004b93aed993aa02bbc588b8d82c22418ac52ec (patch) | |
tree | cdd5e95a154e2e0139474288262835a7f5847665 /src/vendorcode/cavium/bdk/libbdk-hal | |
parent | 71cbd71eb5c0e8e13b25b5d5dd2f495e7d2967eb (diff) |
soc/cavium: import raw BDK sources
This imports common BDK sources that will be used in subsequent
patches.
The BDK is licensed under BSD and will be reduced in size and optimized to
compile under coreboot.
Change-Id: Icb32ee670d9fa9e5c10f9abb298cebf616fa67ad
Signed-off-by: David Hendricks <dhendricks@fb.com>
Reviewed-on: https://review.coreboot.org/25524
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: David Hendricks <david.hendricks@gmail.com>
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; +} |